Closed Bug 2039836 Opened 6 months ago Closed 5 months ago

Assertion failure: wrapper->is<WrapperObject>(), at js/src/proxy/Wrapper.cpp:287

Categories

(Core :: JavaScript Engine, defect, P2)

defect

Tracking

()

RESOLVED FIXED
153 Branch
Tracking Status
firefox-esr140 --- unaffected
firefox151 --- unaffected
firefox152 --- wontfix
firefox153 --- fixed

People

(Reporter: baksmali404, Assigned: jandem)

References

(Blocks 1 open bug, Regression)

Details

(Keywords: regression, reporter-external)

Attachments

(1 external file)

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0

Steps to reproduce:

A fuzzing-induced assertion failure (wrapper->is<WrapperObject>() at js/src/proxy/Wrapper.cpp:287) was discovered in SpiderMonkey. In release builds, this can result in type confusion and potential memory corruption, possibly leading to arbitrary read/write or remote code execution.

version:master

$ git clone https://github.com/mozilla/firefox
$ cd firefox
$ git show
commit ba5a17372ab9f91015127e66de86d14b26136f9e (HEAD -> main, origin/main, origin/HEAD)
Author: Norisz Fay <nfay@mozilla.com>
Date:   Tue May 12 05:26:06 2026 +0300
...

$ ./obj-fuzzbuild/dist/bin/js --version
[COV] no shared memory bitmap available, skipping
[COV] edge counters initialized. Shared memory: (null) with 514806 edges
JavaScript-C152.0a1

Reproduce

./dist/bin/js --fuzzing-safe pocfile.js

pocfile.js

this.nukeAllCCWs();
for (let i4 = 0, i5 = 10; i5; i5--) {
}
function f14() {
    return this;
}
f14.sameZoneAs = this;
f14.transplantWindowProxy = this;
this.newGlobal(f14);
gc();
// CRASH INFO
// ==========
// TERMSIG: 11
// STDERR:
// [1655602] Assertion failure: wrapper->is<WrapperObject>(), at js/src/proxy/Wrapper.cpp:287
// #01: js::Wrapper::wrappedObject(JSObject*)[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x318eb48]
// #02: JS_TransplantObject(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>)[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1d9b482]
// #03: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1ce635a]
// #04: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1cfcc67]
// #05: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b2b5f]
// #06: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b2343]
// #07: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31c76a2]
// #08: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b1473]
// #09: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b226c]
// #10: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x27bd9bd]
// #11: ??? (???:???)
// STDOUT:
// 
// FUZZER ARGS: ./.build/x86_64-unknown-linux-gnu/release/FuzzilliCli --profile=spidermonkey --storagePath=Targets/Spidermonkey/out --resume /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js
// TARGET ARGS: /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js --baseline-warmup-threshold=10 --ion-warmup-threshold=100 --ion-check-range-analysis --ion-extra-checks --fuzzing-safe --disable-oom-functions --reprl
// CONTRIBUTORS: ArrayGenerator, IntArrayGenerator, SpliceMutator, FloatGenerator, BigIntGenerator, ObjectConstructorGenerator, TrivialFunctionGenerator, IntegerGenerator, GrowableSharedArrayBufferGenerator
// EXECUTION TIME: 213ms

Actual results:

asan report

[1674261] Assertion failure: wrapper->is<WrapperObject>(), at js/src/proxy/Wrapper.cpp:287
#01: js::Wrapper::wrappedObject(JSObject*)[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x318eb48]
#02: JS_TransplantObject(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>)[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1d9b482]
#03: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1ce635a]
#04: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1cfcc67]
#05: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b2b5f]
#06: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x31b2343]
#07: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x27bd9bd]
#08: ??? (???:???)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==1674261==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5a120b77eb60 bp 0x7ffcbf339f40 sp 0x7ffcbf339f00 T1674261)
==1674261==The signal is caused by a WRITE memory access.
==1674261==Hint: address points to the zero page.
/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/llvm-symbolizer: error: '[anon:js-executable-memory]': No such file or directory
    #0 0x5a120b77eb60 in MOZ_CrashSequence(void*, long) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/include/mozilla/Assertions.h:261:3
    #1 0x5a120b77eb60 in js::Wrapper::wrappedObject(JSObject*) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/proxy/./../../../../js/src/proxy/Wrapper.cpp:287:3
    #2 0x5a120a38b481 in JS_TransplantObject(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/./../../../js/src/jsapi.cpp:720:5
    #3 0x5a120a2d6359 in NewGlobalObject(JSContext*, JS::RealmOptions&, JSPrincipals*, ShellGlobalKind, bool, JS::Handle<JSObject*>) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/shell/./../../../../js/src/shell/js.cpp:11784:17
    #4 0x5a120a2ecc66 in NewGlobal(JSContext*, unsigned int, JS::Value*) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/shell/./../../../../js/src/shell/js.cpp:7576:23
    #5 0x5a120b7a2b5e in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /home/gandalf/fuzz/fuzz_spm/firefox/js/src/vm/Interpreter.cpp:488:13
    #6 0x5a120b7a2342 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /home/gandalf/fuzz/fuzz_spm/firefox/js/src/vm/Interpreter.cpp:584:12
    #7 0x5a120adad9bc in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/jit/./../../../../js/src/jit/BaselineIC.cpp:1713:10
    #8 0x337b36fbac7e  ([anon:js-executable-memory]+0xbc7e)

==1674261==Register values:
rax = 0x0000000000000000  rbx = 0x00007fc3a2d36200  rcx = 0x000000000000011f  rdx = 0x00007fc3a3204563  
rdi = 0x00007fc3a3205700  rsi = 0x0000000000000000  rbp = 0x00007ffcbf339f40  rsp = 0x00007ffcbf339f00  
 r8 = 0x0000000000000000   r9 = 0x0000000000000003  r10 = 0x0000000000000002  r11 = 0x0000000000000293  
r12 = 0x00007fc3a2dce800  r13 = 0x00007ffcbf339fa0  r14 = 0x00003d3d68c00a98  r15 = 0x000018960b044040  
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/include/mozilla/Assertions.h:261:3 in MOZ_CrashSequence(void*, long)
==1674261==ABORTING

Expected results:

The function js::Wrapper::wrappedObject assumes the input object is always a WrapperObject. However, an object of a different type (plain JSObject, ProxyObject, or a freed object) can reach this code path. While debug builds catch this with an assertion, release builds remove the assertion and proceed with an unsafe downcast via as<WrapperObject>(), leading to misinterpretation of the object's memory layout.

Credit:

Gandalf4a 
Group: core-security → javascript-core-security

This is probably from the transplantWindowProxy support added in bug 2037348.

Likely shell-only but we should change more assertions in the transplant code to release assertions.

Keywords: regression
Regressed by: 2037348
Summary: Assertion failure: res_.isNumber(), at ./../../../../js/src/jit/CacheIR.cpp:15738 → Assertion failure: wrapper->is<WrapperObject>(), at js/src/proxy/Wrapper.cpp:287
Flags: needinfo?(jdemooij)
Blocks: sm-security
Severity: -- → S3
Priority: -- → P2
Group: javascript-core-security
Flags: needinfo?(jdemooij)

This matches the check in the TransplantObject shell function.

This patch also changes some assertions in JS_TransplantObject to release assertions
and fixes a potential re-entrancy issue with the transplantWindowProxy option.

Assignee: nobody → jdemooij
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

Set release status flags based on info from the regressing bug 2037348

Duplicate of this bug: 2041873
Pushed by imoraru@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/a8d162b57654 https://hg.mozilla.org/integration/autoland/rev/ba3700ccf54f Revert "Bug 2039836 - Handle nuked compartments for transplantWindowProxy option. r=jonco" for causing wpt failures on media_fragment_seek.html.
Status: ASSIGNED → RESOLVED
Closed: 5 months ago
Resolution: --- → FIXED
Target Milestone: --- → 153 Branch

The patch landed in nightly and beta is affected.
:jandem, is this bug important enough to require an uplift?

For more information, please visit BugBot documentation.

Flags: needinfo?(jdemooij)

This only affects the JS shell.

Flags: needinfo?(jdemooij)
Duplicate of this bug: 2044833
QA Whiteboard: [qa-triage-done-c154/b153]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: