This commit is contained in:
liudabo 2021-03-15 16:42:40 +08:00
parent 6c40c39f42
commit 72d9b6a521
3 changed files with 263 additions and 1 deletions

219
CVE-2021-22883.patch Normal file
View File

@ -0,0 +1,219 @@
From 922ada77132c1b0b69c9a146822d762b2f9b912b Mon Sep 17 00:00:00 2001
From: Daniel Bevenius <daniel.bevenius@gmail.com>
Date: Fri, 22 Jan 2021 12:34:21 +0100
Subject: [PATCH] http2: add unknownProtocol timeout
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This commit add a configuration options named unknownProtocolTimeout
which can be specified to set a value for the timeout in milliseconds
that a server should wait when an unknowProtocol is sent to it. When
this happens a timer will be started and the if the socket has not been
destroyed during that time the timer callback will destoy it.
Refs: https://hackerone.com/reports/1043360
CVE-ID: CVE-2021-22883
PR-URL: https://github.com/nodejs/node/pull/246
Backport-PR-URL: https://github.com/nodejs/node/pull/250
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reference: https://github.com/nodejs/node/commit/922ada77132c1b0b69c9a146822d762b2f9b912b
---
doc/api/http2.md | 25 +++++++++++++-
lib/internal/http2/core.js | 31 ++++++++++++++---
.../test-http2-server-unknown-protocol.js | 33 +++++++++++++++++++
3 files changed, 84 insertions(+), 5 deletions(-)
create mode 100644 test/parallel/test-http2-server-unknown-protocol.js
diff --git a/doc/api/http2.md b/doc/api/http2.md
index 40a107f..d57a560 100644
--- a/doc/api/http2.md
+++ b/doc/api/http2.md
@@ -1908,7 +1908,9 @@ added: v8.4.0
The `'unknownProtocol'` event is emitted when a connecting client fails to
negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler
receives the socket for handling. If no listener is registered for this event,
-the connection is terminated. See the [Compatibility API][].
+the connection is terminated. A timeout may be specified using the
+`'unknownProtocolTimeout'` option passed to [`http2.createSecureServer()`][].
+See the [Compatibility API][].
#### `server.close([callback])`
<!-- YAML
@@ -1948,6 +1950,9 @@ error will be thrown.
<!-- YAML
added: v8.4.0
changes:
+ - version: REPLACEME
+ pr-url: https://github.com/nodejs-private/node-private/pull/250
+ description: Added `unknownProtocolTimeout` option with a default of 10000.
- version:
- v12.18.0
pr-url: https://github.com/nodejs-private/node-private/pull/206
@@ -2050,6 +2055,10 @@ changes:
`Http2ServerResponse` class to use.
Useful for extending the original `Http2ServerResponse`.
**Default:** `Http2ServerResponse`.
+ * `unknownProtocolTimeout` {number} Specifies a timeout in milliseconds that
+ a server should wait when an [`'unknownProtocol'`][] is emitted. If the
+ socket has not been destroyed by that time the server will destroy it.
+ **Default:** `10000`.
* ...: Any [`net.createServer()`][] option can be provided.
* `onRequestHandler` {Function} See [Compatibility API][]
* Returns: {Http2Server}
@@ -2086,6 +2095,9 @@ server.listen(80);
<!-- YAML
added: v8.4.0
changes:
+ - version: REPLACEME
+ pr-url: https://github.com/nodejs-private/node-private/pull/250
+ description: Added `unknownProtocolTimeout` option with a default of 10000.
- version:
- v12.18.0
pr-url: https://github.com/nodejs-private/node-private/pull/206
@@ -2178,6 +2190,10 @@ changes:
servers, the identity options (`pfx` or `key`/`cert`) are usually required.
* `origins` {string[]} An array of origin strings to send within an `ORIGIN`
frame immediately following creation of a new server `Http2Session`.
+ * `unknownProtocolTimeout` {number} Specifies a timeout in milliseconds that
+ a server should wait when an [`'unknownProtocol'`][] event is emitted. If
+ the socket has not been destroyed by that time the server will destroy it.
+ **Default:** `10000`.
* `onRequestHandler` {Function} See [Compatibility API][]
* Returns: {Http2SecureServer}
@@ -2211,6 +2227,9 @@ server.listen(80);
<!-- YAML
added: v8.4.0
changes:
+ - version: REPLACEME
+ pr-url: https://github.com/nodejs-private/node-private/pull/250
+ description: Added `unknownProtocolTimeout` option with a default of 10000.
- version:
- v12.18.0
pr-url: https://github.com/nodejs-private/node-private/pull/206
@@ -2294,6 +2313,10 @@ changes:
instance passed to `connect` and the `options` object, and returns any
[`Duplex`][] stream that is to be used as the connection for this session.
* ...: Any [`net.connect()`][] or [`tls.connect()`][] options can be provided.
+ * `unknownProtocolTimeout` {number} Specifies a timeout in milliseconds that
+ a server should wait when an [`'unknownProtocol'`][] event is emitted. If
+ the socket has not been destroyed by that time the server will destroy it.
+ **Default:** `10000`.
* `listener` {Function} Will be registered as a one-time listener of the
[`'connect'`][] event.
* Returns: {ClientHttp2Session}
diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js
index 2116bc8..e9a63fe 100644
--- a/lib/internal/http2/core.js
+++ b/lib/internal/http2/core.js
@@ -33,7 +33,7 @@ const net = require('net');
const { Duplex } = require('stream');
const tls = require('tls');
const { URL } = require('url');
-const { setImmediate } = require('timers');
+const { setImmediate, setTimeout, clearTimeout } = require('timers');
const { kIncomingMessage } = require('_http_common');
const { kServerResponse } = require('_http_server');
@@ -2721,14 +2721,14 @@ function handleHeaderContinue(headers) {
this.emit('continue');
}
-const setTimeout = {
+const setTimeoutValue = {
configurable: true,
enumerable: true,
writable: true,
value: setStreamTimeout
};
-ObjectDefineProperty(Http2Stream.prototype, 'setTimeout', setTimeout);
-ObjectDefineProperty(Http2Session.prototype, 'setTimeout', setTimeout);
+ObjectDefineProperty(Http2Stream.prototype, 'setTimeout', setTimeoutValue);
+ObjectDefineProperty(Http2Session.prototype, 'setTimeout', setTimeoutValue);
// When the socket emits an error, destroy the associated Http2Session and
@@ -2788,6 +2788,22 @@ function connectionListener(socket) {
debug('Unknown protocol from %s:%s',
socket.remoteAddress, socket.remotePort);
if (!this.emit('unknownProtocol', socket)) {
+ debug('Unknown protocol timeout: %s', options.unknownProtocolTimeout);
+ // Install a timeout if the socket was not successfully closed, then
+ // destroy the socket to ensure that the underlying resources are
+ // released.
+ const timer = setTimeout(() => {
+ if (!socket.destroyed) {
+ debug('UnknownProtocol socket timeout, destroy socket');
+ socket.destroy();
+ }
+ }, options.unknownProtocolTimeout);
+ // Un-reference the timer to avoid blocking of application shutdown and
+ // clear the timeout if the socket was successfully closed.
+ timer.unref();
+
+ socket.once('close', () => clearTimeout(timer));
+
// We don't know what to do, so let's just tell the other side what's
// going on in a format that they *might* understand.
socket.end('HTTP/1.0 403 Forbidden\r\n' +
@@ -2836,6 +2852,13 @@ function initializeOptions(options) {
);
}
+ if (options.unknownProtocolTimeout !== undefined)
+ validateUint32(options.unknownProtocolTimeout, 'unknownProtocolTimeout');
+ else
+ // TODO(danbev): is this a good default value?
+ options.unknownProtocolTimeout = 10000;
+
+
// Used only with allowHTTP1
options.Http1IncomingMessage = options.Http1IncomingMessage ||
http.IncomingMessage;
diff --git a/test/parallel/test-http2-server-unknown-protocol.js b/test/parallel/test-http2-server-unknown-protocol.js
new file mode 100644
index 0000000..639bbe4
--- /dev/null
+++ b/test/parallel/test-http2-server-unknown-protocol.js
@@ -0,0 +1,33 @@
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+
+// This test verifies that when a server receives an unknownProtocol it will
+// not leave the socket open if the client does not close it.
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const h2 = require('http2');
+const tls = require('tls');
+
+const server = h2.createSecureServer({
+ key: fixtures.readKey('rsa_private.pem'),
+ cert: fixtures.readKey('rsa_cert.crt'),
+ unknownProtocolTimeout: 500,
+ allowHalfOpen: true
+});
+
+server.on('connection', (socket) => {
+ socket.on('close', common.mustCall(() => {
+ server.close();
+ }));
+});
+
+server.listen(0, function() {
+ tls.connect({
+ port: server.address().port,
+ rejectUnauthorized: false,
+ ALPNProtocols: ['bogus']
+ });
+});
--
2.23.0

38
CVE-2021-22884.patch Normal file
View File

@ -0,0 +1,38 @@
From 1564752d553f582c8048ee45614f870ee2a446c9 Mon Sep 17 00:00:00 2001
From: Matteo Collina <hello@matteocollina.com>
Date: Thu, 14 Jan 2021 16:04:44 +0100
Subject: [PATCH] src: drop localhost6 as allowed host for inspector
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
CVE-ID: CVE-2021-22884
Refs: https://hackerone.com/bugs?report_id=1069487
PR-URL: https://github.com/nodejs/node/pull/244
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Reviewed-By: Mary Marchini <oss@mmarchini.me>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reference: https://github.com/nodejs/node/commit/1564752d553f582c8048ee45614f870ee2a446c9
---
src/inspector_socket.cc | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc
index a701928..3814565 100644
--- a/src/inspector_socket.cc
+++ b/src/inspector_socket.cc
@@ -584,8 +584,7 @@ class HttpHandler : public ProtocolHandler {
bool IsAllowedHost(const std::string& host_with_port) const {
std::string host = TrimPort(host_with_port);
return host.empty() || IsIPAddress(host)
- || node::StringEqualNoCase(host.data(), "localhost")
- || node::StringEqualNoCase(host.data(), "localhost6");
+ || node::StringEqualNoCase(host.data(), "localhost");
}
bool parsing_value_;
--
2.23.0

View File

@ -1,5 +1,5 @@
%bcond_with bootstrap %bcond_with bootstrap
%global baserelease 3 %global baserelease 4
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}} %{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
%global nodejs_epoch 1 %global nodejs_epoch 1
%global nodejs_major 12 %global nodejs_major 12
@ -88,6 +88,8 @@ Patch0004: 0004-Make-AARCH64-compile-on-64KB-physical-pages.patch
Patch0005: CVE-2020-8265.patch Patch0005: CVE-2020-8265.patch
Patch0006: CVE-2020-8287-1.patch Patch0006: CVE-2020-8287-1.patch
Patch0007: CVE-2020-8287-2.patch Patch0007: CVE-2020-8287-2.patch
Patch0008: CVE-2021-22883.patch
Patch0009: CVE-2021-22884.patch
BuildRequires: python3-devel BuildRequires: python3-devel
BuildRequires: zlib-devel BuildRequires: zlib-devel
@ -490,6 +492,9 @@ end
%{_pkgdocdir}/npm/docs %{_pkgdocdir}/npm/docs
%changelog %changelog
* Mon Mar 15 2021 xinghe <xinghe1@huawei.com> - 1:12.18.4-4
- fix CVE-2021-22883 CVE-2021-22884
* Tue Feb 09 2021 xinghe <xinghe1@huawei.com> - 1:12.18.4-3 * Tue Feb 09 2021 xinghe <xinghe1@huawei.com> - 1:12.18.4-3
- fix CVE-2020-8265 CVE-2020-8287 - fix CVE-2020-8265 CVE-2020-8287