Skip to content

Commit d381426

Browse files
jasnelltargos
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#206 Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
1 parent 916b282 commit d381426

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
@@ -1948,6 +1948,9 @@ error will be thrown.
19481948
<!-- YAML
19491949
added: v8.4.0
19501950
changes:
1951+
- version: REPLACEME
1952+
pr-url: https://github.com/nodejs-private/node-private/pull/204
1953+
description: Added `maxSettings` option with a default of 32.
19511954
- version: v12.16.0
19521955
pr-url: https://github.com/nodejs/node/pull/30534
19531956
description: Added `maxSessionRejectedStreams` option with a default of 100.
@@ -1975,6 +1978,8 @@ changes:
19751978
* `options` {Object}
19761979
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
19771980
for deflating header fields. **Default:** `4Kib`.
1981+
* `maxSettings` {number} Sets the maximum number of settings entries per
1982+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
19781983
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
19791984
is permitted to use. The value is expressed in terms of number of megabytes,
19801985
e.g. `1` equal 1 megabyte. The minimum value allowed is `1`.
@@ -2078,6 +2083,9 @@ server.listen(80);
20782083
<!-- YAML
20792084
added: v8.4.0
20802085
changes:
2086+
- version: REPLACEME
2087+
pr-url: https://github.com/nodejs-private/node-private/pull/204
2088+
description: Added `maxSettings` option with a default of 32.
20812089
- version: v12.16.0
20822090
pr-url: https://github.com/nodejs/node/pull/30534
20832091
description: Added `maxSessionRejectedStreams` option with a default of 100.
@@ -2105,6 +2113,8 @@ changes:
21052113
**Default:** `false`.
21062114
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
21072115
for deflating header fields. **Default:** `4Kib`.
2116+
* `maxSettings` {number} Sets the maximum number of settings entries per
2117+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
21082118
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
21092119
is permitted to use. The value is expressed in terms of number of megabytes,
21102120
e.g. `1` equal 1 megabyte. The minimum value allowed is `1`. This is a
@@ -2195,6 +2205,9 @@ server.listen(80);
21952205
<!-- YAML
21962206
added: v8.4.0
21972207
changes:
2208+
- version: REPLACEME
2209+
pr-url: https://github.com/nodejs-private/node-private/pull/204
2210+
description: Added `maxSettings` option with a default of 32.
21982211
- version: v8.9.3
21992212
pr-url: https://github.com/nodejs/node/pull/17105
22002213
description: Added the `maxOutstandingPings` option with a default limit of
@@ -2213,6 +2226,8 @@ changes:
22132226
* `options` {Object}
22142227
* `maxDeflateDynamicTableSize` {number} Sets the maximum dynamic table size
22152228
for deflating header fields. **Default:** `4Kib`.
2229+
* `maxSettings` {number} Sets the maximum number of settings entries per
2230+
`SETTINGS` frame. The minimum value allowed is `1`. **Default:** `32`.
22162231
* `maxSessionMemory`{number} Sets the maximum memory that the `Http2Session`
22172232
is permitted to use. The value is expressed in terms of number of megabytes,
22182233
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
@@ -203,7 +203,8 @@ const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5;
203203
const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6;
204204
const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7;
205205
const IDX_OPTIONS_MAX_SESSION_MEMORY = 8;
206-
const IDX_OPTIONS_FLAGS = 9;
206+
const IDX_OPTIONS_MAX_SETTINGS = 9;
207+
const IDX_OPTIONS_FLAGS = 10;
207208

208209
function updateOptionsBuffer(options) {
209210
let flags = 0;
@@ -252,6 +253,11 @@ function updateOptionsBuffer(options) {
252253
optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY] =
253254
MathMax(1, options.maxSessionMemory);
254255
}
256+
if (typeof options.maxSettings === 'number') {
257+
flags |= (1 << IDX_OPTIONS_MAX_SETTINGS);
258+
optionsBuffer[IDX_OPTIONS_MAX_SETTINGS] =
259+
MathMax(1, options.maxSettings);
260+
}
255261
optionsBuffer[IDX_OPTIONS_FLAGS] = flags;
256262
}
257263

‎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
@@ -22,7 +22,8 @@ const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5;
2222
const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6;
2323
const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7;
2424
const IDX_OPTIONS_MAX_SESSION_MEMORY = 8;
25-
const IDX_OPTIONS_FLAGS = 9;
25+
const IDX_OPTIONS_MAX_SETTINGS = 9;
26+
const IDX_OPTIONS_FLAGS = 10;
2627

2728
{
2829
updateOptionsBuffer({
@@ -34,7 +35,8 @@ const IDX_OPTIONS_FLAGS = 9;
3435
maxHeaderListPairs: 6,
3536
maxOutstandingPings: 7,
3637
maxOutstandingSettings: 8,
37-
maxSessionMemory: 9
38+
maxSessionMemory: 9,
39+
maxSettings: 10,
3840
});
3941

4042
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE], 1);
@@ -46,6 +48,7 @@ const IDX_OPTIONS_FLAGS = 9;
4648
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS], 7);
4749
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS], 8);
4850
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SESSION_MEMORY], 9);
51+
strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SETTINGS], 10);
4952

5053
const flags = optionsBuffer[IDX_OPTIONS_FLAGS];
5154

@@ -57,6 +60,7 @@ const IDX_OPTIONS_FLAGS = 9;
5760
ok(flags & (1 << IDX_OPTIONS_MAX_HEADER_LIST_PAIRS));
5861
ok(flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_PINGS));
5962
ok(flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS));
63+
ok(flags & (1 << IDX_OPTIONS_MAX_SETTINGS));
6064
}
6165

6266
{

0 commit comments

Comments
 (0)
Please sign in to comment.