Firefox · SpiderMonkey
CVE-2026-84142
Memory Corruption in SpiderMonkey
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forjs/src/intgemm/IntegerGemmIntrinsic.cpp |
modified | |
ifjs/src/intgemm/IntegerGemmIntrinsic.cpp |
modified | |
forjs/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js |
modified |
Files Changed
js/src/intgemm/IntegerGemmIntrinsic.cppjs/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
Patch
diff --git a/js/src/intgemm/IntegerGemmIntrinsic.cpp b/js/src/intgemm/IntegerGemmIntrinsic.cpp
index f1c400c5818..94f780009eb 100644
--- a/js/src/intgemm/IntegerGemmIntrinsic.cpp
+++ b/js/src/intgemm/IntegerGemmIntrinsic.cpp
@@ -457,6 +457,16 @@ int32_t js::intgemm::IntrI8SelectColumnsOfB(wasm::Instance* instance,
const uint32_t* colIndexListPtr =
reinterpret_cast<const uint32_t*>(&memBase[colIndexList]);
int8_t* outputPtr = reinterpret_cast<int8_t*>(&memBase[output]);
+
+ // Every selected column index must reference a valid column of B. Otherwise
+ // SelectColumnsB would read outside the bounds-checked input matrix, since it
+ // uses each index to compute an offset into inputMatrixBPrepared.
+ for (uint32_t i = 0; i < sizeColIndexList; i++) {
+ if (colIndexListPtr[i] >= colsB) {
+ return -1;
+ }
+ }
+
AutoProfilerMarker marker(cx->runtime()->geckoProfiler(),
"integemm::SelectColumnsB",
"rowsB: {} colsB: {} sizecolList: {}, sizeB: {}",
diff --git a/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js b/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
index dcdefa62947..ab5a57c0d20 100644
--- a/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
+++ b/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
@@ -60,6 +60,24 @@ function testOutOfBounds() {
assertErrorMessage(() => int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, outOfBound), WebAssembly.RuntimeError, /index out of bounds/);
}
+function testInvalidColumnIndex() {
+ // The bound checks above only cover the location of the colIndexList array,
+ // not the column indices it contains. Each index must be a valid column of B
+ // (< colsB); otherwise SelectColumnsB reads out of bounds of the input matrix
+ // and copies host memory into the output buffer.
+ let colIndex = new Uint32Array(memory.buffer);
+ let base = VALID.colIndexList >> 2;
+
+ for (let wild of [VALID.cols, 0x20000000, 0xffffffff]) {
+ for (let i = 0; i < VALID.sizeColIndexList; i++) colIndex[base + i] = 0;
+ colIndex[base + 3] = wild;
+ assertErrorMessage(() => int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, VALID.output), WebAssembly.RuntimeError, /index out of bounds/);
+ }
+
+ // Restore valid indices so the successful-call test below still passes.
+ for (let i = 0; i < VALID.sizeColIndexList; i++) colIndex[base + i] = 0;
+}
+
function testSuccessfulCall() {
// We just test that with valid arguments the intrinsic executes without any error
int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, VALID.output);
@@ -68,6 +86,7 @@ function testSuccessfulCall() {
testInvalidSize();
testInvalidAlignment();
testOutOfBounds();
+testInvalidColumnIndex();
testSuccessfulCall();
`
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js b/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
index dcdefa62947..ab5a57c0d20 100644
--- a/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
+++ b/js/src/jit-test/tests/wasm/builtin-modules/integer-gemm/I8SelectColumnsOfB.js
@@ -60,6 +60,24 @@ function testOutOfBounds() {
assertErrorMessage(() => int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, outOfBound), WebAssembly.RuntimeError, /index out of bounds/);
}
+function testInvalidColumnIndex() {
+ // The bound checks above only cover the location of the colIndexList array,
+ // not the column indices it contains. Each index must be a valid column of B
+ // (< colsB); otherwise SelectColumnsB reads out of bounds of the input matrix
+ // and copies host memory into the output buffer.
+ let colIndex = new Uint32Array(memory.buffer);
+ let base = VALID.colIndexList >> 2;
+
+ for (let wild of [VALID.cols, 0x20000000, 0xffffffff]) {
+ for (let i = 0; i < VALID.sizeColIndexList; i++) colIndex[base + i] = 0;
+ colIndex[base + 3] = wild;
+ assertErrorMessage(() => int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, VALID.output), WebAssembly.RuntimeError, /index out of bounds/);
+ }
+
+ // Restore valid indices so the successful-call test below still passes.
+ for (let i = 0; i < VALID.sizeColIndexList; i++) colIndex[base + i] = 0;
+}
+
function testSuccessfulCall() {
// We just test that with valid arguments the intrinsic executes without any error
int8_select_columns_of_b(VALID.input, VALID.rows, VALID.cols, VALID.colIndexList, VALID.sizeColIndexList, VALID.output);
@@ -68,6 +86,7 @@ function testSuccessfulCall() {
testInvalidSize();
testInvalidAlignment();
testOutOfBounds();
+testInvalidColumnIndex();
testSuccessfulCall();
`
Loading diff…
References
On This Page