File CVE-2024-22019.patch of Package nodejs16

Index: node-v16.20.2/deps/llhttp/CMakeLists.txt
===================================================================
--- node-v16.20.2.orig/deps/llhttp/CMakeLists.txt
+++ node-v16.20.2/deps/llhttp/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.5.1)
 cmake_policy(SET CMP0069 NEW)
 
-project(llhttp VERSION 6.0.11)
+project(llhttp VERSION 6.1.0)
 include(GNUInstallDirs)
 
 set(CMAKE_C_STANDARD 99)
Index: node-v16.20.2/deps/llhttp/include/llhttp.h
===================================================================
--- node-v16.20.2.orig/deps/llhttp/include/llhttp.h
+++ node-v16.20.2/deps/llhttp/include/llhttp.h
@@ -2,8 +2,8 @@
 #define INCLUDE_LLHTTP_H_
 
 #define LLHTTP_VERSION_MAJOR 6
-#define LLHTTP_VERSION_MINOR 0
-#define LLHTTP_VERSION_PATCH 11
+#define LLHTTP_VERSION_MINOR 1
+#define LLHTTP_VERSION_PATCH 0
 
 #ifndef LLHTTP_STRICT_MODE
 # define LLHTTP_STRICT_MODE 0
@@ -349,6 +349,9 @@ struct llhttp_settings_s {
   llhttp_cb      on_headers_complete;
 
   /* Possible return values 0, -1, HPE_USER */
+  llhttp_data_cb on_chunk_parameters;
+
+  /* Possible return values 0, -1, HPE_USER */
   llhttp_data_cb on_body;
 
   /* Possible return values 0, -1, `HPE_PAUSED` */
Index: node-v16.20.2/deps/llhttp/src/api.c
===================================================================
--- node-v16.20.2.orig/deps/llhttp/src/api.c
+++ node-v16.20.2/deps/llhttp/src/api.c
@@ -355,6 +355,13 @@ int llhttp__on_chunk_header(llhttp_t* s,
 }
 
 
+int llhttp__on_chunk_parameters(llhttp_t* s, const char* p, const char* endp) {
+  int err;
+  SPAN_CALLBACK_MAYBE(s, on_chunk_parameters, p, endp - p);
+  return err;
+}
+
+
 int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {
   int err;
   CALLBACK_MAYBE(s, on_chunk_complete);
Index: node-v16.20.2/deps/llhttp/src/llhttp.c
===================================================================
--- node-v16.20.2.orig/deps/llhttp/src/llhttp.c
+++ node-v16.20.2/deps/llhttp/src/llhttp.c
@@ -340,6 +340,8 @@ enum llparse_state_e {
   s_n_llhttp__internal__n_invoke_is_equal_content_length,
   s_n_llhttp__internal__n_chunk_size_almost_done,
   s_n_llhttp__internal__n_chunk_parameters,
+  s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters,
+  s_n_llhttp__internal__n_chunk_parameters_ows,
   s_n_llhttp__internal__n_chunk_size_otherwise,
   s_n_llhttp__internal__n_chunk_size,
   s_n_llhttp__internal__n_chunk_size_digit,
@@ -539,6 +541,10 @@ int llhttp__on_body(
     llhttp__internal_t* s, const unsigned char* p,
     const unsigned char* endp);
 
+int llhttp__on_chunk_parameters(
+    llhttp__internal_t* s, const unsigned char* p,
+    const unsigned char* endp);
+
 int llhttp__on_status(
     llhttp__internal_t* s, const unsigned char* p,
     const unsigned char* endp);
@@ -1226,8 +1232,7 @@ static llparse_state_t llhttp__internal_
           goto s_n_llhttp__internal__n_chunk_parameters;
         }
         case 2: {
-          p++;
-          goto s_n_llhttp__internal__n_chunk_size_almost_done;
+          goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters;
         }
         default: {
           goto s_n_llhttp__internal__n_error_10;
@@ -1236,6 +1241,34 @@ static llparse_state_t llhttp__internal_
       /* UNREACHABLE */;
       abort();
     }
+    case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters:
+    s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: {
+      if (p == endp) {
+        return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters;
+      }
+      state->_span_pos0 = (void*) p;
+      state->_span_cb0 = llhttp__on_chunk_parameters;
+      goto s_n_llhttp__internal__n_chunk_parameters;
+      /* UNREACHABLE */;
+      abort();
+    }
+    case s_n_llhttp__internal__n_chunk_parameters_ows:
+    s_n_llhttp__internal__n_chunk_parameters_ows: {
+      if (p == endp) {
+        return s_n_llhttp__internal__n_chunk_parameters_ows;
+      }
+      switch (*p) {
+        case ' ': {
+          p++;
+          goto s_n_llhttp__internal__n_chunk_parameters_ows;
+        }
+        default: {
+          goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters;
+        }
+      }
+      /* UNREACHABLE */;
+      abort();
+    }
     case s_n_llhttp__internal__n_chunk_size_otherwise:
     s_n_llhttp__internal__n_chunk_size_otherwise: {
       if (p == endp) {
@@ -1246,13 +1279,9 @@ static llparse_state_t llhttp__internal_
           p++;
           goto s_n_llhttp__internal__n_chunk_size_almost_done;
         }
-        case ' ': {
-          p++;
-          goto s_n_llhttp__internal__n_chunk_parameters;
-        }
         case ';': {
           p++;
-          goto s_n_llhttp__internal__n_chunk_parameters;
+          goto s_n_llhttp__internal__n_chunk_parameters_ows;
         }
         default: {
           goto s_n_llhttp__internal__n_error_11;
@@ -6074,6 +6103,24 @@ static llparse_state_t llhttp__internal_
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters: {
+    const unsigned char* start;
+    int err;
+    
+    start = state->_span_pos0;
+    state->_span_pos0 = NULL;
+    err = llhttp__on_chunk_parameters(state, start, p);
+    if (err != 0) {
+      state->error = err;
+      state->error_pos = (const char*) (p + 1);
+      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done;
+      return s_error;
+    }
+    p++;
+    goto s_n_llhttp__internal__n_chunk_size_almost_done;
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_error_10: {
     state->error = 0x2;
     state->reason = "Invalid character in chunk parameters";
@@ -8441,6 +8488,8 @@ enum llparse_state_e {
   s_n_llhttp__internal__n_invoke_is_equal_content_length,
   s_n_llhttp__internal__n_chunk_size_almost_done,
   s_n_llhttp__internal__n_chunk_parameters,
+  s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters,
+  s_n_llhttp__internal__n_chunk_parameters_ows,
   s_n_llhttp__internal__n_chunk_size_otherwise,
   s_n_llhttp__internal__n_chunk_size,
   s_n_llhttp__internal__n_chunk_size_digit,
@@ -8635,6 +8684,10 @@ int llhttp__on_body(
     llhttp__internal_t* s, const unsigned char* p,
     const unsigned char* endp);
 
+int llhttp__on_chunk_parameters(
+    llhttp__internal_t* s, const unsigned char* p,
+    const unsigned char* endp);
+
 int llhttp__on_status(
     llhttp__internal_t* s, const unsigned char* p,
     const unsigned char* endp);
@@ -9299,8 +9352,7 @@ static llparse_state_t llhttp__internal_
           goto s_n_llhttp__internal__n_chunk_parameters;
         }
         case 2: {
-          p++;
-          goto s_n_llhttp__internal__n_chunk_size_almost_done;
+          goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters;
         }
         default: {
           goto s_n_llhttp__internal__n_error_6;
@@ -9309,6 +9361,34 @@ static llparse_state_t llhttp__internal_
       /* UNREACHABLE */;
       abort();
     }
+    case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters:
+    s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters: {
+      if (p == endp) {
+        return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters;
+      }
+      state->_span_pos0 = (void*) p;
+      state->_span_cb0 = llhttp__on_chunk_parameters;
+      goto s_n_llhttp__internal__n_chunk_parameters;
+      /* UNREACHABLE */;
+      abort();
+    }
+    case s_n_llhttp__internal__n_chunk_parameters_ows:
+    s_n_llhttp__internal__n_chunk_parameters_ows: {
+      if (p == endp) {
+        return s_n_llhttp__internal__n_chunk_parameters_ows;
+      }
+      switch (*p) {
+        case ' ': {
+          p++;
+          goto s_n_llhttp__internal__n_chunk_parameters_ows;
+        }
+        default: {
+          goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_parameters;
+        }
+      }
+      /* UNREACHABLE */;
+      abort();
+    }
     case s_n_llhttp__internal__n_chunk_size_otherwise:
     s_n_llhttp__internal__n_chunk_size_otherwise: {
       if (p == endp) {
@@ -9319,13 +9399,9 @@ static llparse_state_t llhttp__internal_
           p++;
           goto s_n_llhttp__internal__n_chunk_size_almost_done;
         }
-        case ' ': {
-          p++;
-          goto s_n_llhttp__internal__n_chunk_parameters;
-        }
         case ';': {
           p++;
-          goto s_n_llhttp__internal__n_chunk_parameters;
+          goto s_n_llhttp__internal__n_chunk_parameters_ows;
         }
         default: {
           goto s_n_llhttp__internal__n_error_7;
@@ -13951,6 +14027,24 @@ static llparse_state_t llhttp__internal_
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_span_end_llhttp__on_chunk_parameters: {
+    const unsigned char* start;
+    int err;
+    
+    start = state->_span_pos0;
+    state->_span_pos0 = NULL;
+    err = llhttp__on_chunk_parameters(state, start, p);
+    if (err != 0) {
+      state->error = err;
+      state->error_pos = (const char*) (p + 1);
+      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done;
+      return s_error;
+    }
+    p++;
+    goto s_n_llhttp__internal__n_chunk_size_almost_done;
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_error_6: {
     state->error = 0x2;
     state->reason = "Invalid character in chunk parameters";
Index: node-v16.20.2/doc/api/errors.md
===================================================================
--- node-v16.20.2.orig/doc/api/errors.md
+++ node-v16.20.2/doc/api/errors.md
@@ -3043,6 +3043,18 @@ malconfigured clients, if more than 8 Ki
 HTTP parsing will abort without a request or response object being created, and
 an `Error` with this code will be emitted.
 
+<a id="HPE_CHUNK_EXTENSIONS_OVERFLOW"></a>
+
+### `HPE_CHUNK_EXTENSIONS_OVERFLOW`
+
+<!-- YAML
+added: REPLACEME
+-->
+
+Too much data was received for a chunk extensions. In order to protect against
+malicious or malconfigured clients, if more than 16 KiB of data is received
+then an `Error` with this code will be emitted.
+
 <a id="HPE_UNEXPECTED_CONTENT_LENGTH"></a>
 
 ### `HPE_UNEXPECTED_CONTENT_LENGTH`
Index: node-v16.20.2/test/parallel/test-http-chunk-extensions-limit.js
===================================================================
--- /dev/null
+++ node-v16.20.2/test/parallel/test-http-chunk-extensions-limit.js
@@ -0,0 +1,131 @@
+'use strict';
+
+const common = require('../common');
+const http = require('http');
+const net = require('net');
+const assert = require('assert');
+
+// Verify that chunk extensions are limited in size when sent all together.
+{
+  const server = http.createServer((req, res) => {
+    req.on('end', () => {
+      res.writeHead(200, { 'Content-Type': 'text/plain' });
+      res.end('bye');
+    });
+
+    req.resume();
+  });
+
+  server.listen(0, () => {
+    const sock = net.connect(server.address().port);
+    let data = '';
+
+    sock.on('data', (chunk) => data += chunk.toString('utf-8'));
+
+    sock.on('end', common.mustCall(function() {
+      assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n');
+      server.close();
+    }));
+
+    sock.end('' +
+      'GET / HTTP/1.1\r\n' +
+      'Host: localhost:8080\r\n' +
+      'Transfer-Encoding: chunked\r\n\r\n' +
+      '2;' + 'A'.repeat(20000) + '=bar\r\nAA\r\n' +
+      '0\r\n\r\n'
+    );
+  });
+}
+
+// Verify that chunk extensions are limited in size when sent in intervals.
+{
+  const server = http.createServer((req, res) => {
+    req.on('end', () => {
+      res.writeHead(200, { 'Content-Type': 'text/plain' });
+      res.end('bye');
+    });
+
+    req.resume();
+  });
+
+  server.listen(0, () => {
+    const sock = net.connect(server.address().port);
+    let remaining = 20000;
+    let data = '';
+
+    const interval = setInterval(
+      () => {
+        if (remaining > 0) {
+          sock.write('A'.repeat(1000));
+        } else {
+          sock.write('=bar\r\nAA\r\n0\r\n\r\n');
+          clearInterval(interval);
+        }
+
+        remaining -= 1000;
+      },
+      common.platformTimeout(20),
+    ).unref();
+
+    sock.on('data', (chunk) => data += chunk.toString('utf-8'));
+
+    sock.on('end', common.mustCall(function() {
+      assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n');
+      server.close();
+    }));
+
+    sock.write('' +
+    'GET / HTTP/1.1\r\n' +
+    'Host: localhost:8080\r\n' +
+    'Transfer-Encoding: chunked\r\n\r\n' +
+    '2;'
+    );
+  });
+}
+
+// Verify the chunk extensions is correctly reset after a chunk
+{
+  const server = http.createServer((req, res) => {
+    req.on('end', () => {
+      res.writeHead(200, { 'content-type': 'text/plain', 'connection': 'close', 'date': 'now' });
+      res.end('bye');
+    });
+
+    req.resume();
+  });
+
+  server.listen(0, () => {
+    const sock = net.connect(server.address().port);
+    let data = '';
+
+    sock.on('data', (chunk) => data += chunk.toString('utf-8'));
+
+    sock.on('end', common.mustCall(function() {
+      assert.strictEqual(
+        data,
+        'HTTP/1.1 200 OK\r\n' +
+        'content-type: text/plain\r\n' +
+        'connection: close\r\n' +
+        'date: now\r\n' +
+        'Transfer-Encoding: chunked\r\n' +
+        '\r\n' +
+        '3\r\n' +
+        'bye\r\n' +
+        '0\r\n' +
+        '\r\n',
+      );
+
+      server.close();
+    }));
+
+    sock.end('' +
+      'GET / HTTP/1.1\r\n' +
+      'Host: localhost:8080\r\n' +
+      'Transfer-Encoding: chunked\r\n\r\n' +
+      '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' +
+      '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' +
+      '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' +
+      '0\r\n\r\n'
+    );
+  });
+}
Index: node-v16.20.2/tools/update-llhttp.sh
===================================================================
--- node-v16.20.2.orig/tools/update-llhttp.sh
+++ node-v16.20.2/tools/update-llhttp.sh
@@ -59,5 +59,5 @@ echo ""
 echo "Please git add llhttp, commit the new version:"
 echo ""
 echo "$ git add -A deps/llhttp"
-echo "$ git commit -m \"deps: update nghttp2 to $LLHTTP_VERSION\""
+echo "$ git commit -m \"deps: update llhttp to $LLHTTP_VERSION\""
 echo ""
Index: node-v16.20.2/lib/_http_server.js
===================================================================
--- node-v16.20.2.orig/lib/_http_server.js
+++ node-v16.20.2/lib/_http_server.js
@@ -706,6 +706,11 @@ const requestHeaderFieldsTooLargeRespons
   `HTTP/1.1 431 ${STATUS_CODES[431]}\r\n` +
   'Connection: close\r\n\r\n', 'ascii'
 );
+const requestChunkExtensionsTooLargeResponse = Buffer.from(
+  `HTTP/1.1 413 ${STATUS_CODES[413]}\r\n` +
+  'Connection: close\r\n\r\n', 'ascii',
+);
+
 function socketOnError(e) {
   // Ignore further errors
   this.removeListener('error', socketOnError);
@@ -719,6 +724,9 @@ function socketOnError(e) {
         case 'HPE_HEADER_OVERFLOW':
           response = requestHeaderFieldsTooLargeResponse;
           break;
+        case 'HPE_CHUNK_EXTENSIONS_OVERFLOW':
+          response = requestChunkExtensionsTooLargeResponse;
+          break;
         case 'ERR_HTTP_REQUEST_TIMEOUT':
           response = requestTimeoutResponse;
           break;
Index: node-v16.20.2/src/node_http_parser.cc
===================================================================
--- node-v16.20.2.orig/src/node_http_parser.cc
+++ node-v16.20.2/src/node_http_parser.cc
@@ -79,6 +79,8 @@ const uint32_t kOnExecute = 5;
 const uint32_t kOnTimeout = 6;
 // Any more fields than this will be flushed into JS
 const size_t kMaxHeaderFieldsCount = 32;
+// Maximum size of chunk extensions
+const size_t kMaxChunkExtensionsSize = 16384;
 
 const uint32_t kLenientNone = 0;
 const uint32_t kLenientHeaders = 1 << 0;
@@ -206,6 +208,7 @@ class Parser : public AsyncWrap, public
 
   int on_message_begin() {
     num_fields_ = num_values_ = 0;
+    chunk_extensions_nread_ = 0;
     url_.Reset();
     status_message_.Reset();
     header_parsing_start_time_ = uv_hrtime();
@@ -443,9 +446,22 @@ class Parser : public AsyncWrap, public
     return 0;
   }
 
-  // Reset nread for the next chunk
+  int on_chunk_extension(const char* at, size_t length) {
+    chunk_extensions_nread_ += length;
+
+    if (chunk_extensions_nread_ > kMaxChunkExtensionsSize) {
+      llhttp_set_error_reason(&parser_,
+        "HPE_CHUNK_EXTENSIONS_OVERFLOW:Chunk extensions overflow");
+      return HPE_USER;
+    }
+
+    return 0;
+  }
+
+  // Reset nread for the next chunk and also reset the extensions counter
   int on_chunk_header() {
     header_nread_ = 0;
+    chunk_extensions_nread_ = 0;
     return 0;
   }
 
@@ -887,6 +903,7 @@ class Parser : public AsyncWrap, public
   const char* current_buffer_data_;
   bool pending_pause_ = false;
   uint64_t header_nread_ = 0;
+  uint64_t chunk_extensions_nread_ = 0;
   uint64_t max_http_header_size_;
   uint64_t headers_timeout_;
   uint64_t header_parsing_start_time_ = 0;
@@ -921,6 +938,7 @@ const llhttp_settings_t Parser::settings
   Proxy<DataCall, &Parser::on_header_field>::Raw,
   Proxy<DataCall, &Parser::on_header_value>::Raw,
   Proxy<Call, &Parser::on_headers_complete>::Raw,
+  Proxy<DataCall, &Parser::on_chunk_extension>::Raw,
   Proxy<DataCall, &Parser::on_body>::Raw,
   Proxy<Call, &Parser::on_message_complete>::Raw,
   Proxy<Call, &Parser::on_chunk_header>::Raw,
openSUSE Build Service is sponsored by