diff options
author | Poonam Jadhav <Poonam.Jadhav@kpit.com> | 2023-03-03 18:02:13 +0530 |
---|---|---|
committer | Armin Kuster <akuster808@gmail.com> | 2023-03-18 16:16:42 -0400 |
commit | b691797f7768378a8caf36812312848add77377a (patch) | |
tree | efbd0abd66be10619d87f4514795f94a9fef5c1e | |
parent | df7fba37446e8af5f043b7d4ba0e2611578a016f (diff) | |
download | meta-openembedded-b691797f7768378a8caf36812312848add77377a.tar.gz |
nodejs: Fix CVE-2022-35255
Add patch to fix CVE-2022-35255
Link: https://sources.debian.org/src/nodejs/12.22.12~dfsg-1~deb11u3/debian/patches/cve-2022-35255.patch
Signed-off-by: Poonam Jadhav <Poonam.Jadhav@kpit.com>
Signed-off-by: Omkar Patil <omkarpatil10.93@gmail.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r-- | meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-35255.patch | 237 | ||||
-rw-r--r-- | meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb | 1 |
2 files changed, 238 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-35255.patch b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-35255.patch new file mode 100644 index 0000000000..e9c2e7404a --- /dev/null +++ b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-35255.patch | |||
@@ -0,0 +1,237 @@ | |||
1 | Origin: https://github.com/nodejs/node/commit/0c2a5723beff39d1f62daec96b5389da3d427e79 | ||
2 | Reviewed-by: Aron Xu <aron@debian.org> | ||
3 | Last-Update: 2022-01-05 | ||
4 | Comment: | ||
5 | Although WebCrypto is not implemented in 12.x series, this fix is introducing | ||
6 | enhancment to the crypto setup of V8:EntropySource(). | ||
7 | |||
8 | commit 0c2a5723beff39d1f62daec96b5389da3d427e79 | ||
9 | Author: Ben Noordhuis <info@bnoordhuis.nl> | ||
10 | Date: Sun Sep 11 10:48:34 2022 +0200 | ||
11 | |||
12 | crypto: fix weak randomness in WebCrypto keygen | ||
13 | |||
14 | Commit dae283d96f from August 2020 introduced a call to EntropySource() | ||
15 | in SecretKeyGenTraits::DoKeyGen() in src/crypto/crypto_keygen.cc. There | ||
16 | are two problems with that: | ||
17 | |||
18 | 1. It does not check the return value, it assumes EntropySource() always | ||
19 | succeeds, but it can (and sometimes will) fail. | ||
20 | |||
21 | 2. The random data returned byEntropySource() may not be | ||
22 | cryptographically strong and therefore not suitable as keying | ||
23 | material. | ||
24 | |||
25 | An example is a freshly booted system or a system without /dev/random or | ||
26 | getrandom(2). | ||
27 | |||
28 | EntropySource() calls out to openssl's RAND_poll() and RAND_bytes() in a | ||
29 | best-effort attempt to obtain random data. OpenSSL has a built-in CSPRNG | ||
30 | but that can fail to initialize, in which case it's possible either: | ||
31 | |||
32 | 1. No random data gets written to the output buffer, i.e., the output is | ||
33 | unmodified, or | ||
34 | |||
35 | 2. Weak random data is written. It's theoretically possible for the | ||
36 | output to be fully predictable because the CSPRNG starts from a | ||
37 | predictable state. | ||
38 | |||
39 | Replace EntropySource() and CheckEntropy() with new function CSPRNG() | ||
40 | that enforces checking of the return value. Abort on startup when the | ||
41 | entropy pool fails to initialize because that makes it too easy to | ||
42 | compromise the security of the process. | ||
43 | |||
44 | Refs: https://hackerone.com/bugs?report_id=1690000 | ||
45 | Refs: https://github.com/nodejs/node/pull/35093 | ||
46 | |||
47 | Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> | ||
48 | Reviewed-By: Tobias Nießen <tniessen@tnie.de> | ||
49 | PR-URL: #346 | ||
50 | Backport-PR-URL: #351 | ||
51 | CVE-ID: CVE-2022-35255 | ||
52 | |||
53 | CVE: CVE-2022-35255 | ||
54 | Upstream-Status: Backport [https://sources.debian.org/src/nodejs/12.22.12~dfsg-1~deb11u3/debian/patches/cve-2022-35255.patch] | ||
55 | Comment: No hunks refreshed | ||
56 | Signed-off-by: Poonam Jadhav <Poonam.Jadhav@kpit.com> | ||
57 | |||
58 | Index: nodejs-12.22.12~dfsg/node.gyp | ||
59 | =================================================================== | ||
60 | --- nodejs-12.22.12~dfsg.orig/node.gyp | ||
61 | +++ nodejs-12.22.12~dfsg/node.gyp | ||
62 | @@ -743,6 +743,8 @@ | ||
63 | 'openssl_default_cipher_list%': '', | ||
64 | }, | ||
65 | |||
66 | + 'cflags': ['-Werror=unused-result'], | ||
67 | + | ||
68 | 'defines': [ | ||
69 | 'NODE_ARCH="<(target_arch)"', | ||
70 | 'NODE_PLATFORM="<(OS)"', | ||
71 | Index: nodejs-12.22.12~dfsg/src/node_crypto.cc | ||
72 | =================================================================== | ||
73 | --- nodejs-12.22.12~dfsg.orig/src/node_crypto.cc | ||
74 | +++ nodejs-12.22.12~dfsg/src/node_crypto.cc | ||
75 | @@ -386,48 +386,14 @@ void ThrowCryptoError(Environment* env, | ||
76 | env->isolate()->ThrowException(exception); | ||
77 | } | ||
78 | |||
79 | +MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) { | ||
80 | + do { | ||
81 | + if (1 == RAND_status()) | ||
82 | + if (1 == RAND_bytes(static_cast<unsigned char*>(buffer), length)) | ||
83 | + return {true}; | ||
84 | + } while (1 == RAND_poll()); | ||
85 | |||
86 | -// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG. | ||
87 | -// The entropy pool starts out empty and needs to fill up before the PRNG | ||
88 | -// can be used securely. Once the pool is filled, it never dries up again; | ||
89 | -// its contents is stirred and reused when necessary. | ||
90 | -// | ||
91 | -// OpenSSL normally fills the pool automatically but not when someone starts | ||
92 | -// generating random numbers before the pool is full: in that case OpenSSL | ||
93 | -// keeps lowering the entropy estimate to thwart attackers trying to guess | ||
94 | -// the initial state of the PRNG. | ||
95 | -// | ||
96 | -// When that happens, we will have to wait until enough entropy is available. | ||
97 | -// That should normally never take longer than a few milliseconds. | ||
98 | -// | ||
99 | -// OpenSSL draws from /dev/random and /dev/urandom. While /dev/random may | ||
100 | -// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't | ||
101 | -// block under normal circumstances. | ||
102 | -// | ||
103 | -// The only time when /dev/urandom may conceivably block is right after boot, | ||
104 | -// when the whole system is still low on entropy. That's not something we can | ||
105 | -// do anything about. | ||
106 | -inline void CheckEntropy() { | ||
107 | - for (;;) { | ||
108 | - int status = RAND_status(); | ||
109 | - CHECK_GE(status, 0); // Cannot fail. | ||
110 | - if (status != 0) | ||
111 | - break; | ||
112 | - | ||
113 | - // Give up, RAND_poll() not supported. | ||
114 | - if (RAND_poll() == 0) | ||
115 | - break; | ||
116 | - } | ||
117 | -} | ||
118 | - | ||
119 | - | ||
120 | -bool EntropySource(unsigned char* buffer, size_t length) { | ||
121 | - // Ensure that OpenSSL's PRNG is properly seeded. | ||
122 | - CheckEntropy(); | ||
123 | - // RAND_bytes() can return 0 to indicate that the entropy data is not truly | ||
124 | - // random. That's okay, it's still better than V8's stock source of entropy, | ||
125 | - // which is /dev/urandom on UNIX platforms and the current time on Windows. | ||
126 | - return RAND_bytes(buffer, length) != -1; | ||
127 | + return {false}; | ||
128 | } | ||
129 | |||
130 | void SecureContext::Initialize(Environment* env, Local<Object> target) { | ||
131 | @@ -649,9 +615,9 @@ void SecureContext::Init(const FunctionC | ||
132 | // OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was | ||
133 | // exposed in the public API. To retain compatibility, install a callback | ||
134 | // which restores the old algorithm. | ||
135 | - if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 || | ||
136 | - RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 || | ||
137 | - RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) { | ||
138 | + if (CSPRNG(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)).is_err() || | ||
139 | + CSPRNG(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)).is_err() || | ||
140 | + CSPRNG(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)).is_err()) { | ||
141 | return env->ThrowError("Error generating ticket keys"); | ||
142 | } | ||
143 | SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_.get(), TicketCompatibilityCallback); | ||
144 | @@ -1643,7 +1609,7 @@ int SecureContext::TicketCompatibilityCa | ||
145 | |||
146 | if (enc) { | ||
147 | memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)); | ||
148 | - if (RAND_bytes(iv, 16) <= 0 || | ||
149 | + if (CSPRNG(iv, 16).is_err() || | ||
150 | EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, | ||
151 | sc->ticket_key_aes_, iv) <= 0 || | ||
152 | HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), | ||
153 | @@ -5867,8 +5833,7 @@ struct RandomBytesJob : public CryptoJob | ||
154 | : CryptoJob(env), rc(Nothing<int>()) {} | ||
155 | |||
156 | inline void DoThreadPoolWork() override { | ||
157 | - CheckEntropy(); // Ensure that OpenSSL's PRNG is properly seeded. | ||
158 | - rc = Just(RAND_bytes(data, size)); | ||
159 | + rc = Just(int(CSPRNG(data, size).is_ok())); | ||
160 | if (0 == rc.FromJust()) errors.Capture(); | ||
161 | } | ||
162 | |||
163 | @@ -6318,8 +6283,8 @@ class GenerateKeyPairJob : public Crypto | ||
164 | } | ||
165 | |||
166 | inline bool GenerateKey() { | ||
167 | - // Make sure that the CSPRNG is properly seeded so the results are secure. | ||
168 | - CheckEntropy(); | ||
169 | + // Make sure that the CSPRNG is properly seeded. | ||
170 | + CHECK(CSPRNG(nullptr, 0).is_ok()); | ||
171 | |||
172 | // Create the key generation context. | ||
173 | EVPKeyCtxPointer ctx = config_->Setup(); | ||
174 | Index: nodejs-12.22.12~dfsg/src/node_crypto.h | ||
175 | =================================================================== | ||
176 | --- nodejs-12.22.12~dfsg.orig/src/node_crypto.h | ||
177 | +++ nodejs-12.22.12~dfsg/src/node_crypto.h | ||
178 | @@ -840,7 +840,19 @@ class ECDH final : public BaseObject { | ||
179 | const EC_GROUP* group_; | ||
180 | }; | ||
181 | |||
182 | -bool EntropySource(unsigned char* buffer, size_t length); | ||
183 | +struct CSPRNGResult { | ||
184 | + const bool ok; | ||
185 | + MUST_USE_RESULT bool is_ok() const { return ok; } | ||
186 | + MUST_USE_RESULT bool is_err() const { return !ok; } | ||
187 | +}; | ||
188 | + | ||
189 | +// Either succeeds with exactly |length| bytes of cryptographically | ||
190 | +// strong pseudo-random data, or fails. This function may block. | ||
191 | +// Don't assume anything about the contents of |buffer| on error. | ||
192 | +// As a special case, |length == 0| can be used to check if the CSPRNG | ||
193 | +// is properly seeded without consuming entropy. | ||
194 | +MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length); | ||
195 | + | ||
196 | #ifndef OPENSSL_NO_ENGINE | ||
197 | void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
198 | #endif // !OPENSSL_NO_ENGINE | ||
199 | Index: nodejs-12.22.12~dfsg/src/inspector_io.cc | ||
200 | =================================================================== | ||
201 | --- nodejs-12.22.12~dfsg.orig/src/inspector_io.cc | ||
202 | +++ nodejs-12.22.12~dfsg/src/inspector_io.cc | ||
203 | @@ -46,8 +46,7 @@ std::string ScriptPath(uv_loop_t* loop, | ||
204 | // Used ver 4 - with numbers | ||
205 | std::string GenerateID() { | ||
206 | uint16_t buffer[8]; | ||
207 | - CHECK(crypto::EntropySource(reinterpret_cast<unsigned char*>(buffer), | ||
208 | - sizeof(buffer))); | ||
209 | + CHECK(crypto::CSPRNG(buffer, sizeof(buffer)).is_ok()); | ||
210 | |||
211 | char uuid[256]; | ||
212 | snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", | ||
213 | Index: nodejs-12.22.12~dfsg/src/node.cc | ||
214 | =================================================================== | ||
215 | --- nodejs-12.22.12~dfsg.orig/src/node.cc | ||
216 | +++ nodejs-12.22.12~dfsg/src/node.cc | ||
217 | @@ -969,9 +969,17 @@ InitializationResult InitializeOncePerPr | ||
218 | // the random source is properly initialized first. | ||
219 | OPENSSL_init(); | ||
220 | #endif // NODE_FIPS_MODE | ||
221 | - // V8 on Windows doesn't have a good source of entropy. Seed it from | ||
222 | - // OpenSSL's pool. | ||
223 | - V8::SetEntropySource(crypto::EntropySource); | ||
224 | + // Ensure CSPRNG is properly seeded. | ||
225 | + CHECK(crypto::CSPRNG(nullptr, 0).is_ok()); | ||
226 | + | ||
227 | + V8::SetEntropySource([](unsigned char* buffer, size_t length) { | ||
228 | + // V8 falls back to very weak entropy when this function fails | ||
229 | + // and /dev/urandom isn't available. That wouldn't be so bad if | ||
230 | + // the entropy was only used for Math.random() but it's also used for | ||
231 | + // hash table and address space layout randomization. Better to abort. | ||
232 | + CHECK(crypto::CSPRNG(buffer, length).is_ok()); | ||
233 | + return true; | ||
234 | + }); | ||
235 | #endif // HAVE_OPENSSL | ||
236 | |||
237 | per_process::v8_platform.Initialize( | ||
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb b/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb index 2258cb1086..df9c6010eb 100644 --- a/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb +++ b/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb | |||
@@ -23,6 +23,7 @@ SRC_URI = "http://nodejs.org/dist/v${PV}/node-v${PV}.tar.xz \ | |||
23 | file://mips-warnings.patch \ | 23 | file://mips-warnings.patch \ |
24 | file://0001-Remove-use-of-register-r7-because-llvm-now-issues-an.patch \ | 24 | file://0001-Remove-use-of-register-r7-because-llvm-now-issues-an.patch \ |
25 | file://CVE-2022-32212.patch \ | 25 | file://CVE-2022-32212.patch \ |
26 | file://CVE-2022-35255.patch \ | ||
26 | " | 27 | " |
27 | SRC_URI_append_class-target = " \ | 28 | SRC_URI_append_class-target = " \ |
28 | file://0002-Using-native-binaries.patch \ | 29 | file://0002-Using-native-binaries.patch \ |