Compare commits
10 Commits
b7d70500b8
...
d9c3644924
Author | SHA256 | Date | |
---|---|---|---|
d9c3644924 | |||
c1015aaffd | |||
9c44ecaad1 | |||
7b3a79261f | |||
e01a8ff785 | |||
11443c2973 | |||
f6e7348e9b | |||
cc718baf73 | |||
97a9329d36 | |||
ef2b06e403 |
@@ -1,40 +1,73 @@
|
||||
From b263f2585ab53f56e0e22b46cf1f8519a8af8a05 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay K <iit.akshay@gmail.com>
|
||||
Date: Mon, 26 Jul 2021 08:21:51 -0400
|
||||
Subject: [PATCH] http2: on receiving rst_stream with cancel code add it to
|
||||
pending list
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/39423
|
||||
Backport-PR-URL: https://github.com/nodejs/node/pull/39527
|
||||
Fixes: https://github.com/nodejs/node/issues/38964
|
||||
Reviewed-By: James M Snell <jasnell@gmail.com>
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
---
|
||||
src/node_http2.cc | 17 +++++++++++++++++
|
||||
src/node_http2.h | 16 ++++++++++++++++
|
||||
2 files changed, 33 insertions(+)
|
||||
|
||||
diff --git a/src/js_stream.cc b/src/js_stream.cc
|
||||
index 4054e90b2e..e3d734c015 100644
|
||||
--- a/src/js_stream.cc
|
||||
+++ b/src/js_stream.cc
|
||||
@@ -105,7 +105,7 @@ int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
|
||||
}
|
||||
|
||||
|
||||
-int JSStream::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+int JSStream::DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) {
|
||||
@@ -122,7 +122,7 @@ int JSStream::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
}
|
||||
|
||||
Local<Value> argv[] = {
|
||||
- w.get()->object(),
|
||||
+ w->object(),
|
||||
bufs_arr
|
||||
};
|
||||
|
||||
diff --git a/src/js_stream.h b/src/js_stream.h
|
||||
index bf0d15d462..6612e558ae 100644
|
||||
--- a/src/js_stream.h
|
||||
+++ b/src/js_stream.h
|
||||
@@ -22,7 +22,7 @@ class JSStream : public AsyncWrap, public StreamBase {
|
||||
int ReadStop() override;
|
||||
|
||||
int DoShutdown(ShutdownWrap* req_wrap) override;
|
||||
- int DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+ int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) override;
|
||||
diff --git a/src/node_file.h b/src/node_file.h
|
||||
index b440c143b9..cbbb8b037d 100644
|
||||
--- a/src/node_file.h
|
||||
+++ b/src/node_file.h
|
||||
@@ -287,7 +287,7 @@ class FileHandle : public AsyncWrap, public StreamBase {
|
||||
ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
|
||||
int DoShutdown(ShutdownWrap* req_wrap) override;
|
||||
|
||||
- int DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+ int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) override {
|
||||
diff --git a/src/node_http2.cc b/src/node_http2.cc
|
||||
index dec6d7dab9ee..cc21373521e4 100644
|
||||
index c81e202943..8cc1d705a9 100644
|
||||
--- a/src/node_http2.cc
|
||||
+++ b/src/node_http2.cc
|
||||
@@ -2150,6 +2150,23 @@ int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec,
|
||||
@@ -2236,6 +2236,24 @@ int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec,
|
||||
void Http2Stream::SubmitRstStream(const uint32_t code) {
|
||||
CHECK(!this->IsDestroyed());
|
||||
code_ = code;
|
||||
+
|
||||
+ // If RST_STREAM frame is received and stream is not writable
|
||||
+ // because it is busy reading data, don't try force purging it.
|
||||
+ // Instead add the stream to pending stream list and process
|
||||
+ // the pending data when it is safe to do so. This is to avoid
|
||||
+ // double free error due to unwanted behavior of nghttp2.
|
||||
+ // Ref:https://github.com/nodejs/node/issues/38964
|
||||
+ auto is_stream_cancel = [](const uint32_t code) {
|
||||
+ return code == NGHTTP2_CANCEL;
|
||||
+ };
|
||||
+
|
||||
+ // Add stream to the pending list if it is received with scope
|
||||
+ // If RST_STREAM frame is received with error code NGHTTP2_CANCEL,
|
||||
+ // add it to the pending list and don't force purge the data. It is
|
||||
+ // to avoids the double free error due to unwanted behavior of nghttp2.
|
||||
+
|
||||
+ // Add stream to the pending list only if it is received with scope
|
||||
+ // below in the stack. The pending list may not get processed
|
||||
+ // if RST_STREAM received is not in scope and added to the list
|
||||
+ // causing endpoint to hang.
|
||||
+ if (session_->is_in_scope() && IsReading()) {
|
||||
+ if (session_->is_in_scope() && is_stream_cancel(code)) {
|
||||
+ session_->AddPendingRstStream(id_);
|
||||
+ return;
|
||||
+ }
|
||||
@@ -42,11 +75,38 @@ index dec6d7dab9ee..cc21373521e4 100644
|
||||
// If possible, force a purge of any currently pending data here to make sure
|
||||
// it is sent before closing the stream. If it returns non-zero then we need
|
||||
// to wait until the current write finishes and try again to avoid nghttp2
|
||||
@@ -2315,7 +2333,7 @@ int Http2Stream::ReadStop() {
|
||||
// chunks of data have been flushed to the underlying nghttp2_session.
|
||||
// Note that this does *not* mean that the data has been flushed
|
||||
// to the socket yet.
|
||||
-int Http2Stream::DoWrite(std::unique_ptr<WriteWrap>& req_wrap,
|
||||
+int Http2Stream::DoWrite(WriteWrap* req_wrap,
|
||||
uv_buf_t* bufs,
|
||||
size_t nbufs,
|
||||
uv_stream_t* send_handle) {
|
||||
@@ -2330,7 +2348,7 @@ int Http2Stream::DoWrite(std::unique_ptr<WriteWrap>& req_wrap,
|
||||
// Store the req_wrap on the last write info in the queue, so that it is
|
||||
// only marked as finished once all buffers associated with it are finished.
|
||||
queue_.emplace(nghttp2_stream_write {
|
||||
- i == nbufs - 1 ? req_wrap.get() : nullptr,
|
||||
+ i == nbufs - 1 ? req_wrap : nullptr,
|
||||
bufs[i]
|
||||
});
|
||||
IncrementAvailableOutboundLength(bufs[i].len);
|
||||
diff --git a/src/node_http2.h b/src/node_http2.h
|
||||
index 045bdfd716da..a59de18f920a 100644
|
||||
index d1d523edcb..486a968392 100644
|
||||
--- a/src/node_http2.h
|
||||
+++ b/src/node_http2.h
|
||||
@@ -764,6 +764,22 @@ class Http2Session : public AsyncWrap,
|
||||
@@ -568,7 +568,7 @@ class Http2Stream : public AsyncWrap,
|
||||
|
||||
AsyncWrap* GetAsyncWrap() override { return this; }
|
||||
|
||||
- int DoWrite(std::unique_ptr<WriteWrap>& w, uv_buf_t* bufs, size_t count,
|
||||
+ int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
|
||||
uv_stream_t* send_handle) override;
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
@@ -756,6 +756,22 @@ class Http2Session : public AsyncWrap, public StreamListener {
|
||||
return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr;
|
||||
}
|
||||
|
||||
@@ -69,3 +129,208 @@ index 045bdfd716da..a59de18f920a 100644
|
||||
// Schedule a write if nghttp2 indicates it wants to write to the socket.
|
||||
void MaybeScheduleWrite();
|
||||
|
||||
diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h
|
||||
index dca02ac76a..027b938d30 100644
|
||||
--- a/src/stream_base-inl.h
|
||||
+++ b/src/stream_base-inl.h
|
||||
@@ -216,14 +216,14 @@ inline StreamWriteResult StreamBase::Write(
|
||||
}
|
||||
|
||||
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(GetAsyncWrap());
|
||||
- std::unique_ptr<WriteWrap> req_wrap{CreateWriteWrap(req_wrap_obj)};
|
||||
+ WriteWrap* req_wrap = CreateWriteWrap(req_wrap_obj);
|
||||
|
||||
err = DoWrite(req_wrap, bufs, count, send_handle);
|
||||
bool async = err == 0;
|
||||
|
||||
- if (!async && req_wrap != nullptr) {
|
||||
+ if (!async) {
|
||||
req_wrap->Dispose();
|
||||
- req_wrap.release();
|
||||
+ req_wrap = nullptr;
|
||||
}
|
||||
|
||||
const char* msg = Error();
|
||||
@@ -232,7 +232,7 @@ inline StreamWriteResult StreamBase::Write(
|
||||
ClearError();
|
||||
}
|
||||
|
||||
- return StreamWriteResult { async, err, req_wrap.release(), total_bytes };
|
||||
+ return StreamWriteResult { async, err, req_wrap, total_bytes };
|
||||
}
|
||||
|
||||
template <typename OtherBase>
|
||||
diff --git a/src/stream_base.h b/src/stream_base.h
|
||||
index 3e922a4ac4..65abd4dcf4 100644
|
||||
--- a/src/stream_base.h
|
||||
+++ b/src/stream_base.h
|
||||
@@ -215,11 +215,10 @@ class StreamResource {
|
||||
virtual int DoTryWrite(uv_buf_t** bufs, size_t* count);
|
||||
// Perform a write of data, and either call req_wrap->Done() when finished
|
||||
// and return 0, or return a libuv error code for synchronous failures.
|
||||
- virtual int DoWrite(
|
||||
- /* NOLINT (runtime/references) */ std::unique_ptr<WriteWrap>& w,
|
||||
- uv_buf_t* bufs,
|
||||
- size_t count,
|
||||
- uv_stream_t* send_handle) = 0;
|
||||
+ virtual int DoWrite(WriteWrap* w,
|
||||
+ uv_buf_t* bufs,
|
||||
+ size_t count,
|
||||
+ uv_stream_t* send_handle) = 0;
|
||||
|
||||
// Returns true if the stream supports the `OnStreamWantsWrite()` interface.
|
||||
virtual bool HasWantsWrite() const { return false; }
|
||||
diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc
|
||||
index bd512e3349..10444fea4a 100644
|
||||
--- a/src/stream_wrap.cc
|
||||
+++ b/src/stream_wrap.cc
|
||||
@@ -351,11 +351,11 @@ int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
|
||||
}
|
||||
|
||||
|
||||
-int LibuvStreamWrap::DoWrite(std::unique_ptr<WriteWrap>& req_wrap,
|
||||
+int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) {
|
||||
- LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap.get());
|
||||
+ LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap);
|
||||
int r;
|
||||
if (send_handle == nullptr) {
|
||||
r = w->Dispatch(uv_write, stream(), bufs, count, AfterUvWrite);
|
||||
diff --git a/src/stream_wrap.h b/src/stream_wrap.h
|
||||
index 3c00d339af..98f0ca4ac4 100644
|
||||
--- a/src/stream_wrap.h
|
||||
+++ b/src/stream_wrap.h
|
||||
@@ -51,7 +51,7 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase {
|
||||
// Resource implementation
|
||||
int DoShutdown(ShutdownWrap* req_wrap) override;
|
||||
int DoTryWrite(uv_buf_t** bufs, size_t* count) override;
|
||||
- int DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+ int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) override;
|
||||
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
|
||||
index 65ea8841b7..ce46e2163e 100644
|
||||
--- a/src/tls_wrap.cc
|
||||
+++ b/src/tls_wrap.cc
|
||||
@@ -91,7 +91,8 @@ bool TLSWrap::InvokeQueued(int status, const char* error_str) {
|
||||
return false;
|
||||
|
||||
if (current_write_ != nullptr) {
|
||||
- WriteWrap* w = current_write_.release();
|
||||
+ WriteWrap* w = current_write_;
|
||||
+ current_write_ = nullptr;
|
||||
w->Done(status, error_str);
|
||||
}
|
||||
|
||||
@@ -616,7 +617,7 @@ void TLSWrap::ClearError() {
|
||||
|
||||
|
||||
// Called by StreamBase::Write() to request async write of clear text into SSL.
|
||||
-int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+int TLSWrap::DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) {
|
||||
@@ -650,7 +651,7 @@ int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
if (BIO_pending(enc_out_) == 0) {
|
||||
Debug(this, "No pending encrypted output, writing to underlying stream");
|
||||
CHECK_NULL(current_empty_write_);
|
||||
- current_empty_write_ = w.get();
|
||||
+ current_empty_write_ = w;
|
||||
StreamWriteResult res =
|
||||
underlying_stream()->Write(bufs, count, send_handle);
|
||||
if (!res.async) {
|
||||
@@ -665,7 +666,7 @@ int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
|
||||
// Store the current write wrap
|
||||
CHECK_NULL(current_write_);
|
||||
- current_write_ = std::move(w);
|
||||
+ current_write_ = w;
|
||||
|
||||
// Write encrypted data to underlying stream and call Done().
|
||||
if (length == 0) {
|
||||
@@ -704,7 +705,7 @@ int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
// If we stopped writing because of an error, it's fatal, discard the data.
|
||||
if (!arg.IsEmpty()) {
|
||||
Debug(this, "Got SSL error (%d), returning UV_EPROTO", err);
|
||||
- current_write_.release();
|
||||
+ current_write_ = nullptr;
|
||||
return UV_EPROTO;
|
||||
}
|
||||
|
||||
@@ -717,8 +718,6 @@ int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
// Write any encrypted/handshake output that may be ready.
|
||||
EncOut();
|
||||
|
||||
- w.reset(current_write_.get());
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/tls_wrap.h b/src/tls_wrap.h
|
||||
index e2e748b859..bfcf07bbc8 100644
|
||||
--- a/src/tls_wrap.h
|
||||
+++ b/src/tls_wrap.h
|
||||
@@ -67,7 +67,7 @@ class TLSWrap : public AsyncWrap,
|
||||
ShutdownWrap* CreateShutdownWrap(
|
||||
v8::Local<v8::Object> req_wrap_object) override;
|
||||
int DoShutdown(ShutdownWrap* req_wrap) override;
|
||||
- int DoWrite(std::unique_ptr<WriteWrap>& w,
|
||||
+ int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) override;
|
||||
@@ -170,7 +170,7 @@ class TLSWrap : public AsyncWrap,
|
||||
// Waiting for ClearIn() to pass to SSL_write().
|
||||
std::vector<char> pending_cleartext_input_;
|
||||
size_t write_size_ = 0;
|
||||
- std::unique_ptr<WriteWrap> current_write_ = nullptr;
|
||||
+ WriteWrap* current_write_ = nullptr;
|
||||
WriteWrap* current_empty_write_ = nullptr;
|
||||
bool write_callback_scheduled_ = false;
|
||||
bool started_ = false;
|
||||
diff --git a/test/parallel/test-http2-cancel-while-client-reading.js b/test/parallel/test-http2-cancel-while-client-reading.js
|
||||
new file mode 100644
|
||||
index 0000000000..0605a02e11
|
||||
--- /dev/null
|
||||
+++ b/test/parallel/test-http2-cancel-while-client-reading.js
|
||||
@@ -0,0 +1,36 @@
|
||||
+'use strict';
|
||||
+const common = require('../common');
|
||||
+const fixtures = require('../common/fixtures');
|
||||
+if (!common.hasCrypto) {
|
||||
+ common.skip('missing crypto');
|
||||
+}
|
||||
+
|
||||
+const http2 = require('http2');
|
||||
+const key = fixtures.readKey('agent1-key.pem', 'binary');
|
||||
+const cert = fixtures.readKey('agent1-cert.pem', 'binary');
|
||||
+
|
||||
+const server = http2.createSecureServer({ key, cert });
|
||||
+
|
||||
+let client_stream;
|
||||
+
|
||||
+server.on('stream', common.mustCall(function(stream) {
|
||||
+ stream.resume();
|
||||
+ stream.on('data', function(chunk) {
|
||||
+ stream.write(chunk);
|
||||
+ client_stream.pause();
|
||||
+ client_stream.close(http2.constants.NGHTTP2_CANCEL);
|
||||
+ });
|
||||
+}));
|
||||
+
|
||||
+server.listen(0, function() {
|
||||
+ const client = http2.connect(`https://localhost:${server.address().port}`,
|
||||
+ { rejectUnauthorized: false }
|
||||
+ );
|
||||
+ client_stream = client.request({ ':method': 'POST' });
|
||||
+ client_stream.on('close', common.mustCall(() => {
|
||||
+ client.close();
|
||||
+ server.close();
|
||||
+ }));
|
||||
+ client_stream.resume();
|
||||
+ client_stream.write(Buffer.alloc(1024 * 1024));
|
||||
+});
|
||||
|
34
CVE-2022-25881.patch
Normal file
34
CVE-2022-25881.patch
Normal file
@@ -0,0 +1,34 @@
|
||||
Index: node-v14.21.3/deps/npm/node_modules/http-cache-semantics/node4/index.js
|
||||
===================================================================
|
||||
--- node-v14.21.3.orig/deps/npm/node_modules/http-cache-semantics/node4/index.js
|
||||
+++ node-v14.21.3/deps/npm/node_modules/http-cache-semantics/node4/index.js
|
||||
@@ -21,7 +21,7 @@ function parseCacheControl(header) {
|
||||
|
||||
// TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives),
|
||||
// the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale
|
||||
- var parts = header.trim().split(/\s*,\s*/); // TODO: lame parsing
|
||||
+ var parts = header.trim().split(/,/); // TODO: lame parsing
|
||||
for (var _iterator = parts, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
|
||||
var _ref;
|
||||
|
||||
@@ -36,11 +36,11 @@ function parseCacheControl(header) {
|
||||
|
||||
var part = _ref;
|
||||
|
||||
- var _part$split = part.split(/\s*=\s*/, 2),
|
||||
+ var _part$split = part.split(/=/, 2),
|
||||
k = _part$split[0],
|
||||
v = _part$split[1];
|
||||
|
||||
- cc[k] = v === undefined ? true : v.replace(/^"|"$/g, ''); // TODO: lame unquoting
|
||||
+ cc[k.trim()] = v === undefined ? true : v.trim().replace(/^"|"$/g, ''); // TODO: lame unquoting
|
||||
}
|
||||
|
||||
return cc;
|
||||
@@ -556,4 +556,4 @@ module.exports = function () {
|
||||
};
|
||||
|
||||
return CachePolicy;
|
||||
-}();
|
||||
\ No newline at end of file
|
||||
+}();
|
128
CVE-2022-32212.patch
Normal file
128
CVE-2022-32212.patch
Normal file
@@ -0,0 +1,128 @@
|
||||
commit 1aa5036c31ac2a9b2a2528af454675ad412f1464
|
||||
Author: Tobias Nießen <tniessen@tnie.de>
|
||||
Date: Fri May 27 21:18:49 2022 +0000
|
||||
|
||||
src: fix IPv4 validation in inspector_socket
|
||||
|
||||
Co-authored-by: RafaelGSS <rafael.nunu@hotmail.com>
|
||||
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
Reviewed-By: RafaelGSS <rafael.nunu@hotmail.com>
|
||||
PR-URL: https://github.com/nodejs-private/node-private/pull/320
|
||||
CVE-ID: CVE-2022-32212
|
||||
|
||||
diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc
|
||||
index 1650c3fe01..79b50e6a45 100644
|
||||
--- a/src/inspector_socket.cc
|
||||
+++ b/src/inspector_socket.cc
|
||||
@@ -164,14 +164,22 @@ static std::string TrimPort(const std::string& host) {
|
||||
static bool IsIPAddress(const std::string& host) {
|
||||
if (host.length() >= 4 && host.front() == '[' && host.back() == ']')
|
||||
return true;
|
||||
- int quads = 0;
|
||||
+ uint_fast16_t accum = 0;
|
||||
+ uint_fast8_t quads = 0;
|
||||
+ bool empty = true;
|
||||
+ auto endOctet = [&accum, &quads, &empty](bool final = false) {
|
||||
+ return !empty && accum <= 0xff && ++quads <= 4 && final == (quads == 4) &&
|
||||
+ (empty = true) && !(accum = 0);
|
||||
+ };
|
||||
for (char c : host) {
|
||||
- if (c == '.')
|
||||
- quads++;
|
||||
- else if (!isdigit(c))
|
||||
+ if (isdigit(c)) {
|
||||
+ if ((accum = (accum * 10) + (c - '0')) > 0xff) return false;
|
||||
+ empty = false;
|
||||
+ } else if (c != '.' || !endOctet()) {
|
||||
return false;
|
||||
+ }
|
||||
}
|
||||
- return quads == 3;
|
||||
+ return endOctet(true);
|
||||
}
|
||||
|
||||
// Constants for hybi-10 frame format.
|
||||
diff --git a/test/cctest/test_inspector_socket.cc b/test/cctest/test_inspector_socket.cc
|
||||
index dc8cd96214..c740d961d9 100644
|
||||
--- a/test/cctest/test_inspector_socket.cc
|
||||
+++ b/test/cctest/test_inspector_socket.cc
|
||||
@@ -851,4 +851,78 @@ TEST_F(InspectorSocketTest, HostCheckedForUPGRADE) {
|
||||
expect_failure_no_delegate(UPGRADE_REQUEST);
|
||||
}
|
||||
|
||||
+TEST_F(InspectorSocketTest, HostIPChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 10.0.2.555:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostNegativeIPChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 10.0.-23.255:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpOctetOutOfIntRangeChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST =
|
||||
+ "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127.0.0.4294967296:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpOctetFarOutOfIntRangeChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST =
|
||||
+ "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127.0.0.18446744073709552000:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpEmptyOctetStartChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: .0.0.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpEmptyOctetMidChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127..0.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpEmptyOctetEndChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127.0.0.:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpTooFewOctetsChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127.0.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpTooManyOctetsChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 127.0.0.0.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
} // anonymous namespace
|
24663
CVE-2022-32213.patch
Normal file
24663
CVE-2022-32213.patch
Normal file
File diff suppressed because it is too large
Load Diff
1615
CVE-2022-35256.patch
Normal file
1615
CVE-2022-35256.patch
Normal file
File diff suppressed because it is too large
Load Diff
209
CVE-2022-43548.patch
Normal file
209
CVE-2022-43548.patch
Normal file
@@ -0,0 +1,209 @@
|
||||
From 2b433af094fb79cf80f086038b7f36342cb6826f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
|
||||
Date: Sun, 25 Sep 2022 12:34:05 +0000
|
||||
Subject: [PATCH] inspector: harden IP address validation again
|
||||
|
||||
Use inet_pton() to parse IP addresses, which restricts IP addresses
|
||||
to a small number of well-defined formats. In particular, octal and
|
||||
hexadecimal number formats are not allowed, and neither are leading
|
||||
zeros. Also explicitly reject 0.0.0.0/8 and ::/128 as non-routable.
|
||||
|
||||
Refs: https://hackerone.com/reports/1710652
|
||||
CVE-ID: CVE-2022-43548
|
||||
PR-URL: https://github.com/nodejs-private/node-private/pull/354
|
||||
Reviewed-by: Michael Dawson <midawson@redhat.com>
|
||||
Reviewed-by: Rafael Gonzaga <rafael.nunu@hotmail.com>
|
||||
Reviewed-by: Rich Trott <rtrott@gmail.com>
|
||||
---
|
||||
src/inspector_socket.cc | 78 +++++++++++++++++++++------
|
||||
test/cctest/test_inspector_socket.cc | 80 ++++++++++++++++++++++++++++
|
||||
2 files changed, 142 insertions(+), 16 deletions(-)
|
||||
|
||||
Index: node-v10.24.1/src/inspector_socket.cc
|
||||
===================================================================
|
||||
--- node-v10.24.1.orig/src/inspector_socket.cc
|
||||
+++ node-v10.24.1/src/inspector_socket.cc
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "openssl/sha.h" // Sha-1 hash
|
||||
|
||||
+#include <algorithm>
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
|
||||
@@ -165,24 +166,70 @@ static std::string TrimPort(const std::s
|
||||
}
|
||||
|
||||
static bool IsIPAddress(const std::string& host) {
|
||||
- if (host.length() >= 4 && host.front() == '[' && host.back() == ']')
|
||||
- return true;
|
||||
- uint_fast16_t accum = 0;
|
||||
- uint_fast8_t quads = 0;
|
||||
- bool empty = true;
|
||||
- auto endOctet = [&accum, &quads, &empty](bool final = false) {
|
||||
- return !empty && accum <= 0xff && ++quads <= 4 && final == (quads == 4) &&
|
||||
- (empty = true) && !(accum = 0);
|
||||
- };
|
||||
- for (char c : host) {
|
||||
- if (isdigit(c)) {
|
||||
- if ((accum = (accum * 10) + (c - '0')) > 0xff) return false;
|
||||
- empty = false;
|
||||
- } else if (c != '.' || !endOctet()) {
|
||||
+ // TODO(tniessen): add CVEs to the following bullet points
|
||||
+ // To avoid DNS rebinding attacks, we are aware of the following requirements:
|
||||
+ // * the host name must be an IP address,
|
||||
+ // * the IP address must be routable, and
|
||||
+ // * the IP address must be formatted unambiguously.
|
||||
+
|
||||
+ // The logic below assumes that the string is null-terminated, so ensure that
|
||||
+ // we did not somehow end up with null characters within the string.
|
||||
+ if (host.find('\0') != std::string::npos) return false;
|
||||
+
|
||||
+ // All IPv6 addresses must be enclosed in square brackets, and anything
|
||||
+ // enclosed in square brackets must be an IPv6 address.
|
||||
+ if (host.length() >= 4 && host.front() == '[' && host.back() == ']') {
|
||||
+ // INET6_ADDRSTRLEN is the maximum length of the dual format (including the
|
||||
+ // terminating null character), which is the longest possible representation
|
||||
+ // of an IPv6 address: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
|
||||
+ if (host.length() - 2 >= INET6_ADDRSTRLEN) return false;
|
||||
+
|
||||
+ // Annoyingly, libuv's implementation of inet_pton() deviates from other
|
||||
+ // implementations of the function in that it allows '%' in IPv6 addresses.
|
||||
+ if (host.find('%') != std::string::npos) return false;
|
||||
+
|
||||
+ // Parse the IPv6 address to ensure it is syntactically valid.
|
||||
+ char ipv6_str[INET6_ADDRSTRLEN];
|
||||
+ std::copy(host.begin() + 1, host.end() - 1, ipv6_str);
|
||||
+ ipv6_str[host.length()] = '\0';
|
||||
+ unsigned char ipv6[sizeof(struct in6_addr)];
|
||||
+ if (uv_inet_pton(AF_INET6, ipv6_str, ipv6) != 0) return false;
|
||||
+
|
||||
+ // The only non-routable IPv6 address is ::/128. It should not be necessary
|
||||
+ // to explicitly reject it because it will still be enclosed in square
|
||||
+ // brackets and not even macOS should make DNS requests in that case, but
|
||||
+ // history has taught us that we cannot be careful enough.
|
||||
+ // Note that RFC 4291 defines both "IPv4-Compatible IPv6 Addresses" and
|
||||
+ // "IPv4-Mapped IPv6 Addresses", which means that there are IPv6 addresses
|
||||
+ // (other than ::/128) that represent non-routable IPv4 addresses. However,
|
||||
+ // this translation assumes that the host is interpreted as an IPv6 address
|
||||
+ // in the first place, at which point DNS rebinding should not be an issue.
|
||||
+ if (std::all_of(ipv6, ipv6 + sizeof(ipv6), [](auto b) { return b == 0; })) {
|
||||
return false;
|
||||
}
|
||||
+
|
||||
+ // It is a syntactically valid and routable IPv6 address enclosed in square
|
||||
+ // brackets. No client should be able to misinterpret this.
|
||||
+ return true;
|
||||
}
|
||||
- return endOctet(true);
|
||||
+
|
||||
+ // Anything not enclosed in square brackets must be an IPv4 address. It is
|
||||
+ // important here that inet_pton() accepts only the so-called dotted-decimal
|
||||
+ // notation, which is a strict subset of the so-called numbers-and-dots
|
||||
+ // notation that is allowed by inet_aton() and inet_addr(). This subset does
|
||||
+ // not allow hexadecimal or octal number formats.
|
||||
+ unsigned char ipv4[sizeof(struct in_addr)];
|
||||
+ if (uv_inet_pton(AF_INET, host.c_str(), ipv4) != 0) return false;
|
||||
+
|
||||
+ // The only strictly non-routable IPv4 address is 0.0.0.0, and macOS will make
|
||||
+ // DNS requests for this IP address, so we need to explicitly reject it. In
|
||||
+ // fact, we can safely reject all of 0.0.0.0/8 (see Section 3.2 of RFC 791 and
|
||||
+ // Section 3.2.1.3 of RFC 1122).
|
||||
+ // Note that inet_pton() stores the IPv4 address in network byte order.
|
||||
+ if (ipv4[0] == 0) return false;
|
||||
+
|
||||
+ // It is a routable IPv4 address in dotted-decimal notation.
|
||||
+ return true;
|
||||
}
|
||||
|
||||
// Constants for hybi-10 frame format.
|
||||
Index: node-v10.24.1/test/cctest/test_inspector_socket.cc
|
||||
===================================================================
|
||||
--- node-v10.24.1.orig/test/cctest/test_inspector_socket.cc
|
||||
+++ node-v10.24.1/test/cctest/test_inspector_socket.cc
|
||||
@@ -924,4 +924,85 @@ TEST_F(InspectorSocketTest, HostIpTooMan
|
||||
expect_handshake_failure();
|
||||
}
|
||||
|
||||
+TEST_F(InspectorSocketTest, HostIpInvalidOctalOctetStartChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 08.1.1.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpInvalidOctalOctetMidChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 1.09.1.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpInvalidOctalOctetEndChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 1.1.1.009:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpLeadingZeroStartChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 01.1.1.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpLeadingZeroMidChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 1.1.001.1:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIpLeadingZeroEndChecked) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: 1.1.1.01:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIPv6NonRoutable) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: [::]:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIPv6NonRoutableDual) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: [::0.0.0.0]:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIPv4InSquareBrackets) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: [127.0.0.1]:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
+TEST_F(InspectorSocketTest, HostIPv6InvalidAbbreviation) {
|
||||
+ const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n"
|
||||
+ "Host: [:::1]:9229\r\n\r\n";
|
||||
+ send_in_chunks(INVALID_HOST_IP_REQUEST.c_str(),
|
||||
+ INVALID_HOST_IP_REQUEST.length());
|
||||
+ expect_handshake_failure();
|
||||
+}
|
||||
+
|
||||
} // anonymous namespace
|
28
CVE-2023-23920.patch
Normal file
28
CVE-2023-23920.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
commit 97a0443f1369e65cf656a529b2f5433bfd56ad92
|
||||
Author: RafaelGSS <rafael.nunu@hotmail.com>
|
||||
Date: Wed Jan 18 17:37:37 2023 -0300
|
||||
|
||||
build: build ICU with ICU_NO_USER_DATA_OVERRIDE
|
||||
|
||||
CVE-ID: CVE-2023-23920
|
||||
Backport-PR-URL: https://github.com/nodejs-private/node-private/pull/377
|
||||
PR-URL: https://github.com/nodejs-private/node-private/pull/374
|
||||
Refs: https://hackerone.com/bugs?subject=nodejs&report_id=1625036
|
||||
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
|
||||
Reviewed-By: Richard Lau <rlau@redhat.com>
|
||||
Reviewed-By: Michael Dawson <midawson@redhat.com>
|
||||
|
||||
diff --git a/configure.py b/configure.py
|
||||
index 892e1d4202..9a75dbb76d 100755
|
||||
--- a/configure.py
|
||||
+++ b/configure.py
|
||||
@@ -1487,6 +1487,9 @@ def configure_intl(o):
|
||||
# always set icu_small, node.gyp depends on it being defined.
|
||||
o['variables']['icu_small'] = b(False)
|
||||
|
||||
+ # prevent data override
|
||||
+ o['defines'] += ['ICU_NO_USER_DATA_OVERRIDE']
|
||||
+
|
||||
with_intl = options.with_intl
|
||||
with_icu_source = options.with_icu_source
|
||||
have_icu_path = bool(options.with_icu_path)
|
466
CVE-2023-44487.patch
Normal file
466
CVE-2023-44487.patch
Normal file
@@ -0,0 +1,466 @@
|
||||
commit d19f98f619771ce0ffe4f173bc96f8e823460de4
|
||||
Author: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
|
||||
Date: Sun Oct 1 00:05:01 2023 +0900
|
||||
|
||||
Rework session management
|
||||
|
||||
index a02a534b..03f6030b 100644
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
|
||||
@@ -2674,6 +2674,24 @@ NGHTTP2_EXTERN void nghttp2_option_set_m
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
+ * This function sets the rate limit for the incoming stream reset
|
||||
+ * (RST_STREAM frame). It is server use only. It is a token-bucket
|
||||
+ * based rate limiter. |burst| specifies the number of tokens that is
|
||||
+ * initially available. The maximum number of tokens is capped to
|
||||
+ * this value. |rate| specifies the number of tokens that are
|
||||
+ * regenerated per second. An incoming RST_STREAM consumes one token.
|
||||
+ * If there is no token available, GOAWAY is sent to tear down the
|
||||
+ * connection. |burst| and |rate| default to 1000 and 33
|
||||
+ * respectively.
|
||||
+ */
|
||||
+NGHTTP2_EXTERN void
|
||||
+nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option,
|
||||
+ uint64_t burst, uint64_t rate);
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * @function
|
||||
+ *
|
||||
* This function sets the maximum number of SETTINGS entries per
|
||||
* SETTINGS frame that will be accepted. If more than those entries
|
||||
* are received, the peer is considered to be misbehaving and session
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_option.c
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/lib/nghttp2_option.c
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_option.c
|
||||
@@ -126,3 +126,10 @@ void nghttp2_option_set_max_settings(ngh
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
|
||||
option->max_settings = val;
|
||||
}
|
||||
+
|
||||
+void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option,
|
||||
+ uint64_t burst, uint64_t rate) {
|
||||
+ option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT;
|
||||
+ option->stream_reset_burst = burst;
|
||||
+ option->stream_reset_rate = rate;
|
||||
+}
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_option.h
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/lib/nghttp2_option.h
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_option.h
|
||||
@@ -68,6 +68,9 @@ typedef enum {
|
||||
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
||||
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
|
||||
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
|
||||
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
|
||||
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
|
||||
+ NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
@@ -75,6 +78,11 @@ typedef enum {
|
||||
*/
|
||||
struct nghttp2_option {
|
||||
/**
|
||||
+ * NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT
|
||||
+ */
|
||||
+ uint64_t stream_reset_burst;
|
||||
+ uint64_t stream_reset_rate;
|
||||
+ /**
|
||||
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
|
||||
*/
|
||||
size_t max_send_header_block_length;
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_ratelim.c
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_ratelim.c
|
||||
@@ -0,0 +1,75 @@
|
||||
+/*
|
||||
+ * nghttp2 - HTTP/2 C Library
|
||||
+ *
|
||||
+ * Copyright (c) 2023 nghttp2 contributors
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be
|
||||
+ * included in all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ */
|
||||
+#include "nghttp2_ratelim.h"
|
||||
+#include "nghttp2_helper.h"
|
||||
+
|
||||
+void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) {
|
||||
+ rl->val = rl->burst = burst;
|
||||
+ rl->rate = rate;
|
||||
+ rl->tstamp = 0;
|
||||
+}
|
||||
+
|
||||
+void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) {
|
||||
+ uint64_t d, gain;
|
||||
+
|
||||
+ if (tstamp == rl->tstamp) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (tstamp > rl->tstamp) {
|
||||
+ d = tstamp - rl->tstamp;
|
||||
+ } else {
|
||||
+ d = 1;
|
||||
+ }
|
||||
+
|
||||
+ rl->tstamp = tstamp;
|
||||
+
|
||||
+ if (UINT64_MAX / d < rl->rate) {
|
||||
+ rl->val = rl->burst;
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ gain = rl->rate * d;
|
||||
+
|
||||
+ if (UINT64_MAX - gain < rl->val) {
|
||||
+ rl->val = rl->burst;
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ rl->val += gain;
|
||||
+ rl->val = nghttp2_min(rl->val, rl->burst);
|
||||
+}
|
||||
+
|
||||
+int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) {
|
||||
+ if (rl->val < n) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ rl->val -= n;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_ratelim.h
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_ratelim.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*
|
||||
+ * nghttp2 - HTTP/2 C Library
|
||||
+ *
|
||||
+ * Copyright (c) 2023 nghttp2 contributors
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be
|
||||
+ * included in all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ */
|
||||
+#ifndef NGHTTP2_RATELIM_H
|
||||
+#define NGHTTP2_RATELIM_H
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif /* HAVE_CONFIG_H */
|
||||
+
|
||||
+#include <nghttp2/nghttp2.h>
|
||||
+
|
||||
+typedef struct nghttp2_ratelim {
|
||||
+ /* burst is the maximum value of val. */
|
||||
+ uint64_t burst;
|
||||
+ /* rate is the amount of value that is regenerated per 1 tstamp. */
|
||||
+ uint64_t rate;
|
||||
+ /* val is the amount of value available to drain. */
|
||||
+ uint64_t val;
|
||||
+ /* tstamp is the last timestamp in second resolution that is known
|
||||
+ to this object. */
|
||||
+ uint64_t tstamp;
|
||||
+} nghttp2_ratelim;
|
||||
+
|
||||
+/* nghttp2_ratelim_init initializes |rl| with the given parameters. */
|
||||
+void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate);
|
||||
+
|
||||
+/* nghttp2_ratelim_update updates rl->val with the current |tstamp|
|
||||
+ given in second resolution. */
|
||||
+void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp);
|
||||
+
|
||||
+/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it
|
||||
+ succeeds, or -1. */
|
||||
+int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n);
|
||||
+
|
||||
+#endif /* NGHTTP2_RATELIM_H */
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_session.c
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/lib/nghttp2_session.c
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_session.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "nghttp2_option.h"
|
||||
#include "nghttp2_http.h"
|
||||
#include "nghttp2_pq.h"
|
||||
+#include "nghttp2_time.h"
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
/*
|
||||
@@ -443,6 +444,10 @@ static int session_new(nghttp2_session *
|
||||
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||
(*session_ptr)->pending_enable_push = 1;
|
||||
|
||||
+ nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
|
||||
+ NGHTTP2_DEFAULT_STREAM_RESET_BURST,
|
||||
+ NGHTTP2_DEFAULT_STREAM_RESET_RATE);
|
||||
+
|
||||
if (server) {
|
||||
(*session_ptr)->server = 1;
|
||||
}
|
||||
@@ -527,6 +532,12 @@ static int session_new(nghttp2_session *
|
||||
option->max_settings) {
|
||||
(*session_ptr)->max_settings = option->max_settings;
|
||||
}
|
||||
+
|
||||
+ if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) {
|
||||
+ nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
|
||||
+ option->stream_reset_burst,
|
||||
+ option->stream_reset_rate);
|
||||
+ }
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
|
||||
@@ -4142,6 +4153,23 @@ static int session_process_priority_fram
|
||||
return nghttp2_session_on_priority_received(session, frame);
|
||||
}
|
||||
|
||||
+static int session_update_stream_reset_ratelim(nghttp2_session *session) {
|
||||
+ if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ nghttp2_ratelim_update(&session->stream_reset_ratelim,
|
||||
+ nghttp2_time_now_sec());
|
||||
+
|
||||
+ if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return nghttp2_session_add_goaway(session, session->last_recv_stream_id,
|
||||
+ NGHTTP2_INTERNAL_ERROR, NULL, 0,
|
||||
+ NGHTTP2_GOAWAY_AUX_NONE);
|
||||
+}
|
||||
+
|
||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame) {
|
||||
int rv;
|
||||
@@ -4171,7 +4199,8 @@ int nghttp2_session_on_rst_stream_receiv
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
- return 0;
|
||||
+
|
||||
+ return session_update_stream_reset_ratelim(session);
|
||||
}
|
||||
|
||||
static int session_process_rst_stream_frame(nghttp2_session *session) {
|
||||
@@ -6942,6 +6971,9 @@ int nghttp2_session_add_goaway(nghttp2_s
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
+
|
||||
+ session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_session.h
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/lib/nghttp2_session.h
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_session.h
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_callbacks.h"
|
||||
#include "nghttp2_mem.h"
|
||||
+#include "nghttp2_ratelim.h"
|
||||
|
||||
/* The global variable for tests where we want to disable strict
|
||||
preface handling. */
|
||||
@@ -102,6 +103,10 @@ typedef struct {
|
||||
/* The default value of maximum number of concurrent streams. */
|
||||
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
|
||||
|
||||
+/* The default values for stream reset rate limiter. */
|
||||
+#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000
|
||||
+#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33
|
||||
+
|
||||
/* Internal state when receiving incoming frame */
|
||||
typedef enum {
|
||||
/* Receiving frame header */
|
||||
@@ -176,7 +181,9 @@ typedef enum {
|
||||
/* Flag means GOAWAY was sent */
|
||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||
/* Flag means GOAWAY was received */
|
||||
- NGHTTP2_GOAWAY_RECV = 0x8
|
||||
+ NGHTTP2_GOAWAY_RECV = 0x8,
|
||||
+ /* Flag means GOAWAY has been submitted at least once */
|
||||
+ NGHTTP2_GOAWAY_SUBMITTED = 0x10
|
||||
} nghttp2_goaway_flag;
|
||||
|
||||
/* nghttp2_inflight_settings stores the SETTINGS entries which local
|
||||
@@ -227,6 +234,9 @@ struct nghttp2_session {
|
||||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||
considered as in-flight. */
|
||||
nghttp2_inflight_settings *inflight_settings_head;
|
||||
+ /* Stream reset rate limiter. If receiving excessive amount of
|
||||
+ stream resets, GOAWAY will be sent. */
|
||||
+ nghttp2_ratelim stream_reset_ratelim;
|
||||
/* The number of outgoing streams. This will be capped by
|
||||
remote_settings.max_concurrent_streams. */
|
||||
size_t num_outgoing_streams;
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_time.c
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_time.c
|
||||
@@ -0,0 +1,62 @@
|
||||
+/*
|
||||
+ * nghttp2 - HTTP/2 C Library
|
||||
+ *
|
||||
+ * Copyright (c) 2023 nghttp2 contributors
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be
|
||||
+ * included in all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ */
|
||||
+#include "nghttp2_time.h"
|
||||
+
|
||||
+#ifdef HAVE_TIME_H
|
||||
+# include <time.h>
|
||||
+#endif /* HAVE_TIME_H */
|
||||
+
|
||||
+#ifdef HAVE_SYSINFOAPI_H
|
||||
+# include <sysinfoapi.h>
|
||||
+#endif /* HAVE_SYSINFOAPI_H */
|
||||
+
|
||||
+#ifndef HAVE_GETTICKCOUNT64
|
||||
+static uint64_t time_now_sec(void) {
|
||||
+ time_t t = time(NULL);
|
||||
+
|
||||
+ if (t == -1) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return (uint64_t)t;
|
||||
+}
|
||||
+#endif /* HAVE_GETTICKCOUNT64 */
|
||||
+
|
||||
+#ifdef HAVE_CLOCK_GETTIME
|
||||
+uint64_t nghttp2_time_now_sec(void) {
|
||||
+ struct timespec tp;
|
||||
+ int rv = clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
+
|
||||
+ if (rv == -1) {
|
||||
+ return time_now_sec();
|
||||
+ }
|
||||
+
|
||||
+ return (uint64_t)tp.tv_sec;
|
||||
+}
|
||||
+#elif defined(HAVE_GETTICKCOUNT64)
|
||||
+uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; }
|
||||
+#else /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
|
||||
+uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); }
|
||||
+#endif /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
|
||||
Index: node-v12.22.12/deps/nghttp2/lib/nghttp2_time.h
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ node-v12.22.12/deps/nghttp2/lib/nghttp2_time.h
|
||||
@@ -0,0 +1,38 @@
|
||||
+/*
|
||||
+ * nghttp2 - HTTP/2 C Library
|
||||
+ *
|
||||
+ * Copyright (c) 2023 nghttp2 contributors
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be
|
||||
+ * included in all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ */
|
||||
+#ifndef NGHTTP2_TIME_H
|
||||
+#define NGHTTP2_TIME_H
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif /* HAVE_CONFIG_H */
|
||||
+
|
||||
+#include <nghttp2/nghttp2.h>
|
||||
+
|
||||
+/* nghttp2_time_now_sec returns seconds from implementation-specific
|
||||
+ timepoint. If it is unable to get seconds, it returns 0. */
|
||||
+uint64_t nghttp2_time_now_sec(void);
|
||||
+
|
||||
+#endif /* NGHTTP2_TIME_H */
|
||||
Index: node-v12.22.12/deps/nghttp2/nghttp2.gyp
|
||||
===================================================================
|
||||
--- node-v12.22.12.orig/deps/nghttp2/nghttp2.gyp
|
||||
+++ node-v12.22.12/deps/nghttp2/nghttp2.gyp
|
||||
@@ -51,6 +51,8 @@
|
||||
'lib/nghttp2_outbound_item.c',
|
||||
'lib/nghttp2_pq.c',
|
||||
'lib/nghttp2_priority_spec.c',
|
||||
+ 'lib/nghttp2_ratelim.c',
|
||||
+ 'lib/nghttp2_time.c',
|
||||
'lib/nghttp2_queue.c',
|
||||
'lib/nghttp2_rcbuf.c',
|
||||
'lib/nghttp2_session.c',
|
31
newicu_test_fixup.patch
Normal file
31
newicu_test_fixup.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
commit 3b73aa416f5903d2464d0cbed0377889a23de5cb
|
||||
Author: Michaël Zasso <targos@protonmail.com>
|
||||
Date: Tue Oct 25 16:13:17 2022 +0200
|
||||
|
||||
deps: update ICU to 72.1
|
||||
|
||||
Refs: https://github.com/unicode-org/icu/releases/tag/release-72-1
|
||||
PR-URL: https://github.com/nodejs/node/pull/45068
|
||||
Reviewed-By: Richard Lau <rlau@redhat.com>
|
||||
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
|
||||
Reviewed-By: Steven R Loomis <srloomis@us.ibm.com>
|
||||
Reviewed-By: James M Snell <jasnell@gmail.com>
|
||||
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
|
||||
|
||||
Index: node-v14.21.3/test/parallel/test-intl.js
|
||||
===================================================================
|
||||
--- node-v14.21.3.orig/test/parallel/test-intl.js
|
||||
+++ node-v14.21.3/test/parallel/test-intl.js
|
||||
@@ -97,7 +97,11 @@ if (!common.hasIntl) {
|
||||
// Test format
|
||||
{
|
||||
const localeString = date0.toLocaleString(['en'], optsGMT);
|
||||
- assert.strictEqual(localeString, '1/1/1970, 12:00:00 AM');
|
||||
+ if (Number(process.versions.cldr) >= 42) {
|
||||
+ assert.strictEqual(localeString, '1/1/1970, 12:00:00 AM');
|
||||
+ } else {
|
||||
+ assert.strictEqual(localeString, '1/1/1970, 12:00:00 AM');
|
||||
+ }
|
||||
}
|
||||
// number format
|
||||
{
|
BIN
nodejs.keyring
BIN
nodejs.keyring
Binary file not shown.
@@ -1,3 +1,49 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Oct 25 10:48:27 UTC 2023 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2023-44487.patch: nghttp2 Security Release (CVE-2023-44487, bsc#1216190)
|
||||
- nodejs.keyring: include new releaser keys
|
||||
- newicu_test_fixup.patch: workaround whitespaces funnies in
|
||||
some icu versions
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 13 14:24:48 UTC 2023 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2022-25881.patch: http-cache-semantics(npm): Don't use regex
|
||||
to trim whitespace (bsc#1208744, CVE-2022-25881)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Feb 22 11:02:22 UTC 2023 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2023-23920.patch: fixes insecure loading of ICU data
|
||||
through ICU_DATA environment variable (bsc#1208487, CVE-2023-23920)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Nov 7 09:06:39 UTC 2022 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2022-43548.patch:
|
||||
* inspector: DNS rebinding in --inspect via invalid octal IP
|
||||
(bsc#1205119, CVE-2022-43548)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Sep 29 11:59:41 UTC 2022 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2022-35256.patch: update llhttp to 2.1.6
|
||||
+ fixes CVE-2022-32213 bypass via obs-fold mechanic (bsc#1201325)
|
||||
+ fixes incorrect parsing of header fields (CVE-2022-35256, bsc#1203832)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Jul 18 15:34:12 UTC 2022 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
- CVE-2021-22930.patch: backports http2 fixes
|
||||
(bsc#1188917, bsc#1189368, CVE-2021-22930, CVE-2021-22940)
|
||||
- CVE-2022-32213.patch: backport llhttp http parser fixes
|
||||
(bsc#1201325, bsc#1201326, bsc#1201327, CVE-2022-32213,
|
||||
CVE-2022-32214, CVE-2022-32215, bsc#1191602, CVE-2021-22960,
|
||||
bsc#1191601, CVE-2021-22959)
|
||||
- CVE-2022-32212.patch: fix IPv4 validation in inspector_socket
|
||||
(bsc#1201328, CVE-2022-32212)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 20 11:00:47 UTC 2022 - Adam Majer <adam.majer@suse.de>
|
||||
|
||||
|
153
nodejs10.spec
153
nodejs10.spec
@@ -155,6 +155,13 @@ Patch50: CVE-2021-3807.patch
|
||||
Patch51: CVE-2021-44906.patch
|
||||
Patch52: CVE-2021-44907.patch
|
||||
Patch53: CVE-2022-0235.patch
|
||||
Patch55: CVE-2022-32213.patch
|
||||
Patch56: CVE-2022-32212.patch
|
||||
Patch58: CVE-2022-35256.patch
|
||||
Patch59: CVE-2022-43548.patch
|
||||
Patch60: CVE-2023-23920.patch
|
||||
Patch61: CVE-2022-25881.patch
|
||||
Patch68: CVE-2023-44487.patch
|
||||
|
||||
## Patches specific to SUSE and openSUSE
|
||||
# PATCH-FIX-OPENSUSE -- set correct path for dtrace if it is built
|
||||
@@ -179,6 +186,8 @@ Patch130: test_ssl_cert_fixups.patch
|
||||
# Use versioned binaries and paths
|
||||
Patch200: versioned.patch
|
||||
|
||||
Patch310: newicu_test_fixup.patch
|
||||
|
||||
BuildRequires: pkg-config
|
||||
BuildRequires: fdupes
|
||||
BuildRequires: procps
|
||||
@@ -213,8 +222,8 @@ BuildRequires: gcc48-c++
|
||||
# for SLE-12:Update targets
|
||||
%if 0%{?suse_version} == 1315
|
||||
%if %node_version_number >= 17
|
||||
BuildRequires: gcc10-c++
|
||||
%define forced_gcc_version 10
|
||||
BuildRequires: gcc12-c++
|
||||
%define forced_gcc_version 12
|
||||
%else
|
||||
%if %node_version_number >= 14
|
||||
BuildRequires: gcc9-c++
|
||||
@@ -230,8 +239,8 @@ BuildRequires: gcc7-c++
|
||||
|
||||
%if 0%{?suse_version} == 1500
|
||||
%if %node_version_number >= 17
|
||||
BuildRequires: gcc10-c++
|
||||
%define forced_gcc_version 10
|
||||
BuildRequires: gcc12-c++
|
||||
%define forced_gcc_version 12
|
||||
%endif
|
||||
%endif
|
||||
# compiler selection
|
||||
@@ -243,10 +252,11 @@ BuildRequires: gcc-c++
|
||||
|
||||
|
||||
# Python dependencies
|
||||
%if %node_version_number >= 16
|
||||
%if %node_version_number >= 14
|
||||
|
||||
%if 0%{?suse_version} && 0%{?suse_version} < 1500
|
||||
BuildRequires: python36
|
||||
%define forced_python_version 3.6m
|
||||
%else
|
||||
BuildRequires: python3
|
||||
%endif
|
||||
@@ -270,26 +280,23 @@ BuildRequires: user(nobody)
|
||||
BuildRequires: group(nobody)
|
||||
%endif
|
||||
|
||||
# shared openssl
|
||||
%if ! 0%{with intree_openssl}
|
||||
|
||||
BuildRequires: pkgconfig(openssl) >= %{openssl_req_ver}
|
||||
|
||||
# require patched openssl library on SLES for nodejs16
|
||||
%if 0%{?suse_version}
|
||||
%if %node_version_number >= 16 && 0%{suse_version} <= 1500 && %{pkg_vcmp openssl-1_1 < '1.1.1e' } && 0%{with openssl_RSA_get0_pss_params}
|
||||
BuildRequires: openssl-has-RSA_get0_pss_params
|
||||
Requires: openssl-has-RSA_get0_pss_params
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%if 0%{?suse_version} >= 1500
|
||||
BuildRequires: openssl >= %{openssl_req_ver}
|
||||
BuildRequires: (libopenssl1_1-hmac if libopenssl-1_1-devel)
|
||||
BuildRequires: (libopenssl3-hmac if libopenssl-3-devel)
|
||||
%else
|
||||
BuildRequires: openssl-1_1 >= %{openssl_req_ver}
|
||||
BuildRequires: libopenssl1_1-hmac
|
||||
%endif
|
||||
|
||||
BuildRequires: libopenssl1_1-hmac
|
||||
|
||||
# /suse_version
|
||||
%endif
|
||||
|
||||
@@ -298,11 +305,14 @@ BuildRequires: openssl >= %{openssl_req_ver}
|
||||
%endif
|
||||
|
||||
%else
|
||||
# bundled openssl
|
||||
%if %node_version_number <= 12 && 0%{?suse_version} == 1315 && 0%{?sle_version} < 120400
|
||||
Provides: bundled(openssl) = 1.1.1k
|
||||
%else
|
||||
BuildRequires: bundled_openssl_should_not_be_required
|
||||
%endif
|
||||
|
||||
# /bundled openssl
|
||||
%endif
|
||||
|
||||
%if ! 0%{with intree_cares}
|
||||
@@ -328,7 +338,7 @@ BuildRequires: valgrind
|
||||
%endif
|
||||
|
||||
%if %{with libalternatives}
|
||||
Requires: alts
|
||||
Suggests: alts
|
||||
%else
|
||||
Requires(postun): %{_sbindir}/update-alternatives
|
||||
%endif
|
||||
@@ -377,9 +387,13 @@ Provides: bundled(brotli) = 1.0.7
|
||||
%else
|
||||
BuildRequires: pkgconfig(libbrotlidec)
|
||||
%endif
|
||||
Provides: bundled(http-parser) = 2.9.4
|
||||
|
||||
|
||||
Provides: bundled(llhttp) = 2.1.5
|
||||
|
||||
|
||||
|
||||
# bundled url-ada parser, not ada
|
||||
|
||||
|
||||
Provides: bundled(node-acorn) = 5.7.2
|
||||
@@ -648,6 +662,7 @@ Provides: bundled(node-mime-types) = 2.1.19
|
||||
Provides: bundled(node-mimic-fn) = 1.2.0
|
||||
Provides: bundled(node-minimatch) = 3.0.4
|
||||
Provides: bundled(node-minimist) = 1.2.5
|
||||
Provides: bundled(node-minimist) = 1.2.6
|
||||
Provides: bundled(node-minipass) = 2.3.3
|
||||
Provides: bundled(node-minipass) = 2.9.0
|
||||
Provides: bundled(node-minizlib) = 1.3.3
|
||||
@@ -723,7 +738,7 @@ Provides: bundled(node-pumpify) = 1.5.1
|
||||
Provides: bundled(node-punycode) = 1.4.1
|
||||
Provides: bundled(node-punycode) = 2.1.1
|
||||
Provides: bundled(node-qrcode-terminal) = 0.12.0
|
||||
Provides: bundled(node-qs) = 6.5.2
|
||||
Provides: bundled(node-qs) = 6.5.3
|
||||
Provides: bundled(node-query-string) = 6.8.2
|
||||
Provides: bundled(node-qw) = 1.0.1
|
||||
Provides: bundled(node-rc) = 1.2.8
|
||||
@@ -868,17 +883,37 @@ echo "`grep node-v%{version}.tar.xz %{S:1} | head -n1 | cut -c1-64` %{S:0}" | s
|
||||
%setup -q -n node-%{version}
|
||||
%endif
|
||||
|
||||
%if %{node_version_number} == 16
|
||||
tar zxf %{S:12}
|
||||
%endif
|
||||
|
||||
%if %{node_version_number} <= 10
|
||||
rm -r deps/npm/*
|
||||
tar zxf %{SOURCE9} -C deps/npm --strip-components=1
|
||||
tar Jxf %{SOURCE90} -C deps/npm
|
||||
pushd deps/npm
|
||||
tar zxf %{SOURCE9} --strip-components=1
|
||||
tar Jxf %{SOURCE90}
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if %{node_version_number} >= 10
|
||||
tar Jxf %{SOURCE11}
|
||||
%endif
|
||||
|
||||
# downgrade node-gyp to last version that supports python 3.4 for SLE12
|
||||
%if 0%{?suse_version} && 0%{?suse_version} < 1500 && %{node_version_number} >= 16
|
||||
rm -r deps/npm/node_modules/node-gyp
|
||||
mkdir deps/npm/node_modules/node-gyp
|
||||
pushd deps/npm/node_modules/node-gyp
|
||||
tar Jxf %{SOURCE5}
|
||||
popd
|
||||
|
||||
%if %{node_version_number} >= 19
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%patch3 -p1
|
||||
%if %{node_version_number} <= 12 && 0%{?suse_version} < 1500
|
||||
%endif
|
||||
%patch7 -p1
|
||||
%if 0%{with valgrind_tests}
|
||||
%patch11 -p1
|
||||
@@ -894,6 +929,13 @@ tar Jxf %{SOURCE11}
|
||||
%patch51 -p1
|
||||
%patch52 -p1
|
||||
%patch53 -p1
|
||||
%patch55 -p1
|
||||
%patch56 -p1
|
||||
%patch58 -p1
|
||||
%patch59 -p1
|
||||
%patch60 -p1
|
||||
%patch61 -p1
|
||||
%patch68 -p1
|
||||
%patch101 -p1
|
||||
%patch102 -p1
|
||||
# Add check_output to configure script (not part of Python 2.6 in SLE11).
|
||||
@@ -910,7 +952,9 @@ tar Jxf %{SOURCE11}
|
||||
%endif
|
||||
%patch200 -p1
|
||||
|
||||
%if %{node_version_number} <= 14
|
||||
%patch310 -p1
|
||||
|
||||
%if %{node_version_number} == 12
|
||||
# minimist security update - patch50
|
||||
rm -r deps/npm/node_modules/mkdirp/node_modules/minimist
|
||||
rmdir ./deps/npm/node_modules/mkdirp/node_modules
|
||||
@@ -922,12 +966,6 @@ find -name \*~ -print0 -delete
|
||||
# abnormalities from patching
|
||||
find \( -name \*.js.orig -or -name \*.md.orig -or -name \*.1.orig \) -delete
|
||||
|
||||
# downgrade node-gyp to last version that supports python 3.4 for SLE12
|
||||
%if 0%{?use_version} && 0%{?suse_version} < 1500
|
||||
rm -r deps/npm/node_modules/node-gyp
|
||||
mkdir deps/npm/node_modules/node-gyp
|
||||
tar -C deps/npm/node_modules/node-gyp Jxf %{SOURCE5}
|
||||
%endif
|
||||
|
||||
|
||||
%build
|
||||
@@ -1018,7 +1056,12 @@ EOF
|
||||
%if 0%{with gdb}
|
||||
--gdb \
|
||||
%endif
|
||||
%if %{node_version_number} < 19
|
||||
--without-dtrace \
|
||||
%endif
|
||||
%if %{node_version_number} >= 16 && (0%{?suse_version} > 1550 || 0%{?sle_version} >= 150400)
|
||||
--openssl-default-cipher-list=PROFILE=SYSTEM \
|
||||
%endif
|
||||
--openssl-use-def-ca-store
|
||||
|
||||
decoupled_cmd make %{?_smp_mflags}
|
||||
@@ -1134,26 +1177,69 @@ export NODE_TEST_NO_INTERNET=1
|
||||
find test \( -name \*.out -or -name \*.js \) -exec sed -i 's,Use `node ,Use `node%{node_version_number} ,' {} \;
|
||||
%endif
|
||||
|
||||
%if %{node_version_number} >= 20
|
||||
rm test/parallel/test-strace-openat-openssl.js
|
||||
%endif
|
||||
|
||||
# Update the python3 executable name to point at forced python version
|
||||
# needed to fix build on SLE12 SP5
|
||||
%if 0%{?forced_python_version:1}
|
||||
sed -i -e "s,'python3','python%{forced_python_version}'," test/parallel/test-child-process-set-blocking.js
|
||||
test -e tools/pseudo-tty.py && sed -i -e "s,^#!/usr/bin/env python3$,#!/usr/bin/python%{forced_python_version}," tools/pseudo-tty.py ||:
|
||||
%endif
|
||||
|
||||
ln addon-rpm.gypi deps/npm/node_modules/node-gyp/addon-rpm.gypi
|
||||
# Tarball doesn't have eslint package distributed, so disable some tests
|
||||
find test -name \*-eslint-\* -print -delete
|
||||
# No documentation is generated, don't bother checking it
|
||||
rm -f test/doctool/test-make-doc.js
|
||||
# No documentation is generated, don't bother checking it, and check broken on older nodejs
|
||||
%if %{node_version_number} <= 10
|
||||
rm test/doctool/test-make-doc.js
|
||||
%endif
|
||||
# DNS lookup doesn't work in build root
|
||||
rm -f test/parallel/test-dns-cancel-reverse-lookup.js \
|
||||
test/parallel/test-dns-resolveany.js
|
||||
rm test/parallel/test-dns-cancel-reverse-lookup.js \
|
||||
test/parallel/test-dns-resolveany.js
|
||||
# multicast test fail since no socket?
|
||||
rm -f test/parallel/test-dgram-membership.js
|
||||
rm test/parallel/test-dgram-membership.js
|
||||
|
||||
%if %{node_version_number} >= 18
|
||||
# OBS broken /etc/hosts -- https://github.com/openSUSE/open-build-service/issues/13104
|
||||
rm test/parallel/test-net-socket-connect-without-cb.js test/parallel/test-tcp-wrap-listen.js
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora_version}
|
||||
# test/parallel/test-crypto-certificate.js requires OPENSSL_ENABLE_MD5_VERIFY=1
|
||||
# as SPKAC required MD5 for verification
|
||||
# https://src.fedoraproject.org/rpms/openssl/blob/rawhide/f/0006-Disable-signature-verification-with-totally-unsafe-h.patch
|
||||
export OPENSSL_ENABLE_MD5_VERIFY=1
|
||||
|
||||
# test failures
|
||||
# error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake
|
||||
# failure:ssl/record/rec_layer_s3.c:1543:SSL alert number 40
|
||||
rm -f test/parallel/test-tls-no-sslv3.js
|
||||
rm test/parallel/test-tls-no-sslv3.js
|
||||
%if %{node_version_number} >= 18
|
||||
rm -r test/addons/openssl-providers
|
||||
rm test/parallel/test-crypto-fips.js
|
||||
%endif
|
||||
|
||||
%endif
|
||||
# fedora
|
||||
|
||||
# qemu test failures
|
||||
%if %{node_version_number} >= 18 && 0%{?qemu_user_space_build}
|
||||
# sequential/test-debugger-*: timeout hit?
|
||||
rm -v test/*/test-debugger-*.js
|
||||
# parallel tests are not parallel under qemu
|
||||
rm -v test/parallel/test-*.js test/parallel/test-*.mjs
|
||||
# RuntimeError: memory access out of bounds
|
||||
rm -v test/wasi/test-*.js
|
||||
# ESM import hits assertion, timeout error?
|
||||
rm -v test/es-module/test-esm-*.js
|
||||
# AssertionError [ERR_ASSERTION]: Missing expected exception
|
||||
rm -v test/js-native-api/test_constructor/test*.js
|
||||
# Too slow for performance tests
|
||||
rm -v test/sequential/test-perf-*.js test/sequential/test-diagnostic-*.js
|
||||
%endif
|
||||
|
||||
# Run CI tests
|
||||
%if 0%{with valgrind_tests}
|
||||
# valgrind may have false positives, so do not fail on these by default
|
||||
@@ -1164,7 +1250,8 @@ make test-ci
|
||||
%files
|
||||
%defattr(-, root, root)
|
||||
%license LICENSE
|
||||
%doc AUTHORS *.md
|
||||
%doc doc/changelogs/CHANGELOG_V%{node_version_number}.md
|
||||
%doc *.md
|
||||
%doc deps/v8/tools/gdbinit
|
||||
%dir %{_libdir}/node_modules
|
||||
%dir %{_datadir}/libalternatives
|
||||
@@ -1220,9 +1307,11 @@ make test-ci
|
||||
%files devel
|
||||
%defattr(-, root, root)
|
||||
%{_includedir}/node%{node_version_number}
|
||||
%if %{node_version_number} < 19
|
||||
%dir %{_datadir}/systemtap
|
||||
%dir %{_datadir}/systemtap/tapset
|
||||
%{_datadir}/systemtap/tapset/node%{node_version_number}.stp
|
||||
%endif
|
||||
|
||||
%files docs
|
||||
%defattr(-,root,root)
|
||||
|
Reference in New Issue
Block a user