Skip to content

Commit 57a71cd

Browse files
authored
http2: validate initialWindowSize per HTTP/2 spec
The HTTP/2 spec (RFC 7540) defines SETTINGS_INITIAL_WINDOW_SIZE maximum as 2^31-1. Values above this must be treated as a FLOW_CONTROL_ERROR. Previously, Node.js allowed values up to 2^32-1 which caused nghttp2_submit_settings() to return NGHTTP2_ERR_INVALID_ARGUMENT, triggering an uncatchable assertion failure and crashing the process. This change adds proper validation to reject values >= 2^31 with a catchable RangeError before they reach nghttp2. PR-URL: #61402 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent 5f982e2 commit 57a71cd

File tree

3 files changed

+8
-3
lines changed

3 files changed

+8
-3
lines changed

lib/internal/http2/core.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ function debugSessionObj(session, message, ...args) {
230230

231231
const kMaxFrameSize = (2 ** 24) - 1;
232232
const kMaxInt = (2 ** 32) - 1;
233+
const kMaxInitialWindowSize = (2 ** 31) - 1; // HTTP/2 spec maximum
233234
const kMaxStreams = (2 ** 32) - 1;
234235
const kMaxALTSVC = (2 ** 14) - 2;
235236

@@ -989,7 +990,7 @@ function pingCallback(cb) {
989990

990991
// Validates the values in a settings object. Specifically:
991992
// 1. headerTableSize must be a number in the range 0 <= n <= kMaxInt
992-
// 2. initialWindowSize must be a number in the range 0 <= n <= kMaxInt
993+
// 2. initialWindowSize must be a number in the range 0 <= n <= 2^31-1
993994
// 3. maxFrameSize must be a number in the range 16384 <= n <= kMaxFrameSize
994995
// 4. maxConcurrentStreams must be a number in the range 0 <= n <= kMaxStreams
995996
// 5. maxHeaderListSize must be a number in the range 0 <= n <= kMaxInt
@@ -1014,7 +1015,7 @@ const validateSettings = hideStackFrames((settings) => {
10141015
0, kMaxInt);
10151016
assertWithinRange.withoutStackTrace('initialWindowSize',
10161017
settings.initialWindowSize,
1017-
0, kMaxInt);
1018+
0, kMaxInitialWindowSize);
10181019
assertWithinRange.withoutStackTrace('maxFrameSize',
10191020
settings.maxFrameSize,
10201021
16384, kMaxFrameSize);

test/parallel/test-http2-getpackedsettings.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ assert.deepStrictEqual(val, check);
2020
['headerTableSize', 0],
2121
['headerTableSize', 2 ** 32 - 1],
2222
['initialWindowSize', 0],
23-
['initialWindowSize', 2 ** 32 - 1],
23+
['initialWindowSize', 2 ** 31 - 1], // Max per HTTP/2 spec
2424
['maxFrameSize', 16384],
2525
['maxFrameSize', 2 ** 24 - 1],
2626
['maxConcurrentStreams', 0],
@@ -42,6 +42,8 @@ http2.getPackedSettings({ enablePush: false });
4242
['headerTableSize', -1],
4343
['headerTableSize', 2 ** 32],
4444
['initialWindowSize', -1],
45+
['initialWindowSize', 2 ** 31], // Max per HTTP/2 spec is 2^31-1
46+
['initialWindowSize', 2 ** 32 - 1], // Regression test for nghttp2 crash
4547
['initialWindowSize', 2 ** 32],
4648
['maxFrameSize', 16383],
4749
['maxFrameSize', 2 ** 24],

test/parallel/test-http2-session-settings.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ server.listen(
133133
['headerTableSize', -1],
134134
['headerTableSize', 2 ** 32],
135135
['initialWindowSize', -1],
136+
['initialWindowSize', 2 ** 31], // Max per HTTP/2 spec is 2^31-1
137+
['initialWindowSize', 2 ** 32 - 1], // Regression test for nghttp2 crash
136138
['initialWindowSize', 2 ** 32],
137139
['maxFrameSize', 16383],
138140
['maxFrameSize', 2 ** 24],

0 commit comments

Comments
 (0)