Skip to content

Commit 6fae244

Browse files
joyeecheungjuanarbol
authored andcommitted
build,test: test array index hash collision
This enables v8_enable_seeded_array_index_hash and add a test for it. Fixes: https://hackerone.com/reports/3511792 PR-URL: nodejs-private/node-private#828 CVE-ID: CVE-2026-21717
1 parent 87521e9 commit 6fae244

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
// See https://hackerone.com/reports/3511792
4+
5+
const payload = [];
6+
const val = 1234;
7+
const MOD = 2 ** 19;
8+
const CHN = 2 ** 17;
9+
const REP = 2 ** 17;
10+
11+
if (process.argv[2] === 'benign') {
12+
for (let i = 0; i < CHN + REP; i++) {
13+
payload.push(`${val + i}`);
14+
}
15+
} else {
16+
let j = val + MOD;
17+
for (let i = 1; i < CHN; i++) {
18+
payload.push(`${j}`);
19+
j = (j + i) % MOD;
20+
}
21+
for (let k = 0; k < REP; k++) {
22+
payload.push(`${val}`);
23+
}
24+
}
25+
26+
const string = JSON.stringify({ data: payload });
27+
JSON.parse(string);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
// This is a regression test for https://hackerone.com/reports/3511792
4+
5+
require('../common');
6+
const assert = require('assert');
7+
const { spawnSync } = require('child_process');
8+
const { performance } = require('perf_hooks');
9+
const fixtures = require('../common/fixtures');
10+
11+
const fixturePath = fixtures.path('array-hash-collision.js');
12+
13+
const t0 = performance.now();
14+
const benignResult = spawnSync(process.execPath, [fixturePath, 'benign']);
15+
const benignTime = performance.now() - t0;
16+
assert.strictEqual(benignResult.status, 0);
17+
console.log(`Benign test completed in ${benignTime.toFixed(2)}ms.`);
18+
19+
const t1 = performance.now();
20+
const maliciousResult = spawnSync(process.execPath, [fixturePath, 'malicious'], {
21+
timeout: Math.ceil(benignTime * 10),
22+
});
23+
const maliciousTime = performance.now() - t1;
24+
console.log(`Malicious test completed in ${maliciousTime.toFixed(2)}ms.`);
25+
26+
assert.strictEqual(maliciousResult.status, 0, `Hash flooding regression detected: ` +
27+
`Benign took ${benignTime}ms, malicious took more than ${maliciousTime}ms.`);

tools/make-v8.sh

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ set -xe
55
BUILD_ARCH_TYPE=$1
66
V8_BUILD_OPTIONS=$2
77

8+
EXTRA_V8_OPTS="v8_enable_static_roots=false v8_enable_seeded_array_index_hash=true v8_use_default_hasher_secret=false"
9+
810
cd deps/v8 || exit
911
find . -type d -name .git -print0 | xargs -0 rm -rf
1012
../../tools/v8/fetch_deps.py .
@@ -32,11 +34,20 @@ if [ "$ARCH" = "s390x" ] || [ "$ARCH" = "ppc64le" ]; then
3234
*clang*) GN_COMPILER_OPTS="is_clang=true clang_base_path=\"/usr\" clang_use_chrome_plugins=false treat_warnings_as_errors=false use_custom_libcxx=false" ;;
3335
*) GN_COMPILER_OPTS="treat_warnings_as_errors=false use_custom_libcxx=false" ;;
3436
esac
35-
gn gen -v "out.gn/$BUILD_ARCH_TYPE" --args="$GN_COMPILER_OPTS is_component_build=false is_debug=false v8_target_cpu=\"$TARGET_ARCH\" target_cpu=\"$TARGET_ARCH\" v8_enable_backtrace=true $CC_WRAPPER"
36-
ninja -v -C "out.gn/$BUILD_ARCH_TYPE" "${JOBS_ARG}" d8 cctest inspector-test
37+
gn gen -v "out.gn/$BUILD_ARCH_TYPE" --args="$GN_COMPILER_OPTS is_component_build=false is_debug=false v8_target_cpu=\"$TARGET_ARCH\" target_cpu=\"$TARGET_ARCH\" v8_enable_backtrace=true $CC_WRAPPER $EXTRA_V8_OPTS"
38+
# shellcheck disable=SC2086
39+
ninja -v -C "out.gn/$BUILD_ARCH_TYPE" ${JOBS_ARG} d8 cctest inspector-test
3740
else
3841
DEPOT_TOOLS_DIR="$(cd depot_tools && pwd)"
42+
export DEPOT_TOOLS_DIR
43+
"$DEPOT_TOOLS_DIR/ensure_bootstrap"
44+
export CHROMIUM_BUILDTOOLS_PATH="$PWD/buildtools"
3945
# shellcheck disable=SC2086
4046
PATH="$DEPOT_TOOLS_DIR":$PATH tools/dev/v8gen.py "$BUILD_ARCH_TYPE" $V8_BUILD_OPTIONS
41-
PATH="$DEPOT_TOOLS_DIR":$PATH ninja -C "out.gn/$BUILD_ARCH_TYPE/" "${JOBS_ARG}" d8 cctest inspector-test
47+
for opt in $EXTRA_V8_OPTS; do
48+
echo "${opt%%=*} = ${opt#*=}" >> "out.gn/$BUILD_ARCH_TYPE/args.gn"
49+
done
50+
PATH="$DEPOT_TOOLS_DIR":$PATH gn gen -v "out.gn/$BUILD_ARCH_TYPE"
51+
# shellcheck disable=SC2086
52+
PATH="$DEPOT_TOOLS_DIR":$PATH ninja -C "out.gn/$BUILD_ARCH_TYPE/" ${JOBS_ARG} d8 cctest inspector-test
4253
fi

tools/v8_gypfiles/features.gypi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@
202202
# Use Siphash as added protection against hash flooding attacks.
203203
'v8_use_siphash%': 0,
204204

205+
# Enable seeded array index hash.
206+
'v8_enable_seeded_array_index_hash%': 1,
207+
205208
# Use Perfetto (https://perfetto.dev) as the default TracingController. Not
206209
# currently implemented.
207210
'v8_use_perfetto%': 0,
@@ -450,6 +453,9 @@
450453
['v8_use_siphash==1', {
451454
'defines': ['V8_USE_SIPHASH',],
452455
}],
456+
['v8_enable_seeded_array_index_hash==1', {
457+
'defines': ['V8_ENABLE_SEEDED_ARRAY_INDEX_HASH',],
458+
}],
453459
['dcheck_always_on!=0', {
454460
'defines': ['DEBUG',],
455461
}, {

0 commit comments

Comments
 (0)