Experimental Policy Mechanism (CVE-2023-30581, bsc#1212574) - CVE-2023-30589.patch: HTTP Request Smuggling via empty headers separated by CR (CVE-2023-30589, bsc#1212582) - CVE-2023-30590.patch: DiffieHellman does not generate keys after setting a private key (CVE-2023-30590, bsc#1212583) - CVE-2023-23918.patch: fixes permissions policies can be bypassed via process.mainModule (bsc#1208481, CVE-2023-23918) - CVE-2023-32002.patch: + fixes policies can be bypassed via Module._load + fixes policies can be bypassed by module.constructor.createRequire (CVE-2023-32002, CVE-2023-32006, bsc#1214150, bsc#1214156) - CVE-2023-32559.patch: Policies can be bypassed via process.binding (CVE-2023-32559, bsc#1214154) OBS-URL: https://build.opensuse.org/package/show/devel:languages:nodejs/nodejs12?expand=0&rev=150
161 lines
5.3 KiB
Diff
161 lines
5.3 KiB
Diff
commit 242aaa0caaf0c15109067b598d58fdeae603c5fd
|
|
Author: Tobias Nießen <tobias.niessen@tuwien.ac.at>
|
|
Date: Sun Apr 16 22:26:47 2023 +0200
|
|
|
|
policy: disable process.binding() when enabled
|
|
|
|
process.binding() can be used to trivially bypass restrictions imposed
|
|
through a policy. Since the function is deprecated already, simply
|
|
replace it with a stub when a policy is being enabled.
|
|
|
|
Fixes: https://hackerone.com/bugs?report_id=1946470
|
|
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
|
|
CVE-ID: CVE-2023-32559
|
|
PR-URL: https://github.com/nodejs-private/node-private/pull/459
|
|
|
|
Index: node-v12.22.12/doc/api/deprecations.md
|
|
===================================================================
|
|
--- node-v12.22.12.orig/doc/api/deprecations.md
|
|
+++ node-v12.22.12/doc/api/deprecations.md
|
|
@@ -2162,6 +2162,9 @@ Type: Documentation-only (supports [`--p
|
|
|
|
`process.binding()` is for use by Node.js internal code only.
|
|
|
|
+While `process.binding()` has not reached End-of-Life status in general, it is
|
|
+unavailable when [policies][] are enabled.
|
|
+
|
|
<a id="DEP0112"></a>
|
|
### DEP0112: `dgram` private APIs
|
|
<!-- YAML
|
|
@@ -2710,3 +2713,5 @@ const moduleParents = Object.values(requ
|
|
[from_arraybuffer]: buffer.html#buffer_static_method_buffer_from_arraybuffer_byteoffset_length
|
|
[from_string_encoding]: buffer.html#buffer_static_method_buffer_from_string_encoding
|
|
[legacy `urlObject`]: url.html#url_legacy_urlobject
|
|
+[policies]: permissions.md#policies
|
|
+
|
|
Index: node-v12.22.12/doc/api/errors.md
|
|
===================================================================
|
|
--- node-v12.22.12.orig/doc/api/errors.md
|
|
+++ node-v12.22.12/doc/api/errors.md
|
|
@@ -610,6 +610,14 @@ A human-readable string describing the r
|
|
<a id="nodejs-error-codes"></a>
|
|
## Node.js error codes
|
|
|
|
+<a id="ERR_ACCESS_DENIED"></a>
|
|
+
|
|
+### `ERR_ACCESS_DENIED`
|
|
+
|
|
+A special type of error that is triggered whenever Node.js tries to get access
|
|
+to a resource restricted by the [policy][] manifest.
|
|
+For example, `process.binding`.
|
|
+
|
|
<a id="ERR_AMBIGUOUS_ARGUMENT"></a>
|
|
### `ERR_AMBIGUOUS_ARGUMENT`
|
|
|
|
Index: node-v12.22.12/lib/internal/errors.js
|
|
===================================================================
|
|
--- node-v12.22.12.orig/lib/internal/errors.js
|
|
+++ node-v12.22.12/lib/internal/errors.js
|
|
@@ -746,6 +746,10 @@ module.exports = {
|
|
// Note: Please try to keep these in alphabetical order
|
|
//
|
|
// Note: Node.js specific errors must begin with the prefix ERR_
|
|
+
|
|
+E('ERR_ACCESS_DENIED',
|
|
+ 'Access to this API has been restricted. Permission: %s',
|
|
+ Error);
|
|
E('ERR_AMBIGUOUS_ARGUMENT', 'The "%s" argument is ambiguous. %s', TypeError);
|
|
E('ERR_ARG_NOT_ITERABLE', '%s must be iterable', TypeError);
|
|
E('ERR_ASSERTION', '%s', Error);
|
|
Index: node-v12.22.12/lib/internal/process/policy.js
|
|
===================================================================
|
|
--- node-v12.22.12.orig/lib/internal/process/policy.js
|
|
+++ node-v12.22.12/lib/internal/process/policy.js
|
|
@@ -7,6 +7,7 @@ const {
|
|
} = primordials;
|
|
|
|
const {
|
|
+ ERR_ACCESS_DENIED,
|
|
ERR_MANIFEST_TDZ,
|
|
} = require('internal/errors').codes;
|
|
const { Manifest } = require('internal/policy/manifest');
|
|
@@ -32,6 +33,15 @@ module.exports = ObjectFreeze({
|
|
return o;
|
|
});
|
|
manifest = new Manifest(json, url);
|
|
+
|
|
+ // process.binding() is deprecated (DEP0111) and trivially allows bypassing
|
|
+ // policies, so if policies are enabled, make this API unavailable.
|
|
+ process.binding = function binding(_module) {
|
|
+ throw new ERR_ACCESS_DENIED('process.binding');
|
|
+ };
|
|
+ process._linkedBinding = function _linkedBinding(_module) {
|
|
+ throw new ERR_ACCESS_DENIED('process._linkedBinding');
|
|
+ };
|
|
},
|
|
|
|
get manifest() {
|
|
Index: node-v12.22.12/test/fixtures/policy/process-binding/app.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v12.22.12/test/fixtures/policy/process-binding/app.js
|
|
@@ -0,0 +1,10 @@
|
|
+'use strict';
|
|
+
|
|
+const assert = require('assert');
|
|
+
|
|
+assert.throws(() => { process.binding(); }, {
|
|
+ code: 'ERR_ACCESS_DENIED'
|
|
+});
|
|
+assert.throws(() => { process._linkedBinding(); }, {
|
|
+ code: 'ERR_ACCESS_DENIED'
|
|
+});
|
|
Index: node-v12.22.12/test/fixtures/policy/process-binding/policy.json
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v12.22.12/test/fixtures/policy/process-binding/policy.json
|
|
@@ -0,0 +1,10 @@
|
|
+{
|
|
+ "resources": {
|
|
+ "./app.js": {
|
|
+ "integrity": true,
|
|
+ "dependencies": {
|
|
+ "assert": true
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
Index: node-v12.22.12/test/parallel/test-policy-process-binding.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v12.22.12/test/parallel/test-policy-process-binding.js
|
|
@@ -0,0 +1,28 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+common.requireNoPackageJSONAbove();
|
|
+
|
|
+if (!common.hasCrypto)
|
|
+ common.skip('missing crypto');
|
|
+
|
|
+const fixtures = require('../common/fixtures');
|
|
+
|
|
+const assert = require('assert');
|
|
+const { spawnSync } = require('child_process');
|
|
+
|
|
+const dep = fixtures.path('policy', 'process-binding', 'app.js');
|
|
+const depPolicy = fixtures.path(
|
|
+ 'policy',
|
|
+ 'process-binding',
|
|
+ 'policy.json');
|
|
+const { status } = spawnSync(
|
|
+ process.execPath,
|
|
+ [
|
|
+ '--experimental-policy', depPolicy, dep,
|
|
+ ],
|
|
+ {
|
|
+ stdio: 'inherit'
|
|
+ },
|
|
+);
|
|
+assert.strictEqual(status, 0);
|