Skip to content

Commit 881c244

Browse files
jasnellBethGriggs
authored andcommittedJun 2, 2020
http2: implement support for max settings entries
Adds the maxSettings option to limit the number of settings entries allowed per SETTINGS frame. Default 32 Signed-off-by: James M Snell <jasnell@gmail.com> Fixes: https://hackerone.com/reports/446662 CVE-ID: CVE-2020-11080 PR-URL: nodejs-private/node-private#204 Backport-PR-URL: nodejs-private/node-private#207 Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com> Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
1 parent 33e9a12 commit 881c244

File tree

6 files changed

+70
-3
lines changed

6 files changed

+70
-3
lines changed
 

‎doc/api/http2.md

+15
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,9 @@ error will be thrown.
19001900
<!-- YAML
19011901
added: v8.4.0
19021902
changes:
1903+
- version: REPLACEME
1904+
pr-url: https://github.com/nodejs-private/node-private/pull/204
1905+
description: Added `maxSettings` option with a default of 32.
19031906
- version: v8.9.3
19041907
pr-url: https://github.com/nodejs/node/pull/17105
19051908
description: Added the `maxOutstandingPings` option with a default limit of
@@ -1917,6 +1920,8 @@ changes:
19171920
* `options` {Object}
19181921
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
19191922
for deflating header fields. **Default:** `4Kib`.
1923+
* `maxSettings` {number} Sets the maximum number of settings entries per
1924+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
19201925
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
19211926
is permitted to use. The value is expressed in terms of number of megabytes,
19221927
e.g. `1` equal 1 megabyte. The minimum value allowed is `1`.
@@ -2010,6 +2015,9 @@ server.listen(80);
20102015
<!-- YAML
20112016
added: v8.4.0
20122017
changes:
2018+
- version: REPLACEME
2019+
pr-url: https://github.com/nodejs-private/node-private/pull/204
2020+
description: Added `maxSettings` option with a default of 32.
20132021
- version: v10.12.0
20142022
pr-url: https://github.com/nodejs/node/pull/22956
20152023
description: Added the `origins` option to automatically send an `ORIGIN`
@@ -2031,6 +2039,8 @@ changes:
20312039
**Default:** `false`.
20322040
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
20332041
for deflating header fields. **Default:** `4Kib`.
2042+
* `maxSettings` {number} Sets the maximum number of settings entries per
2043+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
20342044
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
20352045
is permitted to use. The value is expressed in terms of number of megabytes,
20362046
e.g. `1` equal 1 megabyte. The minimum value allowed is `1`. This is a
@@ -2112,6 +2122,9 @@ server.listen(80);
21122122
<!-- YAML
21132123
added: v8.4.0
21142124
changes:
2125+
- version: REPLACEME
2126+
pr-url: https://github.com/nodejs-private/node-private/pull/204
2127+
description: Added `maxSettings` option with a default of 32.
21152128
- version: v8.9.3
21162129
pr-url: https://github.com/nodejs/node/pull/17105
21172130
description: Added the `maxOutstandingPings` option with a default limit of
@@ -2126,6 +2139,8 @@ changes:
21262139
* `options` {Object}
21272140
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
21282141
for deflating header fields. **Default:** `4Kib`.
2142+
* `maxSettings` {number} Sets the maximum number of settings entries per
2143+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
21292144
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
21302145
is permitted to use. The value is expressed in terms of number of megabytes,
21312146
e.g. `1` equal 1 megabyte. The minimum value allowed is `1`.

‎lib/internal/http2/util.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5;
186186
const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6;
187187
const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7;
188188
const IDX_OPTIONS_MAX_SESSION_MEMORY = 8;
189-
const IDX_OPTIONS_FLAGS = 9;
189+
const IDX_OPTIONS_MAX_SETTINGS = 9;
190+
const IDX_OPTIONS_FLAGS = 10;
190191

191192
function updateOptionsBuffer(options) {
192193
var flags = 0;
@@ -235,6 +236,11 @@ function updateOptionsBuffer(options) {
235236
optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY] =
236237
Math.max(1, options.maxSessionMemory);
237238
}
239+
if (typeof options.maxSettings === 'number') {
240+
flags |= (1 << IDX_OPTIONS_MAX_SETTINGS);
241+
optionsBuffer[IDX_OPTIONS_MAX_SETTINGS] =
242+
Math.max(1, options.maxSettings);
243+
}
238244
optionsBuffer[IDX_OPTIONS_FLAGS] = flags;
239245
}
240246

‎src/node_http2.cc

+6
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ Http2Options::Http2Options(Environment* env, nghttp2_session_type type) {
203203
if (flags & (1 << IDX_OPTIONS_MAX_SESSION_MEMORY)) {
204204
SetMaxSessionMemory(buffer[IDX_OPTIONS_MAX_SESSION_MEMORY] * 1e6);
205205
}
206+
207+
if (flags & (1 << IDX_OPTIONS_MAX_SETTINGS)) {
208+
nghttp2_option_set_max_settings(
209+
options_,
210+
static_cast<size_t>(buffer[IDX_OPTIONS_MAX_SETTINGS]));
211+
}
206212
}
207213

208214
void Http2Session::Http2Settings::Init() {

‎src/node_http2_state.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ namespace http2 {
5252
IDX_OPTIONS_MAX_OUTSTANDING_PINGS,
5353
IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS,
5454
IDX_OPTIONS_MAX_SESSION_MEMORY,
55+
IDX_OPTIONS_MAX_SETTINGS,
5556
IDX_OPTIONS_FLAGS
5657
};
5758

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const http2 = require('http2');
8+
9+
const server = http2.createServer({ maxSettings: 1 });
10+
11+
// TODO(@jasnell): There is still a session event
12+
// emitted on the server side but it will be destroyed
13+
// immediately after creation and there will be no
14+
// stream created.
15+
server.on('session', common.mustCall((session) => {
16+
session.on('stream', common.mustNotCall());
17+
session.on('remoteSettings', common.mustNotCall());
18+
}));
19+
server.on('stream', common.mustNotCall());
20+
21+
server.listen(0, common.mustCall(() => {
22+
// Specify two settings entries when a max of 1 is allowed.
23+
// Connection should error immediately.
24+
const client = http2.connect(
25+
`http://localhost:${server.address().port}`, {
26+
settings: {
27+
// The actual settings values do not matter.
28+
headerTableSize: 1000,
29+
enablePush: false,
30+
} });
31+
32+
client.on('error', common.mustCall(() => {
33+
server.close();
34+
}));
35+
}));

‎test/parallel/test-http2-util-update-options-buffer.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5;
2121
const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6;
2222
const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7;
2323
const IDX_OPTIONS_MAX_SESSION_MEMORY = 8;
24-
const IDX_OPTIONS_FLAGS = 9;
24+
const IDX_OPTIONS_MAX_SETTINGS = 9;
25+
const IDX_OPTIONS_FLAGS = 10;
2526

2627
{
2728
updateOptionsBuffer({
@@ -33,7 +34,8 @@ const IDX_OPTIONS_FLAGS = 9;
3334
maxHeaderListPairs: 6,
3435
maxOutstandingPings: 7,
3536
maxOutstandingSettings: 8,
36-
maxSessionMemory: 9
37+
maxSessionMemory: 9,
38+
maxSettings: 10,
3739
});
3840

3941
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE], 1);
@@ -45,6 +47,7 @@ const IDX_OPTIONS_FLAGS = 9;
4547
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS], 7);
4648
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS], 8);
4749
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY], 9);
50+
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SETTINGS], 10);
4851

4952
const flags = optionsBuffer[IDX_OPTIONS_FLAGS];
5053

@@ -56,6 +59,7 @@ const IDX_OPTIONS_FLAGS = 9;
5659
ok(flags & (1 << IDX_OPTIONS_MAX_HEADER_LIST_PAIRS));
5760
ok(flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_PINGS));
5861
ok(flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS));
62+
ok(flags & (1 << IDX_OPTIONS_MAX_SETTINGS));
5963
}
6064

6165
{

0 commit comments

Comments
 (0)
Please sign in to comment.