From f66898b66505f6f44cec5d3c821fab598c26b7fd Mon Sep 17 00:00:00 2001 From: nashit hayyat Date: Tue, 11 Aug 2026 19:01:56 +0530 Subject: [PATCH] http2: fix out-of-bounds write in altsvc frame buffers Signed-off-by: nashit hayyat --- src/node_http2.cc | 9 +--- test/parallel/test-http2-altsvc-large.js | 57 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 test/parallel/test-http2-altsvc-large.js diff --git a/src/node_http2.cc b/src/node_http2.cc index 04b2acca148d..9ea1d24fef20 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -3403,13 +3403,8 @@ void Http2Session::AltSvc(const FunctionCallbackInfo& args) { MaybeStackBuffer origin(origin_len); MaybeStackBuffer value(value_len); - origin_str->WriteOneByteV2(env->isolate(), - 0, - origin_len, - *origin, - String::WriteFlags::kNullTerminate); - value_str->WriteOneByteV2( - env->isolate(), 0, value_len, *value, String::WriteFlags::kNullTerminate); + origin_str->WriteOneByteV2(env->isolate(), 0, origin_len, *origin); + value_str->WriteOneByteV2(env->isolate(), 0, value_len, *value); session->AltSvc(id, *origin, origin_len, *value, value_len); } diff --git a/test/parallel/test-http2-altsvc-large.js b/test/parallel/test-http2-altsvc-large.js new file mode 100644 index 000000000000..1b6e1eceaea0 --- /dev/null +++ b/test/parallel/test-http2-altsvc-large.js @@ -0,0 +1,57 @@ +'use strict'; + +// Regression test for a one-byte out-of-bounds write in Http2Session::AltSvc. +// The native handler allocated origin/value buffers sized to the string length +// but wrote them with a null terminator, so an origin or alt value longer than +// the inline stack buffer (1024 bytes) overflowed the heap allocation by one +// byte. Exercise both paths with values above that threshold and confirm the +// frames round-trip intact. + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const http2 = require('http2'); +const Countdown = require('../common/countdown'); + +// alt is limited to a quoted-string; padding is well past the 1024-byte inline +// buffer so the value is heap-allocated at its exact length. +const largeAlt = `h2=":8000"; ma=${'0'.repeat(2000)}`; +const largeOrigin = `https://${'a'.repeat(1200)}.example.org`; + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + // origin is empty here, so this exercises the value (alt) buffer. + stream.session.altsvc(largeAlt, stream.id); + stream.respond(); + stream.end('ok'); +})); +server.on('session', common.mustCall((session) => { + // stream id 0 with a long origin exercises the origin buffer. + session.altsvc('h2=":8000"', largeOrigin); +})); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + + const countdown = new Countdown(2, () => { + client.close(); + server.close(); + }); + + client.on('altsvc', common.mustCall((alt, origin, stream) => { + if (stream === 0) { + assert.strictEqual(alt, 'h2=":8000"'); + assert.strictEqual(origin, new URL(largeOrigin).origin); + } else { + assert.strictEqual(alt, largeAlt); + assert.strictEqual(origin, ''); + } + countdown.dec(); + }, 2)); + + const req = client.request(); + req.resume(); + req.on('close', common.mustCall()); +}));