Skip to content

Commit 6f14ee5

Browse files
joyeecheungaduh95
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 Backport-PR-URL: nodejs-private/node-private#833 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: nodejs-private/node-private#809 CVE-ID: CVE-2026-21717
1 parent e3f4d6a commit 6f14ee5

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
@@ -193,6 +193,9 @@
193193
# Use Siphash as added protection against hash flooding attacks.
194194
'v8_use_siphash%': 0,
195195

196+
# Enable seeded array index hash.
197+
'v8_enable_seeded_array_index_hash%': 1,
198+
196199
# Use Perfetto (https://perfetto.dev) as the default TracingController. Not
197200
# currently implemented.
198201
'v8_use_perfetto%': 0,
@@ -454,6 +457,9 @@
454457
['v8_use_siphash==1', {
455458
'defines': ['V8_USE_SIPHASH',],
456459
}],
460+
['v8_enable_seeded_array_index_hash==1', {
461+
'defines': ['V8_ENABLE_SEEDED_ARRAY_INDEX_HASH',],
462+
}],
457463
['v8_enable_shared_ro_heap==1', {
458464
'defines': ['V8_SHARED_RO_HEAP',],
459465
}],

0 commit comments

Comments
 (0)