From 63a0887f35ae837e4e73cc05640b029dcb23d6d6 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Fri, 22 Oct 2021 20:00:45 +0300 Subject: [PATCH] dgram: fix send with out of bounds offset + length fix Socket.prototype.send sending garbage when the message is a string, or Buffer and offset+length is out of bounds. Fixes: https://github.com/nodejs/node/issues/40491 --- lib/dgram.js | 13 ++++ .../parallel/test-dgram-send-bad-arguments.js | 65 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/lib/dgram.js b/lib/dgram.js index 931d9a49544dcc..202d33636893af 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -42,6 +42,7 @@ const { guessHandleType } = internalBinding('util'); const { ERR_INVALID_ARG_TYPE, ERR_MISSING_ARGS, + ERR_OUT_OF_RANGE, ERR_SOCKET_ALREADY_BOUND, ERR_SOCKET_BAD_BUFFER_SIZE, ERR_SOCKET_BUFFER_SIZE, @@ -488,6 +489,18 @@ function sliceBuffer(buffer, offset, length) { offset = offset >>> 0; length = length >>> 0; + // TypedArray and DataView bounds are checked in Buffer.from + if (Buffer.isBuffer(buffer)) { + if (offset > buffer.byteLength) { + throw new ERR_OUT_OF_RANGE('offset', `<= ${buffer.byteLength}`, offset); + } + + if (offset + length > buffer.byteLength) { + throw new ERR_OUT_OF_RANGE('length', + `<= ${buffer.byteLength - offset}`, length); + } + } + return Buffer.from(buffer.buffer, buffer.byteOffset + offset, length); } diff --git a/test/parallel/test-dgram-send-bad-arguments.js b/test/parallel/test-dgram-send-bad-arguments.js index 3e42f31b1af4b6..fa250cfc4e0da0 100644 --- a/test/parallel/test-dgram-send-bad-arguments.js +++ b/test/parallel/test-dgram-send-bad-arguments.js @@ -77,6 +77,71 @@ function checkArgs(connected) { message: 'Already connected' } ); + + for (const input of ['hello', Buffer.from('hello'), + Buffer.from('hello world').subarray(0, 5), + Buffer.from('hello world').subarray(6)]) { + assert.throws( + () => { sock.send(input, 6, 0); }, + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "offset" is out of range. ' + + 'It must be <= 5. Received 6' + } + ); + + assert.throws( + () => { sock.send(input, 0, 6); }, + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "length" is out of range. ' + + 'It must be <= 5. Received 6' + } + ); + + assert.throws( + () => { sock.send(input, 3, 4); }, + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "length" is out of range. ' + + 'It must be <= 2. Received 4' + } + ); + } + + for (const input of [new Uint8Array([1, 2, 3, 4, 5]), + new DataView(new ArrayBuffer(5), 0), + new DataView(new ArrayBuffer(6), 2)]) { + assert.throws( + () => { sock.send(input, 6, 0); }, + { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: '"offset" is outside of buffer bounds', + } + ); + + assert.throws( + () => { sock.send(input, 0, 6); }, + { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: '"length" is outside of buffer bounds', + } + ); + + assert.throws( + () => { sock.send(input, 3, 4); }, + { + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + name: 'RangeError', + message: '"length" is outside of buffer bounds', + } + ); + } } else { assert.throws(() => { sock.send(buf, 1, 1, -1, host); }, RangeError); assert.throws(() => { sock.send(buf, 1, 1, 0, host); }, RangeError);