Assertion failure: hasPrototype(key) in [@ js::wasm::Module::instantiateMemories] via cross-realm WebAssembly.Instance constructor
Categories
(Core :: JavaScript: WebAssembly, defect, P3)
Tracking
()
People
(Reporter: bugmon, Unassigned)
References
(Blocks 1 open bug)
Details
(Keywords: assertion, testcase)
Attachments
(4 files)
js::wasm::Module::instantiateMemories (WasmModule.cpp:540) fetches the exported-object prototypes with the non-creating GlobalObject::getPrototype(JSProto_WasmMemory), which requires the prototype to already exist in cx->realm(); because the wasm classes are DontDefineConstructor and GetPrototypeFromConstructor's cross-realm fallback resolves only JSProto_WasmInstance (linking proto.constructor to that realm's Instance constructor), script can reach WasmInstanceObject::construct in a realm where WasmMemory/Table/Global/Tag were never resolved. Calling Object.getPrototypeOf(Reflect.construct(WebAssembly.Instance, [mod], ntWithNonObjectPrototype)).constructor then hits Assertion failure: hasPrototype(key) at GlobalObject.h:421 in debug builds; in release the assert is compiled out and a null prototype is handed to WasmMemoryObject::create.
Exploit Chain
- Create a second realm
gwith newGlobal() and never touchg.WebAssembly, so none of the wasm classes are resolved there. - Create
nt = g.Function()and setnt.prototype = nullso GetPrototypeFromConstructor takes the cross-realm fallback branch. - Compile a module exporting a memory and call
Reflect.construct(WebAssembly.Instance, [mod], nt); GetPrototypeFromConstructor enters realm g and calls getOrCreatePrototype(JSProto_WasmInstance), resolving only WasmInstance there and linking proto.constructor to g's Instance constructor. - Read
Object.getPrototypeOf(inst).constructorto obtain realm g's WebAssembly.Instance constructor (verified distinct from the local one and an instance of g.Function). - Call
new GInstance(mod); WasmInstanceObject::construct runs Module::instantiate in realm g, and instantiateMemories calls getPrototype(JSProto_WasmMemory) on a realm where that prototype was never created, failing MOZ_ASSERT(hasPrototype(key)) at GlobalObject.h:421.
Affected Code
- js/src/vm/GlobalObject.h, line 417-423
- js/src/wasm/WasmModule.cpp, line 540-543
- js/src/vm/JSObject.cpp, line 826-839
- js/src/vm/GlobalObject.cpp, line 407-409
- js/src/wasm/WasmJS.cpp, line 2496-2510
- js/src/wasm/WasmJS.cpp, line 2265-2274
Steps to Reproduce
- Build the SpiderMonkey debug shell with /app/mozconfigs/mozconfig.js.linux.debug from an unmodified tree (build_dir /firefox/obj-js-debug).
- Run wasm_instance_unresolved_realm.js with js_shell_evaluator against /firefox/obj-js-debug/dist/bin/js (default --fuzzing-safe, no extra flags, no prefs, no patches).
- Observe
Assertion failure: hasPrototype(key), at /firefox/js/src/vm/GlobalObject.h:421with js::wasm::Module::instantiateMemories (WasmModule.cpp:540) on the stack.
Security Impact
- Severity: Low
- Attacker capability: Script can obtain a realm's WebAssembly.Instance constructor without that realm's other wasm prototypes existing and drive Module::instantiate into a state the engine asserts is impossible. In debug builds this is an assertion abort; from the source, release builds would create exported WasmMemory/Table/Global/Tag objects with a null pointer as their prototype. No memory corruption was demonstrated.
- Preconditions: Access to two realms (newGlobal() in the shell; cross-origin/same-origin frames would be the browser analogue, not tested here) and the ability to call Reflect.construct with a foreign-realm newTarget whose .prototype is a non-object.
The full analysis report is attached (analysis.md).
| Reporter | ||
Comment 1•2 months ago
|
||
| Reporter | ||
Comment 2•2 months ago
|
||
| Reporter | ||
Comment 3•2 months ago
|
||
| Reporter | ||
Comment 4•2 months ago
|
||
Comment 5•2 months ago
|
||
This bug was filed automatically by an AI-powered security testing tool. The analysis, testcase, and any suggested patches were generated by an AI model and have NOT been verified by a human.
Please review all details carefully before triaging. The issue was confirmed by an independent verifier, but for non-ASAN issues, the verifier has been made less strict. Additionally, the root cause analysis and suggested fix may contain errors.
Updated•2 months ago
|
Updated•2 months ago
|
Comment 6•2 months ago
|
||
In release builds this results in an object with null proto.
Updated•2 months ago
|
Comment 7•2 months ago
|
||
The component has been changed since the backlog priority was decided, so we're resetting it.
For more information, please visit BugBot documentation.
Updated•2 months ago
|
Description
•