8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent ac28a62 commit 10f05b6Copy full SHA for 10f05b6
src/node_http2.cc
@@ -1328,6 +1328,8 @@ inline void Http2Session::HandleHeadersFrame(const nghttp2_frame* frame) {
1328
return;
1329
1330
std::vector<nghttp2_header> headers(stream->move_headers());
1331
+ DecrementCurrentSessionMemory(stream->current_headers_length_);
1332
+ stream->current_headers_length_ = 0;
1333
1334
Local<String> name_str;
1335
Local<String> value_str;
@@ -2021,6 +2023,7 @@ Http2Stream::~Http2Stream() {
2021
2023
if (session_ == nullptr)
2022
2024
2025
DEBUG_HTTP2STREAM(this, "tearing down stream");
2026
+ session_->DecrementCurrentSessionMemory(current_headers_length_);
2027
session_->RemoveStream(this);
2028
session_ = nullptr;
2029
@@ -2032,6 +2035,7 @@ Http2Stream::~Http2Stream() {
2032
2035
void Http2Stream::StartHeaders(nghttp2_headers_category category) {
2033
2036
DEBUG_HTTP2STREAM2(this, "starting headers, category: %d", id_, category);
2034
2037
CHECK(!this->IsDestroyed());
2038
2039
current_headers_length_ = 0;
2040
current_headers_.clear();
2041
current_headers_category_ = category;
@@ -2323,10 +2327,6 @@ inline int Http2Stream::DoWrite(WriteWrap* req_wrap,
2323
2327
return 0;
2324
2328
}
2325
2329
2326
-inline size_t GetBufferLength(nghttp2_rcbuf* buf) {
- return nghttp2_rcbuf_get_buf(buf).len;
-}
-
2330
// Ads a header to the Http2Stream. Note that the header name and value are
2331
// provided using a buffer structure provided by nghttp2 that allows us to
2332
// avoid unnecessary memcpy's. Those buffers are ref counted. The ref count
@@ -2338,7 +2338,12 @@ inline bool Http2Stream::AddHeader(nghttp2_rcbuf* name,
2338
2339
if (this->statistics_.first_header == 0)
2340
this->statistics_.first_header = uv_hrtime();
2341
- size_t length = GetBufferLength(name) + GetBufferLength(value) + 32;
+ size_t name_len = nghttp2_rcbuf_get_buf(name).len;
2342
+ if (name_len == 0 && !IsReverted(SECURITY_REVERT_CVE_2019_9516)) {
2343
+ return true; // Ignore headers with empty names.
2344
+ }
2345
+ size_t value_len = nghttp2_rcbuf_get_buf(value).len;
2346
+ size_t length = name_len + value_len + 32;
2347
// A header can only be added if we have not exceeded the maximum number
2348
// of headers and the session has memory available for it.
2349
if (!session_->IsAvailableSessionMemory(length) ||
@@ -2354,6 +2359,7 @@ inline bool Http2Stream::AddHeader(nghttp2_rcbuf* name,
2354
2359
nghttp2_rcbuf_incref(name);
2355
2360
nghttp2_rcbuf_incref(value);
2356
2361
current_headers_length_ += length;
2362
+ session_->IncrementCurrentSessionMemory(length);
2357
2363
return true;
2358
2364
2365
src/node_revert.h
@@ -18,6 +18,7 @@ namespace node {
18
#define SECURITY_REVERSIONS(XX) \
19
XX(CVE_2018_12116, "CVE-2018-12116", "HTTP request splitting") \
20
XX(CVE_2019_9514, "CVE-2019-9514", "HTTP/2 Reset Flood") \
21
+ XX(CVE_2019_9516, "CVE-2019-9516", "HTTP/2 0-Length Headers Leak") \
22
// XX(CVE_2016_PEND, "CVE-2016-PEND", "Vulnerability Title")
23
// TODO(addaleax): Remove all of the above before Node.js 13 as the comment
24
// at the start of the file indicates.
test/parallel/test-http2-zero-length-header.js
@@ -0,0 +1,25 @@
1
+'use strict';
2
+const common = require('../common');
3
+if (!common.hasCrypto)
4
+ common.skip('missing crypto');
5
+
6
+const assert = require('assert');
7
+const http2 = require('http2');
8
9
+const server = http2.createServer();
10
+server.on('stream', (stream, headers) => {
11
+ assert.deepStrictEqual(headers, {
12
+ ':scheme': 'http',
13
+ ':authority': `localhost:${server.address().port}`,
14
+ ':method': 'GET',
15
+ ':path': '/',
16
+ 'bar': '',
17
+ '__proto__': null
+ });
+ stream.session.destroy();
+ server.close();
+});
+server.listen(0, common.mustCall(() => {
+ const client = http2.connect(`http://localhost:${server.address().port}/`);
+ client.request({ ':path': '/', '': 'foo', 'bar': '' }).end();
25
+}));