From cb94aa0a201a37cc53fe413d74b19753a3f6d9a3 Mon Sep 17 00:00:00 2001 From: liyuxiang Date: Wed, 9 Nov 2022 17:55:30 +0800 Subject: [PATCH] CVE-2022-43548 --- CVE-2022-43548-pre-1.patch | 131 ++++++++++++++++++++++ CVE-2022-43548-pre-2.patch | 48 +++++++++ CVE-2022-43548.patch | 216 +++++++++++++++++++++++++++++++++++++ nodejs.spec | 8 +- 4 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 CVE-2022-43548-pre-1.patch create mode 100644 CVE-2022-43548-pre-2.patch create mode 100644 CVE-2022-43548.patch diff --git a/CVE-2022-43548-pre-1.patch b/CVE-2022-43548-pre-1.patch new file mode 100644 index 0000000..34ebc55 --- /dev/null +++ b/CVE-2022-43548-pre-1.patch @@ -0,0 +1,131 @@ +From 1aa5036c31ac2a9b2a2528af454675ad412f1464 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= +Date: Fri, 27 May 2022 21:18:49 +0000 +Subject: [PATCH] src: fix IPv4 validation in inspector_socket + +Co-authored-by: RafaelGSS + +Reviewed-By: Matteo Collina +Reviewed-By: RafaelGSS +PR-URL: https://github.com/nodejs-private/node-private/pull/320 +CVE-ID: CVE-2022-32212 +--- + src/inspector_socket.cc | 18 +++++-- + test/cctest/test_inspector_socket.cc | 74 ++++++++++++++++++++++++++++ + 2 files changed, 87 insertions(+), 5 deletions(-) + +diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc +index 1650c3fe01de..79b50e6a452d 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 dc8cd962141e..c740d961d9b7 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 diff --git a/CVE-2022-43548-pre-2.patch b/CVE-2022-43548-pre-2.patch new file mode 100644 index 0000000..5faf7d0 --- /dev/null +++ b/CVE-2022-43548-pre-2.patch @@ -0,0 +1,48 @@ +From b358fb27a4253c6827378a64163448c04301e19c Mon Sep 17 00:00:00 2001 +From: RafaelGSS +Date: Wed, 13 Jul 2022 13:20:22 -0300 +Subject: [PATCH] src: fix IPv4 non routable validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-By: Matteo Collina +Reviewed-By: James M Snell +Reviewed-By: Tobias Nießen +Reviewed-By: Juan José Arboleda +PR-URL: https://github.com/nodejs-private/node-private/pull/337 +CVE-ID: CVE-2022-32212, CVE-2018-7160 +--- + src/inspector_socket.cc | 1 + + test/cctest/test_inspector_socket.cc | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc +index 79b50e6a452d..ab1cdf1fa5bd 100644 +--- a/src/inspector_socket.cc ++++ b/src/inspector_socket.cc +@@ -164,6 +164,7 @@ 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; ++ if (host.front() == '0') return false; + uint_fast16_t accum = 0; + uint_fast8_t quads = 0; + bool empty = true; +diff --git a/test/cctest/test_inspector_socket.cc b/test/cctest/test_inspector_socket.cc +index c740d961d9b7..6ae92c4b27e2 100644 +--- a/test/cctest/test_inspector_socket.cc ++++ b/test/cctest/test_inspector_socket.cc +@@ -925,4 +925,12 @@ TEST_F(InspectorSocketTest, HostIpTooManyOctetsChecked) { + expect_handshake_failure(); + } + ++TEST_F(InspectorSocketTest, HostIPNonRoutable) { ++ 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(); ++} ++ + } // anonymous namespace diff --git a/CVE-2022-43548.patch b/CVE-2022-43548.patch new file mode 100644 index 0000000..76172a3 --- /dev/null +++ b/CVE-2022-43548.patch @@ -0,0 +1,216 @@ +From 2b433af094fb79cf80f086038b7f36342cb6826f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= +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 +Reviewed-by: Rafael Gonzaga +Reviewed-by: Rich Trott +--- + src/inspector_socket.cc | 78 +++++++++++++++++++++------ + test/cctest/test_inspector_socket.cc | 80 ++++++++++++++++++++++++++++ + 2 files changed, 142 insertions(+), 16 deletions(-) + +diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc +index 8cabdaec2821..a28bd557c8ab 100644 +--- a/src/inspector_socket.cc ++++ b/src/inspector_socket.cc +@@ -6,6 +6,7 @@ + + #include "openssl/sha.h" // Sha-1 hash + ++#include + #include + #include + +@@ -162,25 +163,70 @@ 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; +- if (host.front() == '0') return false; +- 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. +diff --git a/test/cctest/test_inspector_socket.cc b/test/cctest/test_inspector_socket.cc +index 6ae92c4b27e2..b351a23002c9 100644 +--- a/test/cctest/test_inspector_socket.cc ++++ b/test/cctest/test_inspector_socket.cc +@@ -925,6 +925,54 @@ TEST_F(InspectorSocketTest, HostIpTooManyOctetsChecked) { + 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, HostIPNonRoutable) { + const std::string INVALID_HOST_IP_REQUEST = "GET /json HTTP/1.1\r\n" + "Host: 0.0.0.0:9229\r\n\r\n"; +@@ -933,4 +981,36 @@ TEST_F(InspectorSocketTest, HostIPNonRoutable) { + 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 diff --git a/nodejs.spec b/nodejs.spec index 911d8ee..ad6a201 100644 --- a/nodejs.spec +++ b/nodejs.spec @@ -1,5 +1,5 @@ %bcond_with bootstrap -%global baserelease 1 +%global baserelease 2 %{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}} %global nodejs_epoch 1 %global nodejs_major 12 @@ -83,6 +83,9 @@ Patch0001: 0001-Disable-running-gyp-on-shared-deps.patch Patch0002: 0002-Install-both-binaries-and-use-libdir.patch Patch0003: 0004-Make-AARCH64-compile-on-64KB-physical-pages.patch Patch00010: 0005-use-getauxval-in-node_main_cc.patch +Patch00011: CVE-2022-43548-pre-1.patch +Patch00012: CVE-2022-43548-pre-2.patch +Patch00013: CVE-2022-43548.patch BuildRequires: python3-devel BuildRequires: zlib-devel @@ -485,6 +488,9 @@ end %{_pkgdocdir}/npm/docs %changelog +* Wed Nov 16 2022 liyuxiang 1:12.22.11-2 +- fix CVE-2022-43548 + * Mon Mar 28 2022 wangkai 1:12.22.11-1 - Update to 12.22.11, fix some cves. -- Gitee