diff --git a/Disable-running-gyp-on-shared-deps.patch b/0001-Disable-running-gyp-on-shared-deps.patch similarity index 62% rename from Disable-running-gyp-on-shared-deps.patch rename to 0001-Disable-running-gyp-on-shared-deps.patch index 7db5731e019b8bd6614aaa7a177b01e2c896167d..3c11dd8747bbd2cdb47fdc77dcac8480ef08aed2 100644 --- a/Disable-running-gyp-on-shared-deps.patch +++ b/0001-Disable-running-gyp-on-shared-deps.patch @@ -1,10 +1,17 @@ +From 7a6257be1d0276ff22d2d92ea89c5bca6c633802 Mon Sep 17 00:00:00 2001 +From: Zuzana Svetlikova +Date: Thu, 27 Apr 2017 14:25:42 +0200 +Subject: [PATCH 1/3] Disable running gyp on shared deps + +--- + Makefile | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + diff --git a/Makefile b/Makefile -index 5fc2bb0c58f5532044a14e9f9595b2316f562726..f1c1545caa220d7442d6d92c49412ec7554de123 100644 +index 316410e3f81e39cdddecf91d5b717c884a9c51b3..62c8ebb5b95a68e44d4c2ab3beee70d63c3175c7 100644 --- a/Makefile +++ b/Makefile -@@ -121,14 +121,13 @@ with-code-cache: - - .PHONY: test-code-cache +@@ -123,10 +123,9 @@ with-code-cache: test-code-cache: with-code-cache $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) code-cache @@ -18,8 +25,6 @@ index 5fc2bb0c58f5532044a14e9f9595b2316f562726..f1c1545caa220d7442d6d92c49412ec7 $(PYTHON) tools/gyp_node.py -f make config.gypi: configure configure.py - @if [ -x config.status ]; then \ - ./config.status; \ -- -2.19.0 +2.24.1 diff --git a/0002-Install-both-binaries-and-use-libdir.patch b/0002-Install-both-binaries-and-use-libdir.patch new file mode 100644 index 0000000000000000000000000000000000000000..9e184d7e926bdc2c6914a91365a6620725ac0955 --- /dev/null +++ b/0002-Install-both-binaries-and-use-libdir.patch @@ -0,0 +1,86 @@ +From 8828c8fdc98f310a718a65ebc47d8a163e41b0cb Mon Sep 17 00:00:00 2001 +From: Elliott Sales de Andrade +Date: Tue, 19 Mar 2019 23:22:40 -0400 +Subject: [PATCH 2/3] Install both binaries and use libdir. + +This allows us to build with a shared library for other users while +still providing the normal executable. + +Signed-off-by: Elliott Sales de Andrade +--- + configure.py | 7 +++++++ + tools/install.py | 29 +++++++++++++---------------- + 2 files changed, 20 insertions(+), 16 deletions(-) + +diff --git a/configure.py b/configure.py +index 22861a10eeac54cae69fc1be4b9aef7ed5106a35..48389fbdcb57cbf8d9c11d4921c65f34a1937cc7 100755 +--- a/configure.py ++++ b/configure.py +@@ -552,6 +552,12 @@ parser.add_option('--shared', + help='compile shared library for embedding node in another project. ' + + '(This mode is not officially supported for regular applications)') + ++parser.add_option('--libdir', ++ action='store', ++ dest='libdir', ++ default='lib', ++ help='a directory to install the shared library into') ++ + parser.add_option('--without-v8-platform', + action='store_true', + dest='without_v8_platform', +@@ -1095,6 +1101,7 @@ def configure_node(o): + if options.code_cache_path: + o['variables']['node_code_cache_path'] = options.code_cache_path + o['variables']['node_shared'] = b(options.shared) ++ o['variables']['libdir'] = options.libdir + node_module_version = getmoduleversion.get_version() + + if sys.platform == 'darwin': +diff --git a/tools/install.py b/tools/install.py +index 028c32ecbbdf9625238dfcc2baef66df9408b539..bf443c4d15a3b3ebf1e10a5dd802e9c5999691e5 100755 +--- a/tools/install.py ++++ b/tools/install.py +@@ -117,26 +117,23 @@ def subdir_files(path, dest, action): + + def files(action): + is_windows = sys.platform == 'win32' +- output_file = 'node' + output_prefix = 'out/Release/' ++ output_libprefix = output_prefix + +- if 'false' == variables.get('node_shared'): +- if is_windows: +- output_file += '.exe' ++ if is_windows: ++ output_bin = 'node.exe' ++ output_lib = 'node.dll' + else: +- if is_windows: +- output_file += '.dll' +- else: +- output_file = 'lib' + output_file + '.' + variables.get('shlib_suffix') +- # GYP will output to lib.target except on OS X, this is hardcoded +- # in its source - see the _InstallableTargetInstallPath function. +- if sys.platform != 'darwin': +- output_prefix += 'lib.target/' ++ output_bin = 'node' ++ output_lib = 'libnode.' + variables.get('shlib_suffix') ++ # GYP will output to lib.target except on OS X, this is hardcoded ++ # in its source - see the _InstallableTargetInstallPath function. ++ if sys.platform != 'darwin': ++ output_libprefix += 'lib.target/' + +- if 'false' == variables.get('node_shared'): +- action([output_prefix + output_file], 'bin/' + output_file) +- else: +- action([output_prefix + output_file], 'lib/' + output_file) ++ action([output_prefix + output_bin], 'bin/' + output_bin) ++ if 'true' == variables.get('node_shared'): ++ action([output_libprefix + output_lib], variables.get('libdir') + '/' + output_lib) + + if 'true' == variables.get('node_use_dtrace'): + action(['out/Release/node.d'], 'lib/dtrace/node.d') +-- +2.24.1 + diff --git a/0003-build-auto-load-ICU-data-from-with-icu-default-data-.patch b/0003-build-auto-load-ICU-data-from-with-icu-default-data-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a02d6519c42ec29ba4d7acfec0eb7089c916caf --- /dev/null +++ b/0003-build-auto-load-ICU-data-from-with-icu-default-data-.patch @@ -0,0 +1,122 @@ +From 9ca4d4aeccf50e6c036e5536ef070a09c1776817 Mon Sep 17 00:00:00 2001 +From: Stephen Gallagher +Date: Fri, 6 Dec 2019 16:40:25 -0500 +Subject: [PATCH 3/3] build: auto-load ICU data from + --with-icu-default-data-dir + +When compiled with `--with-intl=small` and +`--with-icu-default-data-dir=PATH`, Node.js will use PATH as a +fallback location for the ICU data. + +We will first perform an access check using fopen(PATH, 'r') to +ensure that the file is readable. If it is, we'll set the +icu_data_directory and proceed. There's a slight overhead for the +fopen() check, but it should be barely measurable. + +This will be useful for Linux distribution packagers who want to +be able to ship a minimal node binary in a container image but +also be able to add on the full i18n support where needed. With +this patch, it becomes possible to ship the interpreter as +/usr/bin/node in one package for the distribution and to ship the +data files in another package (without a strict dependency +between the two). This means that users of the distribution will +not need to explicitly direct Node.js to locate the ICU data. It +also means that in environments where full internationalization is +not required, they do not need to carry the extra content (with +the associated storage costs). + +Refs: https://github.com/nodejs/node/issues/3460 + +Signed-off-by: Stephen Gallagher +--- + configure.py | 9 +++++++++ + node.gypi | 7 +++++++ + src/node.cc | 20 ++++++++++++++++++++ + 3 files changed, 36 insertions(+) + +diff --git a/configure.py b/configure.py +index 48389fbdcb57cbf8d9c11d4921c65f34a1937cc7..063e8748b954a7fed4fe084399e61371c061edab 100755 +--- a/configure.py ++++ b/configure.py +@@ -433,6 +433,14 @@ intl_optgroup.add_option('--with-icu-source', + 'the icu4c source archive. ' + 'v%d.x or later recommended.' % icu_versions['minimum_icu']) + ++intl_optgroup.add_option('--with-icu-default-data-dir', ++ action='store', ++ dest='with_icu_default_data_dir', ++ help='Path to the icuXXdt{lb}.dat file. If unspecified, ICU data will ' ++ 'only be read if the NODE_ICU_DATA environment variable or the ' ++ '--icu-data-dir runtime argument is used. This option has effect ' ++ 'only when Node.js is built with --with-intl=small-icu.') ++ + parser.add_option('--with-ltcg', + action='store_true', + dest='with_ltcg', +@@ -1360,6 +1368,7 @@ def configure_intl(o): + locs.add('root') # must have root + o['variables']['icu_locales'] = string.join(locs,',') + # We will check a bit later if we can use the canned deps/icu-small ++ o['variables']['icu_default_data'] = options.with_icu_default_data_dir or '' + elif with_intl == 'full-icu': + # full ICU + o['variables']['v8_enable_i18n_support'] = 1 +diff --git a/node.gypi b/node.gypi +index 466a1746811cfac1a8ce4ef604ef1152c6229ff1..65b97d6466a14f4343a948a5fc36f8a2580badfb 100644 +--- a/node.gypi ++++ b/node.gypi +@@ -113,6 +113,13 @@ + 'conditions': [ + [ 'icu_small=="true"', { + 'defines': [ 'NODE_HAVE_SMALL_ICU=1' ], ++ 'conditions': [ ++ [ 'icu_default_data!=""', { ++ 'defines': [ ++ 'NODE_ICU_DEFAULT_DATA_DIR="<(icu_default_data)"', ++ ], ++ }], ++ ], + }]], + }], + [ 'node_use_bundled_v8=="true" and \ +diff --git a/src/node.cc b/src/node.cc +index 7c0118758dfd9449283b900209b2ba8df7ddd129..c9840e3e367ca47176a17a7940a1e08eb1f56f78 100644 +--- a/src/node.cc ++++ b/src/node.cc +@@ -92,6 +92,7 @@ + + #if defined(NODE_HAVE_I18N_SUPPORT) + #include ++#include + #endif + + #if defined(LEAK_SANITIZER) +@@ -2643,6 +2644,25 @@ void Init(std::vector* argv, + // If the parameter isn't given, use the env variable. + if (per_process_opts->icu_data_dir.empty()) + SafeGetenv("NODE_ICU_DATA", &per_process_opts->icu_data_dir); ++ ++#ifdef NODE_ICU_DEFAULT_DATA_DIR ++ // If neither the CLI option nor the environment variable was specified, ++ // fall back to the configured default ++ if (per_process_opts->icu_data_dir.empty()) { ++ // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data ++ // file and can be read. ++ static const char full_path[] = ++ NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat"; ++ ++ FILE* f = fopen(full_path, "rb"); ++ ++ if (f != nullptr) { ++ fclose(f); ++ per_process_opts->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR; ++ } ++ } ++#endif // NODE_ICU_DEFAULT_DATA_DIR ++ + // Initialize ICU. + // If icu_data_dir is empty here, it will load the 'minimal' data. + if (!i18n::InitializeICUDirectory(per_process_opts->icu_data_dir)) { +-- +2.24.1 + diff --git a/CVE-2018-12121.patch b/CVE-2018-12121.patch deleted file mode 100644 index 5a54b5ad20c3222c3a7474651715fab0c8ca04ed..0000000000000000000000000000000000000000 --- a/CVE-2018-12121.patch +++ /dev/null @@ -1,265 +0,0 @@ -From 186035243fad247e3955fa0c202987cae99e82db Mon Sep 17 00:00:00 2001 -From: Matteo Collina -Date: Tue, 21 Aug 2018 17:26:51 +0200 -Subject: [PATCH] deps,http: http_parser set max header size to 8KB - -CVE-2018-12121 - -PR-URL: https://github.com/nodejs-private/node-private/pull/143 -Ref: https://github.com/nodejs-private/security/issues/139 -Ref: https://github.com/nodejs-private/http-parser-private/pull/2 -Reviewed-By: Anatoli Papirovski -Reviewed-By: Ben Noordhuis -Reviewed-By: James M Snell -Reviewed-By: Rod Vagg -Reviewed-By: Anna Henningsen ---- - deps/http_parser/http_parser.gyp | 4 +- - test/parallel/test-http-max-headers-count.js | 6 +- - test/parallel/test-https-max-headers-count.js | 6 +- - test/sequential/test-http-max-http-headers.js | 154 ++++++++++++++++++ - 4 files changed, 162 insertions(+), 8 deletions(-) - create mode 100644 test/sequential/test-http-max-http-headers.js - -diff --git a/deps/http_parser/http_parser.gyp b/deps/http_parser/http_parser.gyp -index ef34ecaeaea..4364f73d1f4 100644 ---- a/deps/http_parser/http_parser.gyp -+++ b/deps/http_parser/http_parser.gyp -@@ -56,7 +56,7 @@ - 'defines': [ 'HTTP_PARSER_STRICT=0' ], - 'include_dirs': [ '.' ], - }, -- 'defines': [ 'HTTP_PARSER_STRICT=0' ], -+ 'defines': [ 'HTTP_MAX_HEADER_SIZE=8192', 'HTTP_PARSER_STRICT=0' ], - 'sources': [ './http_parser.c', ], - 'conditions': [ - ['OS=="win"', { -@@ -79,7 +79,7 @@ - 'defines': [ 'HTTP_PARSER_STRICT=1' ], - 'include_dirs': [ '.' ], - }, -- 'defines': [ 'HTTP_PARSER_STRICT=1' ], -+ 'defines': [ 'HTTP_MAX_HEADER_SIZE=8192', 'HTTP_PARSER_STRICT=1' ], - 'sources': [ './http_parser.c', ], - 'conditions': [ - ['OS=="win"', { -diff --git a/test/parallel/test-http-max-headers-count.js b/test/parallel/test-http-max-headers-count.js -index 05f4f774c2c..9fcfe316e39 100644 ---- a/test/parallel/test-http-max-headers-count.js -+++ b/test/parallel/test-http-max-headers-count.js -@@ -28,14 +28,14 @@ let requests = 0; - let responses = 0; - - const headers = {}; --const N = 2000; -+const N = 100; - for (let i = 0; i < N; ++i) { - headers[`key${i}`] = i; - } - - const maxAndExpected = [ // for server - [50, 50], -- [1500, 1500], -+ [1500, 102], - [0, N + 2] // Host and Connection - ]; - let max = maxAndExpected[requests][0]; -@@ -56,7 +56,7 @@ server.maxHeadersCount = max; - server.listen(0, function() { - const maxAndExpected = [ // for client - [20, 20], -- [1200, 1200], -+ [1200, 103], - [0, N + 3] // Connection, Date and Transfer-Encoding - ]; - doRequest(); -diff --git a/test/parallel/test-https-max-headers-count.js b/test/parallel/test-https-max-headers-count.js -index 8c099d1e5fb..12aaaa9cd3a 100644 ---- a/test/parallel/test-https-max-headers-count.js -+++ b/test/parallel/test-https-max-headers-count.js -@@ -17,14 +17,14 @@ let requests = 0; - let responses = 0; - - const headers = {}; --const N = 2000; -+const N = 100; - for (let i = 0; i < N; ++i) { - headers[`key${i}`] = i; - } - - const maxAndExpected = [ // for server - [50, 50], -- [1500, 1500], -+ [1500, 102], - [0, N + 2] // Host and Connection - ]; - let max = maxAndExpected[requests][0]; -@@ -45,7 +45,7 @@ server.maxHeadersCount = max; - server.listen(0, common.mustCall(() => { - const maxAndExpected = [ // for client - [20, 20], -- [1200, 1200], -+ [1200, 103], - [0, N + 3] // Connection, Date and Transfer-Encoding - ]; - const doRequest = common.mustCall(() => { -diff --git a/test/sequential/test-http-max-http-headers.js b/test/sequential/test-http-max-http-headers.js -new file mode 100644 -index 00000000000..155b75fb076 ---- /dev/null -+++ b/test/sequential/test-http-max-http-headers.js -@@ -0,0 +1,154 @@ -+'use strict'; -+ -+const assert = require('assert'); -+const common = require('../common'); -+const http = require('http'); -+const net = require('net'); -+const MAX = 8 * 1024; // 8KB -+ -+// Verify that we cannot receive more than 8KB of headers. -+ -+function once(cb) { -+ let called = false; -+ return () => { -+ if (!called) { -+ called = true; -+ cb(); -+ } -+ }; -+} -+ -+function finished(client, callback) { -+ 'abort error end'.split(' ').forEach((e) => { -+ client.on(e, once(() => setImmediate(callback))); -+ }); -+} -+ -+function fillHeaders(headers, currentSize, valid = false) { -+ // Generate valid headers -+ if (valid) { -+ // TODO(mcollina): understand why -9 is needed instead of -1 -+ headers = headers.slice(0, -9); -+ } -+ return headers + '\r\n\r\n'; -+} -+ -+const timeout = common.platformTimeout(10); -+ -+function writeHeaders(socket, headers) { -+ const array = []; -+ -+ // this is off from 1024 so that \r\n does not get split -+ const chunkSize = 1000; -+ let last = 0; -+ -+ for (let i = 0; i < headers.length / chunkSize; i++) { -+ const current = (i + 1) * chunkSize; -+ array.push(headers.slice(last, current)); -+ last = current; -+ } -+ -+ // safety check we are chunking correctly -+ assert.strictEqual(array.join(''), headers); -+ -+ next(); -+ -+ function next() { -+ if (socket.write(array.shift())) { -+ if (array.length === 0) { -+ socket.end(); -+ } else { -+ setTimeout(next, timeout); -+ } -+ } else { -+ socket.once('drain', next); -+ } -+ } -+} -+ -+function test1() { -+ let headers = -+ 'HTTP/1.1 200 OK\r\n' + -+ 'Content-Length: 0\r\n' + -+ 'X-CRASH: '; -+ -+ // OK, Content-Length, 0, X-CRASH, aaa... -+ const currentSize = 2 + 14 + 1 + 7; -+ headers = fillHeaders(headers, currentSize); -+ -+ const server = net.createServer((sock) => { -+ sock.once('data', (chunk) => { -+ writeHeaders(sock, headers); -+ sock.resume(); -+ }); -+ }); -+ -+ server.listen(0, common.mustCall(() => { -+ const port = server.address().port; -+ const client = http.get({ port: port }, common.mustNotCall(() => {})); -+ -+ client.on('error', common.mustCall((err) => { -+ assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW'); -+ server.close(); -+ setImmediate(test2); -+ })); -+ })); -+} -+ -+const test2 = common.mustCall(() => { -+ let headers = -+ 'GET / HTTP/1.1\r\n' + -+ 'Host: localhost\r\n' + -+ 'Agent: node\r\n' + -+ 'X-CRASH: '; -+ -+ // /, Host, localhost, Agent, node, X-CRASH, a... -+ const currentSize = 1 + 4 + 9 + 5 + 4 + 7; -+ headers = fillHeaders(headers, currentSize); -+ -+ const server = http.createServer(common.mustNotCall()); -+ -+ server.on('clientError', common.mustCall((err) => { -+ assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW'); -+ })); -+ -+ server.listen(0, common.mustCall(() => { -+ const client = net.connect(server.address().port); -+ client.on('connect', () => { -+ writeHeaders(client, headers); -+ client.resume(); -+ }); -+ -+ finished(client, common.mustCall((err) => { -+ server.close(); -+ setImmediate(test3); -+ })); -+ })); -+}); -+ -+const test3 = common.mustCall(() => { -+ let headers = -+ 'GET / HTTP/1.1\r\n' + -+ 'Host: localhost\r\n' + -+ 'Agent: node\r\n' + -+ 'X-CRASH: '; -+ -+ // /, Host, localhost, Agent, node, X-CRASH, a... -+ const currentSize = 1 + 4 + 9 + 5 + 4 + 7; -+ headers = fillHeaders(headers, currentSize, true); -+ -+ const server = http.createServer(common.mustCall((req, res) => { -+ res.end('hello world'); -+ setImmediate(server.close.bind(server)); -+ })); -+ -+ server.listen(0, common.mustCall(() => { -+ const client = net.connect(server.address().port); -+ client.on('connect', () => { -+ writeHeaders(client, headers); -+ client.resume(); -+ }); -+ })); -+}); -+ -+test1(); diff --git a/CVE-2018-12122.patch b/CVE-2018-12122.patch deleted file mode 100644 index c46268b278865a2e9d773bfcc441a160c8f48b55..0000000000000000000000000000000000000000 --- a/CVE-2018-12122.patch +++ /dev/null @@ -1,208 +0,0 @@ -From ee618a7ab239c98d945c723a4e225bc409151736 Mon Sep 17 00:00:00 2001 -From: Matteo Collina -Date: Thu, 23 Aug 2018 16:46:07 +0200 -Subject: [PATCH] http,https: protect against slow headers attack - -CVE-2018-12122 - -An attacker can send a char/s within headers and exahust the resources -(file descriptors) of a system even with a tight max header length -protection. This PR destroys a socket if it has not received the headers -in 40s. - -PR-URL: https://github.com/nodejs-private/node-private/pull/144 -Reviewed-By: Sam Roberts -Reviewed-By: Ben Noordhuis -Reviewed-By: James M Snell ---- - doc/api/http.md | 20 ++++++++ - doc/api/https.md | 7 +++ - lib/_http_server.js | 22 ++++++++- - lib/https.js | 1 + - lib/internal/http.js | 27 +++++++--- - test/async-hooks/test-graph.http.js | 2 +- - test/parallel/test-http-slow-headers.js | 50 +++++++++++++++++++ - test/parallel/test-https-slow-headers.js | 63 ++++++++++++++++++++++++ - 8 files changed, 182 insertions(+), 10 deletions(-) - create mode 100644 test/parallel/test-http-slow-headers.js - create mode 100644 test/parallel/test-https-slow-headers.js - -diff --git a/doc/api/http.md b/doc/api/http.md -index 1c6b5717e004..13373debb404 100644 ---- a/doc/api/http.md -+++ b/doc/api/http.md -@@ -958,6 +958,26 @@ added: v0.7.0 - - Limits maximum incoming headers count. If set to 0, no limit will be applied. - -+### server.headersTimeout -+ -+ -+* {number} **Default:** `40000` -+ -+Limit the amount of time the parser will wait to receive the complete HTTP -+headers. -+ -+In case of inactivity, the rules defined in [server.timeout][] apply. However, -+that inactivity based timeout would still allow the connection to be kept open -+if the headers are being sent very slowly (by default, up to a byte per 2 -+minutes). In order to prevent this, whenever header data arrives an additional -+check is made that more than `server.headersTimeout` milliseconds has not -+passed since the connection was established. If the check fails, a `'timeout'` -+event is emitted on the server object, and (by default) the socket is destroyed. -+See [server.timeout][] for more information on how timeout behaviour can be -+customised. -+ - ### server.setTimeout([msecs][, callback]) -