mediasoup 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/node/lib/PipeTransportTypes.d.ts +8 -0
  3. package/node/lib/PipeTransportTypes.d.ts.map +1 -1
  4. package/node/lib/PlainTransportTypes.d.ts +8 -0
  5. package/node/lib/PlainTransportTypes.d.ts.map +1 -1
  6. package/node/lib/Router.d.ts +4 -4
  7. package/node/lib/Router.d.ts.map +1 -1
  8. package/node/lib/Router.js +10 -7
  9. package/node/lib/RouterTypes.d.ts +8 -0
  10. package/node/lib/RouterTypes.d.ts.map +1 -1
  11. package/node/lib/WebRtcTransportTypes.d.ts +8 -0
  12. package/node/lib/WebRtcTransportTypes.d.ts.map +1 -1
  13. package/node/lib/fbs/transport/options.d.ts +5 -2
  14. package/node/lib/fbs/transport/options.d.ts.map +1 -1
  15. package/node/lib/fbs/transport/options.js +18 -7
  16. package/node/lib/test/test-DataConsumer.js +3 -0
  17. package/package.json +11 -11
  18. package/worker/fbs/transport.fbs +1 -0
  19. package/worker/fuzzer/src/RTC/RTP/FuzzerPacket.cpp +44 -0
  20. package/worker/include/RTC/SCTP/public/SctpOptions.hpp +7 -0
  21. package/worker/include/RTC/SCTP/tx/RoundRobinSendQueue.hpp +2 -0
  22. package/worker/include/RTC/Transport.hpp +0 -5
  23. package/worker/scripts/package-lock.json +7 -7
  24. package/worker/src/RTC/ICE/StunPacket.cpp +6 -2
  25. package/worker/src/RTC/RTP/Packet.cpp +11 -0
  26. package/worker/src/RTC/SCTP/association/Association.cpp +1 -0
  27. package/worker/src/RTC/SCTP/association/StateCookie.cpp +5 -2
  28. package/worker/src/RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.cpp +4 -1
  29. package/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp +10 -2
  30. package/worker/src/RTC/SrtpSession.cpp +82 -25
  31. package/worker/src/RTC/Transport.cpp +7 -15
  32. package/worker/subprojects/libsrtp3.wrap +4 -4
  33. package/worker/tasks.py +1 -1
  34. package/worker/test/src/RTC/SCTP/association/TestAssociation.cpp +34 -0
  35. package/worker/test/src/RTC/SCTP/association/TestStreamResetHandler.cpp +1 -0
  36. package/worker/test/src/RTC/SCTP/packet/errorCauses/TestMissingMandatoryParameterErrorCause.cpp +24 -0
  37. package/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp +180 -39
@@ -21,15 +21,15 @@
21
21
  }
22
22
  },
23
23
  "node_modules/brace-expansion": {
24
- "version": "5.0.7",
25
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
26
- "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
24
+ "version": "5.0.8",
25
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
26
+ "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "balanced-match": "^4.0.2"
30
30
  },
31
31
  "engines": {
32
- "node": "18 || 20 || >=22"
32
+ "node": "20 || >=22"
33
33
  }
34
34
  },
35
35
  "node_modules/glob": {
@@ -105,9 +105,9 @@
105
105
  "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="
106
106
  },
107
107
  "brace-expansion": {
108
- "version": "5.0.7",
109
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
110
- "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
108
+ "version": "5.0.8",
109
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
110
+ "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
111
111
  "requires": {
112
112
  "balanced-match": "^4.0.2"
113
113
  }
@@ -4,8 +4,9 @@
4
4
  #include "RTC/ICE/StunPacket.hpp"
5
5
  #include "Logger.hpp"
6
6
  #include "MediaSoupErrors.hpp"
7
+ #include <openssl/crypto.h>
7
8
  #include <cstdio> // std::snprintf()
8
- #include <cstring> // std::memcmp(), std::memcpy(), std::memset()
9
+ #include <cstring> // std::memcpy(), std::memset()
9
10
  #include <string>
10
11
 
11
12
  namespace RTC
@@ -744,7 +745,10 @@ namespace RTC
744
745
 
745
746
  // Compare the computed HMAC-SHA1 with the MESSAGE-INTEGRITY in the STUN
746
747
  // packet.
747
- if (std::memcmp(messageIntegrity, computedMessageIntegrity, StunPacket::FixedHeaderLength) == 0)
748
+ //
749
+ // NOTE: Use `CRYPTO_memcmp()` to have constant time memory comparison.
750
+ // See https://github.com/versatica/mediasoup/security/advisories/GHSA-xvjj-6cm4-ppgq
751
+ if (CRYPTO_memcmp(messageIntegrity, computedMessageIntegrity, StunPacket::FixedHeaderLength) == 0)
748
752
  {
749
753
  result = StunPacket::AuthenticationResult::OK;
750
754
  }
@@ -1083,6 +1083,17 @@ namespace RTC
1083
1083
  return false;
1084
1084
  }
1085
1085
 
1086
+ if (len > extenLen)
1087
+ {
1088
+ MS_WARN_TAG(
1089
+ rtp,
1090
+ "no enough space for updated dependency descriptor [needed:%zu, available:%" PRIu8 "]",
1091
+ len,
1092
+ extenLen);
1093
+
1094
+ return false;
1095
+ }
1096
+
1086
1097
  std::memcpy(extenValue, data, len);
1087
1098
 
1088
1099
  SetExtensionLength(this->headerExtensionIds.dependencyDescriptor, len);
@@ -54,6 +54,7 @@ namespace RTC
54
54
  this->associationListenerDeferrer,
55
55
  sctpOptions.mtu,
56
56
  sctpOptions.defaultStreamPriority,
57
+ sctpOptions.defaultStreamBufferedAmountLowThreshold,
57
58
  sctpOptions.totalBufferedAmountLowThreshold),
58
59
  t1InitTimer(this->shared->CreateBackoffTimer(
59
60
  BackoffTimerHandleInterface::BackoffTimerHandleOptions{
@@ -4,7 +4,8 @@
4
4
  #include "RTC/SCTP/association/StateCookie.hpp"
5
5
  #include "Logger.hpp"
6
6
  #include "MediaSoupErrors.hpp"
7
- #include <cstring> // std::memcpy(), std::memcmp()
7
+ #include <openssl/crypto.h>
8
+ #include <cstring> // std::memcpy()
8
9
  #include <string_view>
9
10
 
10
11
  namespace RTC
@@ -179,7 +180,9 @@ namespace RTC
179
180
  const uint8_t* expectedMac = Utils::Crypto::GetHmacSha1(
180
181
  reinterpret_cast<const char*>(macKey), macKeyLength, buffer, StateCookie::MacOffset);
181
182
 
182
- return std::memcmp(buffer + StateCookie::MacOffset, expectedMac, StateCookie::MacLength) == 0;
183
+ // NOTE: Use `CRYPTO_memcmp()` to have constant time memory comparison.
184
+ // See https://github.com/versatica/mediasoup/security/advisories/GHSA-xvjj-6cm4-ppgq
185
+ return CRYPTO_memcmp(buffer + StateCookie::MacOffset, expectedMac, StateCookie::MacLength) == 0;
183
186
  }
184
187
 
185
188
  Types::SctpImplementation StateCookie::DetermineSctpImplementation(
@@ -81,8 +81,11 @@ namespace RTC
81
81
  new MissingMandatoryParameterErrorCause(const_cast<uint8_t*>(buffer), bufferLength);
82
82
 
83
83
  // In this chunk we must validate that some fields have correct values.
84
+ //
85
+ // NOTE: Must cast result to uint64_t to avoid integer overflow.
86
+ // See https://github.com/versatica/mediasoup/security/advisories/GHSA-p9cq-fqxc-987w
84
87
  if (
85
- (errorCause->GetNumberOfMissingParameters() * 2) !=
88
+ (static_cast<uint64_t>(errorCause->GetNumberOfMissingParameters()) * 2) !=
86
89
  causeLength -
87
90
  MissingMandatoryParameterErrorCause::MissingMandatoryParameterErrorCauseHeaderLength)
88
91
  {
@@ -20,9 +20,11 @@ namespace RTC
20
20
  AssociationListenerInterface& associationListener,
21
21
  size_t mtu,
22
22
  uint16_t defaultPriority,
23
+ size_t defaultStreamBufferedAmountLowThreshold,
23
24
  size_t totalBufferedAmountLowThreshold)
24
25
  : associationListener(associationListener),
25
26
  defaultPriority(defaultPriority),
27
+ defaultStreamBufferedAmountLowThreshold(defaultStreamBufferedAmountLowThreshold),
26
28
  scheduler(mtu),
27
29
  totalBufferedAmountThresholdWatcher(
28
30
  [this]()
@@ -256,7 +258,9 @@ namespace RTC
256
258
 
257
259
  if (it == this->streams.end())
258
260
  {
259
- return 0;
261
+ // The stream is created lazily (on first send or when its threshold is
262
+ // explicitly set), so report the default that it will be created with.
263
+ return this->defaultStreamBufferedAmountLowThreshold;
260
264
  }
261
265
 
262
266
  const auto& stream = it->second;
@@ -297,7 +301,11 @@ namespace RTC
297
301
  this->associationListener.OnAssociationStreamBufferedAmountLow(streamId);
298
302
  }));
299
303
 
300
- return it2->second;
304
+ auto& stream = it2->second;
305
+
306
+ stream.GetBufferedAmount().SetLowThreshold(this->defaultStreamBufferedAmountLowThreshold);
307
+
308
+ return stream;
301
309
  }
302
310
 
303
311
  void RoundRobinSendQueue::AssertIsConsistent() const
@@ -5,7 +5,6 @@
5
5
  #include "DepLibSRTP.hpp"
6
6
  #include "Logger.hpp"
7
7
  #include "MediaSoupErrors.hpp"
8
- #include <cstring> // std::memset()
9
8
 
10
9
  namespace RTC
11
10
  {
@@ -127,42 +126,34 @@ namespace RTC
127
126
  {
128
127
  MS_TRACE();
129
128
 
130
- srtp_policy_t policy; // NOLINT(cppcoreguidelines-pro-type-member-init)
131
-
132
- // Set all policy fields to 0.
133
- std::memset(&policy, 0, sizeof(srtp_policy_t));
129
+ srtp_profile_t profile;
134
130
 
135
131
  switch (cryptoSuite)
136
132
  {
137
133
  case CryptoSuite::AEAD_AES_256_GCM:
138
134
  {
139
- srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
140
- srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
135
+ profile = srtp_profile_aead_aes_256_gcm;
141
136
 
142
137
  break;
143
138
  }
144
139
 
145
140
  case CryptoSuite::AEAD_AES_128_GCM:
146
141
  {
147
- srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
148
- srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
142
+ profile = srtp_profile_aead_aes_128_gcm;
149
143
 
150
144
  break;
151
145
  }
152
146
 
153
147
  case CryptoSuite::AES_CM_128_HMAC_SHA1_80:
154
148
  {
155
- srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
156
- srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
149
+ profile = srtp_profile_aes128_cm_sha1_80;
157
150
 
158
151
  break;
159
152
  }
160
153
 
161
154
  case CryptoSuite::AES_CM_128_HMAC_SHA1_32:
162
155
  {
163
- srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
164
- // NOTE: Must be 80 for RTCP.
165
- srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
156
+ profile = srtp_profile_aes128_cm_sha1_32;
166
157
 
167
158
  break;
168
159
  }
@@ -173,35 +164,101 @@ namespace RTC
173
164
  }
174
165
  }
175
166
 
176
- MS_ASSERT(
177
- keyLen == policy.rtp.cipher_key_len, "given keyLen does not match policy.rtp.cipher_keyLen");
167
+ // Create the policy object.
168
+ srtp_policy_t policy{ nullptr };
169
+ srtp_err_status_t err = srtp_policy_create(std::addressof(policy));
170
+
171
+ if (DepLibSRTP::IsError(err))
172
+ {
173
+ MS_THROW_ERROR("srtp_policy_create() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
174
+ }
175
+
176
+ // Set SSRC.
177
+ srtp_ssrc_t ssrc{};
178
178
 
179
179
  switch (type)
180
180
  {
181
181
  case Type::INBOUND:
182
182
  {
183
- policy.ssrc.type = ssrc_any_inbound;
183
+ ssrc.type = ssrc_any_inbound;
184
184
 
185
185
  break;
186
186
  }
187
187
 
188
188
  case Type::OUTBOUND:
189
189
  {
190
- policy.ssrc.type = ssrc_any_outbound;
190
+ ssrc.type = ssrc_any_outbound;
191
191
 
192
192
  break;
193
193
  }
194
194
  }
195
195
 
196
- policy.ssrc.value = 0;
197
- policy.key = key;
196
+ ssrc.value = 0;
197
+
198
+ err = srtp_policy_set_ssrc(policy, ssrc);
199
+
200
+ if (DepLibSRTP::IsError(err))
201
+ {
202
+ srtp_policy_destroy(policy);
203
+ MS_THROW_ERROR("srtp_policy_set_ssrc() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
204
+ }
205
+
206
+ // Set the crypto profile.
207
+ err = srtp_policy_set_profile(policy, profile);
208
+
209
+ if (DepLibSRTP::IsError(err))
210
+ {
211
+ srtp_policy_destroy(policy);
212
+ MS_THROW_ERROR("srtp_policy_set_profile() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
213
+ }
214
+
215
+ // Split the concatenated key+salt buffer using the profile's lengths.
216
+ const size_t masterKeyLen = srtp_profile_get_master_key_length(profile);
217
+ const size_t masterSaltLen = srtp_profile_get_master_salt_length(profile);
218
+
219
+ MS_ASSERT(
220
+ keyLen == masterKeyLen + masterSaltLen,
221
+ "given keyLen does not match profile master key + salt length");
222
+
223
+ err = srtp_policy_add_key(
224
+ policy,
225
+ /*key*/ key,
226
+ /*key_len*/ masterKeyLen,
227
+ /*salt*/ key + masterKeyLen,
228
+ /*salt_len*/ masterSaltLen,
229
+ /*mki*/ nullptr,
230
+ /*mki_len*/ 0);
231
+
232
+ if (DepLibSRTP::IsError(err))
233
+ {
234
+ srtp_policy_destroy(policy);
235
+ MS_THROW_ERROR("srtp_policy_add_key() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
236
+ }
237
+
198
238
  // Required for sending RTP retransmission without RTX.
199
- policy.allow_repeat_tx = true;
200
- policy.window_size = 1024;
201
- policy.next = nullptr;
239
+ err = srtp_policy_set_allow_repeat_tx(policy, true);
240
+
241
+ if (DepLibSRTP::IsError(err))
242
+ {
243
+ srtp_policy_destroy(policy);
244
+ MS_THROW_ERROR(
245
+ "srtp_policy_set_allow_repeat_tx() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
246
+ }
247
+
248
+ err = srtp_policy_set_window_size(policy, 1024);
249
+
250
+ if (DepLibSRTP::IsError(err))
251
+ {
252
+ srtp_policy_destroy(policy);
253
+ MS_THROW_ERROR(
254
+ "srtp_policy_set_window_size() failed: %s", DepLibSRTP::GetErrorString(err).c_str());
255
+ }
256
+
257
+ // Create the SRTP session.
258
+ err = srtp_create(std::addressof(this->session), policy);
202
259
 
203
- // Set the SRTP session.
204
- const srtp_err_status_t err = srtp_create(&this->session, &policy);
260
+ // Policy is no longer needed once the session is created.
261
+ srtp_policy_destroy(policy);
205
262
 
206
263
  if (DepLibSRTP::IsError(err))
207
264
  {
@@ -49,20 +49,10 @@ namespace RTC
49
49
  {
50
50
  MS_TRACE();
51
51
 
52
+ this->direct = options->direct();
52
53
  this->maxSendMessageSize = options->maxSendMessageSize();
53
54
  this->maxReceiveMessageSize = options->maxReceiveMessageSize();
54
55
 
55
- if (options->direct())
56
- {
57
- this->direct = true;
58
- }
59
- else
60
- {
61
- this->sctpSendBufferSize = options->sctpSendBufferSize();
62
- this->sctpPerStreamSendQueueLimit = options->sctpPerStreamSendQueueLimit();
63
- this->sctpMaxReceiverWindowBufferSize = options->sctpMaxReceiverWindowBufferSize();
64
- }
65
-
66
56
  if (
67
57
  auto initialAvailableOutgoingBitrate = options->initialAvailableOutgoingBitrate();
68
58
  initialAvailableOutgoingBitrate.has_value())
@@ -80,11 +70,13 @@ namespace RTC
80
70
  const RTC::SCTP::SctpOptions sctpOptions = {
81
71
  .mtu = RTC::Consts::MaxSafeMtuSizeForSctp,
82
72
  .maxSendMessageSize = this->maxSendMessageSize,
83
- .maxSendBufferSize = this->sctpSendBufferSize,
84
- .perStreamSendQueueLimit = this->sctpPerStreamSendQueueLimit,
73
+ .maxSendBufferSize = options->sctpSendBufferSize(),
74
+ .perStreamSendQueueLimit = options->sctpPerStreamSendQueueLimit(),
85
75
  .maxReceiveMessageSize = this->maxReceiveMessageSize,
86
- .maxReceiverWindowBufferSize = this->sctpMaxReceiverWindowBufferSize,
87
- .requireAuthenticatedCookie = requireSctpStateCookieAuthentication
76
+ .maxReceiverWindowBufferSize = options->sctpMaxReceiverWindowBufferSize(),
77
+ .defaultStreamBufferedAmountLowThreshold =
78
+ options->sctpDefaultStreamBufferedAmountLowThreshold(),
79
+ .requireAuthenticatedCookie = requireSctpStateCookieAuthentication
88
80
  };
89
81
 
90
82
  this->sctpAssociation = std::make_unique<RTC::SCTP::Association>(
@@ -1,8 +1,8 @@
1
1
  [wrap-file]
2
- directory = libsrtp-3.0.0-beta
3
- source_url = https://github.com/versatica/libsrtp/archive/v3.0.0-beta.zip
4
- source_filename = libsrtp-3.0.0-beta.zip
5
- source_hash = b0cb21aaf27120b1a242f3d9b07c145b4a6c7a02a25da0824539fd95611f690c
2
+ directory = libsrtp-3.0.0-beta-2fc078db
3
+ source_url = https://github.com/versatica/libsrtp/archive/v3.0.0-beta-2fc078db.zip
4
+ source_filename = libsrtp-3.0.0-beta-2fc078db.zip
5
+ source_hash = d2c0fc2fdb84c615ed835471014611fb0b55f92c183c690ebeceb6ad4821a8b9
6
6
 
7
7
  [provide]
8
8
  libsrtp3 = libsrtp3_dep
package/worker/tasks.py CHANGED
@@ -43,7 +43,7 @@ NUM_CORES = (
43
43
  )
44
44
  PYTHON = os.getenv("PYTHON") or sys.executable
45
45
  MESON = os.getenv("MESON") or f"{PIP_MESON_NINJA_DIR}/bin/meson"
46
- MESON_VERSION = os.getenv("MESON_VERSION") or "1.9.1"
46
+ MESON_VERSION = os.getenv("MESON_VERSION") or "1.11.2"
47
47
  # MESON_ARGS can be used to provide extra configuration parameters to meson,
48
48
  # such as adding defines or changing optimization options. For instance, use
49
49
  # `MESON_ARGS="-Dms_log_trace=true -Dms_log_file_line=true" npm i` to compile
@@ -1057,6 +1057,40 @@ SCENARIO("SCTP Association", "[sctp][association]")
1057
1057
  REQUIRE(a.listener.HasOnStreamBufferedAmountLowBeenCalledWithStreamId(1) == true);
1058
1058
  }
1059
1059
 
1060
+ SECTION("applies the configured default buffered amount low threshold to new streams")
1061
+ {
1062
+ auto sctpOptions = makeSctpOptions();
1063
+
1064
+ sctpOptions.defaultStreamBufferedAmountLowThreshold = 1024;
1065
+
1066
+ AssociationUnderTest a(sctpOptions);
1067
+
1068
+ // Sending a message creates the outgoing stream, which must inherit the
1069
+ // configured default buffered amount low threshold.
1070
+ sendMessage(a, 1, 53, std::vector<uint8_t>(10));
1071
+
1072
+ REQUIRE(a.association.GetStreamBufferedAmountLowThreshold(1) == 1024);
1073
+ }
1074
+
1075
+ SECTION("does not trigger buffered amount low until crossing a non-zero default threshold")
1076
+ {
1077
+ auto sctpOptions = makeSctpOptions();
1078
+
1079
+ sctpOptions.defaultStreamBufferedAmountLowThreshold = 1024;
1080
+
1081
+ AssociationUnderTest a(sctpOptions);
1082
+ AssociationUnderTest z;
1083
+
1084
+ connectAssociations(a, z);
1085
+
1086
+ // A small message never takes the buffered amount above the threshold, so
1087
+ // draining it must not trigger the event.
1088
+ sendMessage(a, 1, 53, std::vector<uint8_t>(10));
1089
+ exchangeMessages(a, z);
1090
+
1091
+ REQUIRE(a.listener.HasOnStreamBufferedAmountLowBeenCalledWithStreamId(1) == false);
1092
+ }
1093
+
1060
1094
  SECTION("detects the peer implementation")
1061
1095
  {
1062
1096
  AssociationUnderTest a;
@@ -57,6 +57,7 @@ namespace
57
57
  this->associationListener,
58
58
  this->sctpOptions.mtu,
59
59
  this->sctpOptions.defaultStreamPriority,
60
+ this->sctpOptions.defaultStreamBufferedAmountLowThreshold,
60
61
  this->sctpOptions.totalBufferedAmountLowThreshold),
61
62
  dataTracker(this->delayedAckTimer.get(), RemoteInitialTsn),
62
63
  reassemblyQueue(this->sctpOptions.maxReceiverWindowBufferSize),
@@ -164,6 +164,30 @@ SCENARIO("Invalid Stream Identifier Error Cause (2)", "[serializable][sctp][erro
164
164
  // clang-format on
165
165
 
166
166
  REQUIRE(!RTC::SCTP::MissingMandatoryParameterErrorCause::Parse(buffer3, sizeof(buffer3)));
167
+
168
+ // Security advisory.
169
+ // See https://github.com/versatica/mediasoup/security/advisories/GHSA-p9cq-fqxc-987w
170
+ //
171
+ // Number of missing parameters chosen so that, multiplied by 2 in 32-bit
172
+ // arithmetic, it wraps around to a value that would falsely match the
173
+ // length field. 0x80000001 (2147483649) * 2 wraps to 2, which equals
174
+ // Length 10 minus the 8-byte header. The check must be done in 64-bit
175
+ // arithmetic so this malformed cause is rejected instead of accepted
176
+ // (which would later drive an out-of-bounds read while iterating the
177
+ // bogus 2.1 billion parameter count).
178
+ // clang-format off
179
+ alignas(4) uint8_t buffer4[] =
180
+ {
181
+ // Code:2 (MISSING-MANDATORY-PARAMETER), Length: 10
182
+ 0x00, 0x02, 0x00, 0x0A,
183
+ // Number of missing params: 0x80000001 (2147483649)
184
+ 0x80, 0x00, 0x00, 0x01,
185
+ // A single param type (2 bytes) plus 2 bytes of padding
186
+ 0x00, 0x05, 0x00, 0x00,
187
+ };
188
+ // clang-format on
189
+
190
+ REQUIRE(!RTC::SCTP::MissingMandatoryParameterErrorCause::Parse(buffer4, sizeof(buffer4)));
167
191
  }
168
192
 
169
193
  SECTION("MissingMandatoryParameterErrorCause::Factory() succeeds")