Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/node_http2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3403,13 +3403,8 @@ void Http2Session::AltSvc(const FunctionCallbackInfo<Value>& args) {

MaybeStackBuffer<uint8_t> origin(origin_len);
MaybeStackBuffer<uint8_t> 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);
}
Expand Down
57 changes: 57 additions & 0 deletions test/parallel/test-http2-altsvc-large.js
Original file line number Diff line number Diff line change
@@ -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());
}));
Loading