From f6f61c3a31f09bd3caab2c201901dfbcc51657ec Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 5 Aug 2026 10:25:32 +0100 Subject: [PATCH] buffer: prevent string write offset overflow Reject offsets outside the destination buffer before subtracting from its length in SlowWriteString. Normalize wrapper arguments once so validated values reach the native binding. Signed-off-by: Matteo Collina --- lib/internal/buffer.js | 15 ++++++++++++--- src/node_buffer.cc | 5 +++++ test/parallel/test-buffer-write.js | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index d23f5d0ab6ab..a5965e84885a 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -959,30 +959,39 @@ function writeFloatBackwards(val, offset = 0) { class FastBuffer extends Uint8Array {} -function asciiWrite(buf, string, offset = 0, length = buf.byteLength - offset) { +function asciiWrite(buf, string, offset = 0, length) { + offset = Number(offset); if (offset < 0 || offset > buf.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } + if (length === undefined) length = buf.byteLength - offset; + else length = Number(length); if (length < 0 || length > buf.byteLength - offset) { throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); } return asciiWriteStatic(buf, string, offset, length); } -function latin1Write(buf, string, offset = 0, length = buf.byteLength - offset) { +function latin1Write(buf, string, offset = 0, length) { + offset = Number(offset); if (offset < 0 || offset > buf.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } + if (length === undefined) length = buf.byteLength - offset; + else length = Number(length); if (length < 0 || length > buf.byteLength - offset) { throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); } return latin1WriteStatic(buf, string, offset, length); } -function utf8Write(buf, string, offset = 0, length = buf.byteLength - offset) { +function utf8Write(buf, string, offset = 0, length) { + offset = Number(offset); if (offset < 0 || offset > buf.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } + if (length === undefined) length = buf.byteLength - offset; + else length = Number(length); if (length < 0 || length > buf.byteLength - offset) { throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); } diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 19c28609660d..89ea4f635e9f 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1727,6 +1727,11 @@ void SlowWriteString(const FunctionCallbackInfo& args) { size_t max_length = 0; THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &offset)); + if (offset > ts_obj_length) { + return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS( + env, "\"offset\" is outside of buffer bounds"); + } + THROW_AND_RETURN_IF_OOB( ParseArrayIndex(env, args[3], ts_obj_length - offset, &max_length)); diff --git a/test/parallel/test-buffer-write.js b/test/parallel/test-buffer-write.js index 4c797059b592..11cfb32ab19a 100644 --- a/test/parallel/test-buffer-write.js +++ b/test/parallel/test-buffer-write.js @@ -127,3 +127,17 @@ assert.throws(() => { }, common.expectsError({ code: 'ERR_BUFFER_OUT_OF_BOUNDS', })); + +for (const method of ['asciiWrite', 'latin1Write', 'utf8Write']) { + let calls = 0; + const offset = { + valueOf() { + calls++; + return 2; + }, + }; + assert.throws(() => Buffer.alloc(1)[method]('ww', offset, 1), common.expectsError({ + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + })); + assert.strictEqual(calls, 1); +}