Skip to content

Commit 89197a0

Browse files
bcallerdarrachequesne
authored andcommitted
fix: prevent DoS (OOM) via massive packets (#95)
When maxHttpBufferSize is large (1e8 bytes), a payload of length 100MB can be sent like so: 99999991:422222222222222222222222222222222222222222222... This massive packet can cause OOM via building up many many `ConsOneByteString` objects due to concatenation: 99999989 `ConsOneByteString`s and then converting the massive integer to a `Number`. The performance can be improved to avoid this by using `substring` rather than building the string via concatenation. Below I tried one payload of length 7e7 as the 1e8 payload took so long to process that it timed out before running out of memory. ``` ==== JS stack trace ========================================= 0: ExitFrame [pc: 0x13c5b79] Security context: 0x152fe7b808d1 <JSObject> 1: decodeString [0x2dd385fb5d1] [/node_modules/socket.io-parser/index.js:~276] [pc=0xf59746881be](this=0x175d34c42b69 <JSGlobal Object>,0x14eccff10fe1 <Very long string[69999990]>) 2: add [0x31fc2693da29] [/node_modules/socket.io-parser/index.js:242] [bytecode=0xa7ed6554889 offset=11](this=0x0a2881be5069 <Decoder map = 0x3ceaa8bf48c9>,0x14eccff10fe1 <Very... FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 1: 0xa09830 node::Abort() [node] 2: 0xa09c55 node::OnFatalError(char const*, char const*) [node] 3: 0xb7d71e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node] 4: 0xb7da99 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node] 5: 0xd2a1f5 [node] 6: 0xd2a886 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [node] 7: 0xd37105 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [node] 8: 0xd37fb5 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node] 9: 0xd3965f v8::internal::Heap::HandleGCRequest() [node] 10: 0xce8395 v8::internal::StackGuard::HandleInterrupts() [node] 11: 0x1042cb6 v8::internal::Runtime_StackGuard(int, unsigned long*, v8::internal::Isolate*) [node] 12: 0x13c5b79 [node] ``` Backported from master: dcb942d
1 parent 25ca624 commit 89197a0

File tree

1 file changed

+7
-10
lines changed

1 file changed

+7
-10
lines changed

index.js

+7-10
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,9 @@ function decodeString(str) {
286286

287287
// look up attachments if type binary
288288
if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) {
289-
var buf = '';
290-
while (str.charAt(++i) !== '-') {
291-
buf += str.charAt(i);
292-
if (i == str.length) break;
293-
}
289+
var start = i + 1;
290+
while (str.charAt(++i) !== '-' && i != str.length) {}
291+
var buf = str.substring(start, i);
294292
if (buf != Number(buf) || str.charAt(i) !== '-') {
295293
throw new Error('Illegal attachments');
296294
}
@@ -299,31 +297,30 @@ function decodeString(str) {
299297

300298
// look up namespace (if any)
301299
if ('/' === str.charAt(i + 1)) {
302-
p.nsp = '';
300+
var start = i + 1;
303301
while (++i) {
304302
var c = str.charAt(i);
305303
if (',' === c) break;
306-
p.nsp += c;
307304
if (i === str.length) break;
308305
}
306+
p.nsp = str.substring(start, i);
309307
} else {
310308
p.nsp = '/';
311309
}
312310

313311
// look up id
314312
var next = str.charAt(i + 1);
315313
if ('' !== next && Number(next) == next) {
316-
p.id = '';
314+
var start = i + 1;
317315
while (++i) {
318316
var c = str.charAt(i);
319317
if (null == c || Number(c) != c) {
320318
--i;
321319
break;
322320
}
323-
p.id += str.charAt(i);
324321
if (i === str.length) break;
325322
}
326-
p.id = Number(p.id);
323+
p.id = Number(str.substring(start, i + 1));
327324
}
328325

329326
// look up json data

0 commit comments

Comments
 (0)