
Reproduction of a WebAssembly use-after-free vulnerability in Mozilla's JavaScript engine, demonstrating a deterministic race condition and providing a controlled proof-of-concept.
A not fancy reproduction. The baseline required some fiddling here.
Mozilla describes this issue as a WebAssembly use-after-free. Public fix
9823b5c86ffa keeps the exact trapping wasm::Code alive in JitActivation.
The test performs a bad-signature cross-instance tail call. A Debugger unwind hook clears the table's last target reference and forces a shrinking GC while the engine handles the trap. Before entering the tail call, Wasm invokes a normal JavaScript import that prints the marker.
9b564f641a42: status 139 (SIGSEGV).9823b5c86ffa: prints PASS: trap handled after target release and
exits 0.poc-controlled.js expands the target's shared-stub allocation with 144
imports. Its stale throw continuation lands inside one of four executable
pages. A pre-created lazy-tier carrier embeds 6,000 unique SIMD constants in a
four-page optimized code segment. During exception unwind, GC releases the
target and synchronous tiering reuses that hole. A syscall runway every 64
bytes prints UAF NACHOS and invokes exit_group(0).
Run:
js --wasm-compiler=baseline+ion \
--setpref=wasm_lazy_tiering_level=9 \
--setpref=wasm_lazy_tiering_synchronous=true \
--more-compartments poc-controlled.js
Observed reliability on the source-built Linux x86-64 pre-fix shell: 3/3
runs printed the marker and exited 0. The matched fixed shell raises the normal
RuntimeError: indirect call signature mismatch and does not print it.
The controlled PoC uses shell-only Debugger and GC functions to make the race deterministic. It establishes native control in jsshell, not delivery from a web page or escape from the Firefox content sandbox.
Run with an equivalent debug shell:
js --wasm-compiler=baseline --more-compartments poc.js
This is lifetime regression evidence, not a memory primitive or exploit. The marker appears on both builds and does not result from the UAF.