diff options
| author | Archana Polampalli <archana.polampalli@windriver.com> | 2024-02-27 02:17:50 +0000 |
|---|---|---|
| committer | Armin Kuster <akuster808@gmail.com> | 2024-06-02 15:08:41 -0400 |
| commit | 7b468c6f83352d288d8e01f663539c93a65bf884 (patch) | |
| tree | 0b176d2584f9d4e24307f084e620ad946016f953 /meta-oe | |
| parent | 0560b848996a0feb410a8cd8ca07c60fe2f3b5bc (diff) | |
| download | meta-openembedded-7b468c6f83352d288d8e01f663539c93a65bf884.tar.gz | |
nodejs: fix CVE-2024-22019
Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Diffstat (limited to 'meta-oe')
| -rw-r--r-- | meta-oe/recipes-devtools/nodejs/nodejs/CVE-2024-22019.patch | 556 | ||||
| -rw-r--r-- | meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb | 1 |
2 files changed, 557 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2024-22019.patch b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2024-22019.patch new file mode 100644 index 0000000000..ca1c7981cc --- /dev/null +++ b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2024-22019.patch | |||
| @@ -0,0 +1,556 @@ | |||
| 1 | From 911cb33cdadab57a75f97186290ea8f3903a6171 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Paolo Insogna <paolo@cowtech.it> | ||
| 3 | Date: Tue, 9 Jan 2024 18:10:04 +0100 | ||
| 4 | Subject: [PATCH] http: add maximum chunk extension size | ||
| 5 | |||
| 6 | PR-URL: https://github.com/nodejs-private/node-private/pull/520 | ||
| 7 | Refs: https://github.com/nodejs-private/node-private/pull/518 | ||
| 8 | |||
| 9 | CVE-ID: CVE-2024-22019 | ||
| 10 | |||
| 11 | Upstream-Status: Backport [https://github.com/nodejs/node/commit/911cb33cdadab57a] | ||
| 12 | |||
| 13 | Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> | ||
| 14 | --- | ||
| 15 | deps/llhttp/CMakeLists.txt | 2 +- | ||
| 16 | deps/llhttp/include/llhttp.h | 7 +- | ||
| 17 | deps/llhttp/src/api.c | 7 + | ||
| 18 | deps/llhttp/src/llhttp.c | 122 ++++++++++++++-- | ||
| 19 | doc/api/errors.md | 12 ++ | ||
| 20 | lib/_http_server.js | 8 ++ | ||
| 21 | src/node_http_parser.cc | 20 ++- | ||
| 22 | .../test-http-chunk-extensions-limit.js | 131 ++++++++++++++++++ | ||
| 23 | tools/update-llhttp.sh | 2 +- | ||
| 24 | 9 files changed, 292 insertions(+), 19 deletions(-) | ||
| 25 | create mode 100644 test/parallel/test-http-chunk-extensions-limit.js | ||
| 26 | |||
| 27 | diff --git a/deps/llhttp/CMakeLists.txt b/deps/llhttp/CMakeLists.txt | ||
| 28 | index d038203..747564a 100644 | ||
| 29 | --- a/deps/llhttp/CMakeLists.txt | ||
| 30 | +++ b/deps/llhttp/CMakeLists.txt | ||
| 31 | @@ -1,7 +1,7 @@ | ||
| 32 | cmake_minimum_required(VERSION 3.5.1) | ||
| 33 | cmake_policy(SET CMP0069 NEW) | ||
| 34 | |||
| 35 | -project(llhttp VERSION 6.0.11) | ||
| 36 | +project(llhttp VERSION 6.1.0) | ||
| 37 | include(GNUInstallDirs) | ||
| 38 | |||
| 39 | set(CMAKE_C_STANDARD 99) | ||
| 40 | diff --git a/deps/llhttp/include/llhttp.h b/deps/llhttp/include/llhttp.h | ||
| 41 | index 2da66f1..78f27ab 100644 | ||
| 42 | --- a/deps/llhttp/include/llhttp.h | ||
| 43 | +++ b/deps/llhttp/include/llhttp.h | ||
| 44 | @@ -2,8 +2,8 @@ | ||
| 45 | #define INCLUDE_LLHTTP_H_ | ||
| 46 | |||
| 47 | #define LLHTTP_VERSION_MAJOR 6 | ||
| 48 | -#define LLHTTP_VERSION_MINOR 0 | ||
| 49 | -#define LLHTTP_VERSION_PATCH 11 | ||
| 50 | +#define LLHTTP_VERSION_MINOR 1 | ||
| 51 | +#define LLHTTP_VERSION_PATCH 0 | ||
| 52 | |||
| 53 | #ifndef LLHTTP_STRICT_MODE | ||
| 54 | # define LLHTTP_STRICT_MODE 0 | ||
| 55 | @@ -348,6 +348,9 @@ struct llhttp_settings_s { | ||
| 56 | */ | ||
| 57 | llhttp_cb on_headers_complete; | ||
| 58 | |||
| 59 | + /* Possible return values 0, -1, HPE_USER */ | ||
| 60 | + llhttp_data_cb on_chunk_parameters; | ||
| 61 | + | ||
| 62 | /* Possible return values 0, -1, HPE_USER */ | ||
| 63 | llhttp_data_cb on_body; | ||
| 64 | |||
| 65 | diff --git a/deps/llhttp/src/api.c b/deps/llhttp/src/api.c | ||
| 66 | index c4ce197..d3065b3 100644 | ||
| 67 | --- a/deps/llhttp/src/api.c | ||
| 68 | +++ b/deps/llhttp/src/api.c | ||
| 69 | @@ -355,6 +355,13 @@ int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { | ||
| 70 | } | ||
| 71 | |||
| 72 | |||
| 73 | +int llhttp__on_chunk_parameters(llhttp_t* s, const char* p, const char* endp) { | ||
| 74 | + int err; | ||
| 75 | + SPAN_CALLBACK_MAYBE(s, on_chunk_parameters, p, endp - p); | ||
| 76 | + return err; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | + | ||
| 80 | int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { | ||
| 81 | int err; | ||
| 82 | CALLBACK_MAYBE(s, on_chunk_complete); | ||
| 83 | diff --git a/deps/llhttp/src/llhttp.c b/deps/llhttp/src/llhttp.c | ||
| 84 | index 5e7c5d1..5eb19f6 100644 | ||
| 85 | --- a/deps/llhttp/src/llhttp.c | ||
| 86 | +++ b/deps/llhttp/src/llhttp.c | ||
| 87 | @@ -340,6 +340,8 @@ enum llparse_state_e { | ||
| 88 | s_n_llhttp__internal__n_invoke_is_equal_content_length, | ||
| 89 | s_n_llhttp__internal__n_chunk_size_almost_done, | ||
| 90 | s_n_llhttp__internal__n_chunk_parameters, | ||
| 91 | + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters, | ||
| 92 | + s_n_llhttp__internal__n_chunk_parameters_ows, | ||
| 93 | s_n_llhttp__internal__n_chunk_size_otherwise, | ||
| 94 | s_n_llhttp__internal__n_chunk_size, | ||
| 95 | s_n_llhttp__internal__n_chunk_size_digit, | ||
| 96 | @@ -539,6 +541,10 @@ int llhttp__on_body( | ||
| 97 | llhttp__internal_t* s, const unsigned char* p, | ||
| 98 | const unsigned char* endp); | ||
| 99 | |||
| 100 | +int llhttp__on_chunk_parameters( | ||
| 101 | + llhttp__internal_t* s, const unsigned char* p, | ||
| 102 | + const unsigned char* endp); | ||
| 103 | + | ||
| 104 | int llhttp__on_status( | ||
| 105 | llhttp__internal_t* s, const unsigned char* p, | ||
| 106 | const unsigned char* endp); | ||
| 107 | @@ -1226,8 +1232,7 @@ static llparse_state_t llhttp__internal__run( | ||
| 108 | goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 109 | } | ||
| 110 | case 2: { | ||
| 111 | - p++; | ||
| 112 | - goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 113 | + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters; | ||
| 114 | } | ||
| 115 | default: { | ||
| 116 | goto s_n_llhttp__internal__n_error_10; | ||
| 117 | @@ -1236,6 +1241,34 @@ static llparse_state_t llhttp__internal__run( | ||
| 118 | /* UNREACHABLE */; | ||
| 119 | abort(); | ||
| 120 | } | ||
| 121 | + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: | ||
| 122 | + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: { | ||
| 123 | + if (p == endp) { | ||
| 124 | + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters; | ||
| 125 | + } | ||
| 126 | + state->_span_pos0 = (void*) p; | ||
| 127 | + state->_span_cb0 = llhttp__on_chunk_parameters; | ||
| 128 | + goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 129 | + /* UNREACHABLE */; | ||
| 130 | + abort(); | ||
| 131 | + } | ||
| 132 | + case s_n_llhttp__internal__n_chunk_parameters_ows: | ||
| 133 | + s_n_llhttp__internal__n_chunk_parameters_ows: { | ||
| 134 | + if (p == endp) { | ||
| 135 | + return s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 136 | + } | ||
| 137 | + switch (*p) { | ||
| 138 | + case ' ': { | ||
| 139 | + p++; | ||
| 140 | + goto s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 141 | + } | ||
| 142 | + default: { | ||
| 143 | + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters; | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + /* UNREACHABLE */; | ||
| 147 | + abort(); | ||
| 148 | + } | ||
| 149 | case s_n_llhttp__internal__n_chunk_size_otherwise: | ||
| 150 | s_n_llhttp__internal__n_chunk_size_otherwise: { | ||
| 151 | if (p == endp) { | ||
| 152 | @@ -1246,13 +1279,9 @@ static llparse_state_t llhttp__internal__run( | ||
| 153 | p++; | ||
| 154 | goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 155 | } | ||
| 156 | - case ' ': { | ||
| 157 | - p++; | ||
| 158 | - goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 159 | - } | ||
| 160 | case ';': { | ||
| 161 | p++; | ||
| 162 | - goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 163 | + goto s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 164 | } | ||
| 165 | default: { | ||
| 166 | goto s_n_llhttp__internal__n_error_11; | ||
| 167 | @@ -6074,6 +6103,24 @@ static llparse_state_t llhttp__internal__run( | ||
| 168 | /* UNREACHABLE */; | ||
| 169 | abort(); | ||
| 170 | } | ||
| 171 | + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters: { | ||
| 172 | + const unsigned char* start; | ||
| 173 | + int err; | ||
| 174 | + | ||
| 175 | + start = state->_span_pos0; | ||
| 176 | + state->_span_pos0 = NULL; | ||
| 177 | + err = llhttp__on_chunk_parameters(state, start, p); | ||
| 178 | + if (err != 0) { | ||
| 179 | + state->error = err; | ||
| 180 | + state->error_pos = (const char*) (p + 1); | ||
| 181 | + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 182 | + return s_error; | ||
| 183 | + } | ||
| 184 | + p++; | ||
| 185 | + goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 186 | + /* UNREACHABLE */; | ||
| 187 | + abort(); | ||
| 188 | + } | ||
| 189 | s_n_llhttp__internal__n_error_10: { | ||
| 190 | state->error = 0x2; | ||
| 191 | state->reason = "Invalid character in chunk parameters"; | ||
| 192 | @@ -8441,6 +8488,8 @@ enum llparse_state_e { | ||
| 193 | s_n_llhttp__internal__n_invoke_is_equal_content_length, | ||
| 194 | s_n_llhttp__internal__n_chunk_size_almost_done, | ||
| 195 | s_n_llhttp__internal__n_chunk_parameters, | ||
| 196 | + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters, | ||
| 197 | + s_n_llhttp__internal__n_chunk_parameters_ows, | ||
| 198 | s_n_llhttp__internal__n_chunk_size_otherwise, | ||
| 199 | s_n_llhttp__internal__n_chunk_size, | ||
| 200 | s_n_llhttp__internal__n_chunk_size_digit, | ||
| 201 | @@ -8635,6 +8684,10 @@ int llhttp__on_body( | ||
| 202 | llhttp__internal_t* s, const unsigned char* p, | ||
| 203 | const unsigned char* endp); | ||
| 204 | |||
| 205 | +int llhttp__on_chunk_parameters( | ||
| 206 | + llhttp__internal_t* s, const unsigned char* p, | ||
| 207 | + const unsigned char* endp); | ||
| 208 | + | ||
| 209 | int llhttp__on_status( | ||
| 210 | llhttp__internal_t* s, const unsigned char* p, | ||
| 211 | const unsigned char* endp); | ||
| 212 | @@ -9299,8 +9352,7 @@ static llparse_state_t llhttp__internal__run( | ||
| 213 | goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 214 | } | ||
| 215 | case 2: { | ||
| 216 | - p++; | ||
| 217 | - goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 218 | + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters; | ||
| 219 | } | ||
| 220 | default: { | ||
| 221 | goto s_n_llhttp__internal__n_error_6; | ||
| 222 | @@ -9309,6 +9361,34 @@ static llparse_state_t llhttp__internal__run( | ||
| 223 | /* UNREACHABLE */; | ||
| 224 | abort(); | ||
| 225 | } | ||
| 226 | + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: | ||
| 227 | + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: { | ||
| 228 | + if (p == endp) { | ||
| 229 | + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters; | ||
| 230 | + } | ||
| 231 | + state->_span_pos0 = (void*) p; | ||
| 232 | + state->_span_cb0 = llhttp__on_chunk_parameters; | ||
| 233 | + goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 234 | + /* UNREACHABLE */; | ||
| 235 | + abort(); | ||
| 236 | + } | ||
| 237 | + case s_n_llhttp__internal__n_chunk_parameters_ows: | ||
| 238 | + s_n_llhttp__internal__n_chunk_parameters_ows: { | ||
| 239 | + if (p == endp) { | ||
| 240 | + return s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 241 | + } | ||
| 242 | + switch (*p) { | ||
| 243 | + case ' ': { | ||
| 244 | + p++; | ||
| 245 | + goto s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 246 | + } | ||
| 247 | + default: { | ||
| 248 | + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters; | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + /* UNREACHABLE */; | ||
| 252 | + abort(); | ||
| 253 | + } | ||
| 254 | case s_n_llhttp__internal__n_chunk_size_otherwise: | ||
| 255 | s_n_llhttp__internal__n_chunk_size_otherwise: { | ||
| 256 | if (p == endp) { | ||
| 257 | @@ -9319,13 +9399,9 @@ static llparse_state_t llhttp__internal__run( | ||
| 258 | p++; | ||
| 259 | goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 260 | } | ||
| 261 | - case ' ': { | ||
| 262 | - p++; | ||
| 263 | - goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 264 | - } | ||
| 265 | case ';': { | ||
| 266 | p++; | ||
| 267 | - goto s_n_llhttp__internal__n_chunk_parameters; | ||
| 268 | + goto s_n_llhttp__internal__n_chunk_parameters_ows; | ||
| 269 | } | ||
| 270 | default: { | ||
| 271 | goto s_n_llhttp__internal__n_error_7; | ||
| 272 | @@ -13951,6 +14027,24 @@ static llparse_state_t llhttp__internal__run( | ||
| 273 | /* UNREACHABLE */; | ||
| 274 | abort(); | ||
| 275 | } | ||
| 276 | + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters: { | ||
| 277 | + const unsigned char* start; | ||
| 278 | + int err; | ||
| 279 | + | ||
| 280 | + start = state->_span_pos0; | ||
| 281 | + state->_span_pos0 = NULL; | ||
| 282 | + err = llhttp__on_chunk_parameters(state, start, p); | ||
| 283 | + if (err != 0) { | ||
| 284 | + state->error = err; | ||
| 285 | + state->error_pos = (const char*) (p + 1); | ||
| 286 | + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 287 | + return s_error; | ||
| 288 | + } | ||
| 289 | + p++; | ||
| 290 | + goto s_n_llhttp__internal__n_chunk_size_almost_done; | ||
| 291 | + /* UNREACHABLE */; | ||
| 292 | + abort(); | ||
| 293 | + } | ||
| 294 | s_n_llhttp__internal__n_error_6: { | ||
| 295 | state->error = 0x2; | ||
| 296 | state->reason = "Invalid character in chunk parameters"; | ||
| 297 | diff --git a/doc/api/errors.md b/doc/api/errors.md | ||
| 298 | index dcf8744..a76bfe5 100644 | ||
| 299 | --- a/doc/api/errors.md | ||
| 300 | +++ b/doc/api/errors.md | ||
| 301 | @@ -3043,6 +3043,18 @@ malconfigured clients, if more than 8 KiB of HTTP header data is received then | ||
| 302 | HTTP parsing will abort without a request or response object being created, and | ||
| 303 | an `Error` with this code will be emitted. | ||
| 304 | |||
| 305 | +<a id="HPE_CHUNK_EXTENSIONS_OVERFLOW"></a> | ||
| 306 | + | ||
| 307 | +### `HPE_CHUNK_EXTENSIONS_OVERFLOW` | ||
| 308 | + | ||
| 309 | +<!-- YAML | ||
| 310 | +added: REPLACEME | ||
| 311 | +--> | ||
| 312 | + | ||
| 313 | +Too much data was received for a chunk extensions. In order to protect against | ||
| 314 | +malicious or malconfigured clients, if more than 16 KiB of data is received | ||
| 315 | +then an `Error` with this code will be emitted. | ||
| 316 | + | ||
| 317 | <a id="HPE_UNEXPECTED_CONTENT_LENGTH"></a> | ||
| 318 | |||
| 319 | ### `HPE_UNEXPECTED_CONTENT_LENGTH` | ||
| 320 | diff --git a/lib/_http_server.js b/lib/_http_server.js | ||
| 321 | index 4e23266..263bb52 100644 | ||
| 322 | --- a/lib/_http_server.js | ||
| 323 | +++ b/lib/_http_server.js | ||
| 324 | @@ -706,6 +706,11 @@ const requestHeaderFieldsTooLargeResponse = Buffer.from( | ||
| 325 | `HTTP/1.1 431 ${STATUS_CODES[431]}\r\n` + | ||
| 326 | 'Connection: close\r\n\r\n', 'ascii' | ||
| 327 | ); | ||
| 328 | +const requestChunkExtensionsTooLargeResponse = Buffer.from( | ||
| 329 | + `HTTP/1.1 413 ${STATUS_CODES[413]}\r\n` + | ||
| 330 | + 'Connection: close\r\n\r\n', 'ascii', | ||
| 331 | +); | ||
| 332 | + | ||
| 333 | function socketOnError(e) { | ||
| 334 | // Ignore further errors | ||
| 335 | this.removeListener('error', socketOnError); | ||
| 336 | @@ -719,6 +724,9 @@ function socketOnError(e) { | ||
| 337 | case 'HPE_HEADER_OVERFLOW': | ||
| 338 | response = requestHeaderFieldsTooLargeResponse; | ||
| 339 | break; | ||
| 340 | + case 'HPE_CHUNK_EXTENSIONS_OVERFLOW': | ||
| 341 | + response = requestChunkExtensionsTooLargeResponse; | ||
| 342 | + break; | ||
| 343 | case 'ERR_HTTP_REQUEST_TIMEOUT': | ||
| 344 | response = requestTimeoutResponse; | ||
| 345 | break; | ||
| 346 | diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc | ||
| 347 | index 74f3248..b92e848 100644 | ||
| 348 | --- a/src/node_http_parser.cc | ||
| 349 | +++ b/src/node_http_parser.cc | ||
| 350 | @@ -79,6 +79,8 @@ const uint32_t kOnExecute = 5; | ||
| 351 | const uint32_t kOnTimeout = 6; | ||
| 352 | // Any more fields than this will be flushed into JS | ||
| 353 | const size_t kMaxHeaderFieldsCount = 32; | ||
| 354 | +// Maximum size of chunk extensions | ||
| 355 | +const size_t kMaxChunkExtensionsSize = 16384; | ||
| 356 | |||
| 357 | const uint32_t kLenientNone = 0; | ||
| 358 | const uint32_t kLenientHeaders = 1 << 0; | ||
| 359 | @@ -206,6 +208,7 @@ class Parser : public AsyncWrap, public StreamListener { | ||
| 360 | |||
| 361 | int on_message_begin() { | ||
| 362 | num_fields_ = num_values_ = 0; | ||
| 363 | + chunk_extensions_nread_ = 0; | ||
| 364 | url_.Reset(); | ||
| 365 | status_message_.Reset(); | ||
| 366 | header_parsing_start_time_ = uv_hrtime(); | ||
| 367 | @@ -443,9 +446,22 @@ class Parser : public AsyncWrap, public StreamListener { | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | - // Reset nread for the next chunk | ||
| 372 | + int on_chunk_extension(const char* at, size_t length) { | ||
| 373 | + chunk_extensions_nread_ += length; | ||
| 374 | + | ||
| 375 | + if (chunk_extensions_nread_ > kMaxChunkExtensionsSize) { | ||
| 376 | + llhttp_set_error_reason(&parser_, | ||
| 377 | + "HPE_CHUNK_EXTENSIONS_OVERFLOW:Chunk extensions overflow"); | ||
| 378 | + return HPE_USER; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + return 0; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + // Reset nread for the next chunk and also reset the extensions counter | ||
| 385 | int on_chunk_header() { | ||
| 386 | header_nread_ = 0; | ||
| 387 | + chunk_extensions_nread_ = 0; | ||
| 388 | return 0; | ||
| 389 | } | ||
| 390 | |||
| 391 | @@ -887,6 +903,7 @@ class Parser : public AsyncWrap, public StreamListener { | ||
| 392 | const char* current_buffer_data_; | ||
| 393 | bool pending_pause_ = false; | ||
| 394 | uint64_t header_nread_ = 0; | ||
| 395 | + uint64_t chunk_extensions_nread_ = 0; | ||
| 396 | uint64_t max_http_header_size_; | ||
| 397 | uint64_t headers_timeout_; | ||
| 398 | uint64_t header_parsing_start_time_ = 0; | ||
| 399 | @@ -921,6 +938,7 @@ const llhttp_settings_t Parser::settings = { | ||
| 400 | Proxy<DataCall, &Parser::on_header_field>::Raw, | ||
| 401 | Proxy<DataCall, &Parser::on_header_value>::Raw, | ||
| 402 | Proxy<Call, &Parser::on_headers_complete>::Raw, | ||
| 403 | + Proxy<DataCall, &Parser::on_chunk_extension>::Raw, | ||
| 404 | Proxy<DataCall, &Parser::on_body>::Raw, | ||
| 405 | Proxy<Call, &Parser::on_message_complete>::Raw, | ||
| 406 | Proxy<Call, &Parser::on_chunk_header>::Raw, | ||
| 407 | diff --git a/test/parallel/test-http-chunk-extensions-limit.js b/test/parallel/test-http-chunk-extensions-limit.js | ||
| 408 | new file mode 100644 | ||
| 409 | index 0000000..6868b3d | ||
| 410 | --- /dev/null | ||
| 411 | +++ b/test/parallel/test-http-chunk-extensions-limit.js | ||
| 412 | @@ -0,0 +1,131 @@ | ||
| 413 | +'use strict'; | ||
| 414 | + | ||
| 415 | +const common = require('../common'); | ||
| 416 | +const http = require('http'); | ||
| 417 | +const net = require('net'); | ||
| 418 | +const assert = require('assert'); | ||
| 419 | + | ||
| 420 | +// Verify that chunk extensions are limited in size when sent all together. | ||
| 421 | +{ | ||
| 422 | + const server = http.createServer((req, res) => { | ||
| 423 | + req.on('end', () => { | ||
| 424 | + res.writeHead(200, { 'Content-Type': 'text/plain' }); | ||
| 425 | + res.end('bye'); | ||
| 426 | + }); | ||
| 427 | + | ||
| 428 | + req.resume(); | ||
| 429 | + }); | ||
| 430 | + | ||
| 431 | + server.listen(0, () => { | ||
| 432 | + const sock = net.connect(server.address().port); | ||
| 433 | + let data = ''; | ||
| 434 | + | ||
| 435 | + sock.on('data', (chunk) => data += chunk.toString('utf-8')); | ||
| 436 | + | ||
| 437 | + sock.on('end', common.mustCall(function() { | ||
| 438 | + assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n'); | ||
| 439 | + server.close(); | ||
| 440 | + })); | ||
| 441 | + | ||
| 442 | + sock.end('' + | ||
| 443 | + 'GET / HTTP/1.1\r\n' + | ||
| 444 | + 'Host: localhost:8080\r\n' + | ||
| 445 | + 'Transfer-Encoding: chunked\r\n\r\n' + | ||
| 446 | + '2;' + 'A'.repeat(20000) + '=bar\r\nAA\r\n' + | ||
| 447 | + '0\r\n\r\n' | ||
| 448 | + ); | ||
| 449 | + }); | ||
| 450 | +} | ||
| 451 | + | ||
| 452 | +// Verify that chunk extensions are limited in size when sent in intervals. | ||
| 453 | +{ | ||
| 454 | + const server = http.createServer((req, res) => { | ||
| 455 | + req.on('end', () => { | ||
| 456 | + res.writeHead(200, { 'Content-Type': 'text/plain' }); | ||
| 457 | + res.end('bye'); | ||
| 458 | + }); | ||
| 459 | + | ||
| 460 | + req.resume(); | ||
| 461 | + }); | ||
| 462 | + | ||
| 463 | + server.listen(0, () => { | ||
| 464 | + const sock = net.connect(server.address().port); | ||
| 465 | + let remaining = 20000; | ||
| 466 | + let data = ''; | ||
| 467 | + | ||
| 468 | + const interval = setInterval( | ||
| 469 | + () => { | ||
| 470 | + if (remaining > 0) { | ||
| 471 | + sock.write('A'.repeat(1000)); | ||
| 472 | + } else { | ||
| 473 | + sock.write('=bar\r\nAA\r\n0\r\n\r\n'); | ||
| 474 | + clearInterval(interval); | ||
| 475 | + } | ||
| 476 | + | ||
| 477 | + remaining -= 1000; | ||
| 478 | + }, | ||
| 479 | + common.platformTimeout(20), | ||
| 480 | + ).unref(); | ||
| 481 | + | ||
| 482 | + sock.on('data', (chunk) => data += chunk.toString('utf-8')); | ||
| 483 | + | ||
| 484 | + sock.on('end', common.mustCall(function() { | ||
| 485 | + assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n'); | ||
| 486 | + server.close(); | ||
| 487 | + })); | ||
| 488 | + | ||
| 489 | + sock.write('' + | ||
| 490 | + 'GET / HTTP/1.1\r\n' + | ||
| 491 | + 'Host: localhost:8080\r\n' + | ||
| 492 | + 'Transfer-Encoding: chunked\r\n\r\n' + | ||
| 493 | + '2;' | ||
| 494 | + ); | ||
| 495 | + }); | ||
| 496 | +} | ||
| 497 | + | ||
| 498 | +// Verify the chunk extensions is correctly reset after a chunk | ||
| 499 | +{ | ||
| 500 | + const server = http.createServer((req, res) => { | ||
| 501 | + req.on('end', () => { | ||
| 502 | + res.writeHead(200, { 'content-type': 'text/plain', 'connection': 'close', 'date': 'now' }); | ||
| 503 | + res.end('bye'); | ||
| 504 | + }); | ||
| 505 | + | ||
| 506 | + req.resume(); | ||
| 507 | + }); | ||
| 508 | + | ||
| 509 | + server.listen(0, () => { | ||
| 510 | + const sock = net.connect(server.address().port); | ||
| 511 | + let data = ''; | ||
| 512 | + | ||
| 513 | + sock.on('data', (chunk) => data += chunk.toString('utf-8')); | ||
| 514 | + | ||
| 515 | + sock.on('end', common.mustCall(function() { | ||
| 516 | + assert.strictEqual( | ||
| 517 | + data, | ||
| 518 | + 'HTTP/1.1 200 OK\r\n' + | ||
| 519 | + 'content-type: text/plain\r\n' + | ||
| 520 | + 'connection: close\r\n' + | ||
| 521 | + 'date: now\r\n' + | ||
| 522 | + 'Transfer-Encoding: chunked\r\n' + | ||
| 523 | + '\r\n' + | ||
| 524 | + '3\r\n' + | ||
| 525 | + 'bye\r\n' + | ||
| 526 | + '0\r\n' + | ||
| 527 | + '\r\n', | ||
| 528 | + ); | ||
| 529 | + | ||
| 530 | + server.close(); | ||
| 531 | + })); | ||
| 532 | + | ||
| 533 | + sock.end('' + | ||
| 534 | + 'GET / HTTP/1.1\r\n' + | ||
| 535 | + 'Host: localhost:8080\r\n' + | ||
| 536 | + 'Transfer-Encoding: chunked\r\n\r\n' + | ||
| 537 | + '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + | ||
| 538 | + '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + | ||
| 539 | + '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + | ||
| 540 | + '0\r\n\r\n' | ||
| 541 | + ); | ||
| 542 | + }); | ||
| 543 | +} | ||
| 544 | diff --git a/tools/update-llhttp.sh b/tools/update-llhttp.sh | ||
| 545 | index 12e2f46..a95eef1 100755 | ||
| 546 | --- a/tools/update-llhttp.sh | ||
| 547 | +++ b/tools/update-llhttp.sh | ||
| 548 | @@ -59,5 +59,5 @@ echo "" | ||
| 549 | echo "Please git add llhttp, commit the new version:" | ||
| 550 | echo "" | ||
| 551 | echo "$ git add -A deps/llhttp" | ||
| 552 | -echo "$ git commit -m \"deps: update nghttp2 to $LLHTTP_VERSION\"" | ||
| 553 | +echo "$ git commit -m \"deps: update llhttp to $LLHTTP_VERSION\"" | ||
| 554 | echo "" | ||
| 555 | -- | ||
| 556 | 2.40.0 | ||
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb b/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb index da1f621ee0..f736c2929a 100644 --- a/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb +++ b/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb | |||
| @@ -27,6 +27,7 @@ SRC_URI = "http://nodejs.org/dist/v${PV}/node-v${PV}.tar.xz \ | |||
| 27 | file://0001-mips-Use-32bit-cast-for-operand-on-mips32.patch \ | 27 | file://0001-mips-Use-32bit-cast-for-operand-on-mips32.patch \ |
| 28 | file://0001-Nodejs-Fixed-pipes-DeprecationWarning.patch \ | 28 | file://0001-Nodejs-Fixed-pipes-DeprecationWarning.patch \ |
| 29 | file://CVE-2022-25883.patch \ | 29 | file://CVE-2022-25883.patch \ |
| 30 | file://CVE-2024-22019.patch \ | ||
| 30 | " | 31 | " |
| 31 | SRC_URI:append:class-target = " \ | 32 | SRC_URI:append:class-target = " \ |
| 32 | file://0001-Using-native-binaries.patch \ | 33 | file://0001-Using-native-binaries.patch \ |
