Closed Bug 1860721 Opened 1 year ago Closed 1 year ago

Spidermonkey: SEGV in /js/src/vm/JSFunction.h:459:5 in JSFunction::nonLazyScript() const

Categories

(Core :: JavaScript Engine, defect, P2)

defect

Tracking

()

RESOLVED FIXED
121 Branch
Tracking Status
firefox121 --- fixed

People

(Reporter: baksmali404, Assigned: arai)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

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

Steps to reproduce:

version:master

$ git clone https://github.com/mozilla/gecko-dev
$ cd gecko-dev
$ git show
commit 81f368dab93fff035ce7fcc376e16990e89dd5ec (HEAD -> master, origin/master, origin/HEAD)
Author: Robert Longson <longsonr@gmail.com>
Date:   Sun Oct 15 06:21:08 2023 +0000

Reproduce

./dist/bin/js pocfile.js

pocfile.js

const v0 = `
    function f1(a2, a3, a4) {
        try {
            h.getOwnPropertyDescriptor();
        } catch(e7) {
            try {
                b.catch();
            } catch(e10) {
                this.relazifyFunctions();
            }
        }
        return a3;
    }
    function f14(a15, a16) {
        try {
            f();
        } catch(e20) {
        }
        try {
            MAX_VALUE.catch(MAX_VALUE, search);
        } catch(e23) {
        }
        const v24 = \`
            function f25(a26, a27) {
                return Map;
            }
            Promise.race().catch(f25);
        \`;
        const o31 = {
        };
        const v33 = new Map(a15);
        Object.defineProperty(v33, "sameZoneAs", { enumerable: true, value: o31 });
        const v34 = v33.set();
        const t33 = this.newGlobal(v34).Debugger;
        t33(v34).getNewestFrame().eval(v24);
        try {
            h.freeze(v0, f, h, Map);
        } catch(e43) {
            try {
                b.catch(f, a15);
            } catch(e46) {
            }
        }
        return v0;
    }
    const v48 = new Set();
    const v49 = v48.add();
    this.wrapWithProto(v49, v49).forEach(f14);
    try {
        f();
    } catch(e55) {
    }
    [f1,f1];
`;
const v58 = eval(v0);
const v60 = new SharedArrayBuffer();
try {
    ("d").concat(v60, f);
} catch(e64) {
}
for (const v66 of eval(v58)) {
    v66();
}
// CRASH INFO
// ==========
// TERMSIG: 11
// STDERR:
// Assertion failure: hasBytecode(), at /home/user/fuzz/gecko-dev/js/src/vm/JSFunction.h:459
// #01: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x3283a16]
// #02: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x32efc05]
// #03: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x40b758b]
// #04: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x40c5ac2]
// #05: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x3547da1]
// #06: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x354adee]
// #07: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2e7afce]
// #08: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2e09bbf]
// #09: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de155e]
// #10: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de0938]
// #11: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de2d65]
// #12: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de7654]
// #13: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2f9a635]
// #14: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x37d9602]
// #15: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de4a3b]
// #16: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de2fc1]
// #17: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2de7654]
// #18: JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>)[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x31a650b]
// #19: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x344e68c]
// #20: js::RunJobs(JSContext*)[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x344d426]
// #21: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2b69f3a]
// #22: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2b3efcb]
// #23: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2b31feb]
// #24: ???[/lib/x86_64-linux-gnu/libc.so.6 +0x29d90]
// #25: __libc_start_main[/lib/x86_64-linux-gnu/libc.so.6 +0x29e40]
// #26: ???[/home/user/fuzz/gecko-dev/obj-fuzzbuild/dist/bin/js +0x2a37319]
// #27: ??? (???:???)
// STDOUT:
// 
// ARGS: /home/user/fuzz/gecko-dev/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
// EXECUTION TIME: 242ms
gc();

Actual results:

asan report

Assertion failure: hasBytecode(), at /home/user/fuzz/gecko-dev/js/src/vm/JSFunction.h:459
#01: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x31ab42b]
#02: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x31f9582]
#03: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x3e32002]
#04: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x3e3ba93]
#05: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x341e590]
#06: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x3420fdc]
#07: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2e1dc83]
#08: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2dbb180]
#09: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d932af]
#10: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d923d7]
#11: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d94393]
#12: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d96f4e]
#13: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2fe312f]
#14: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x365fafc]
#15: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2df94bf]
#16: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d94567]
#17: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2d96f4e]
#18: JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>)[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x30ea20a]
#19: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x333627d]
#20: js::RunJobs(JSContext*)[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x33354de]
#21: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2b28eca]
#22: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2afe9ff]
#23: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x2af21ab]
#24: ???[/lib/x86_64-linux-gnu/libc.so.6 +0x29d90]
#25: __libc_start_main[/lib/x86_64-linux-gnu/libc.so.6 +0x29e40]
#26: ???[/home/user/fuzz/gecko-dev/build_asan/dist/bin/js +0x29f7749]
#27: ??? (???:???)
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3112757==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55cfbee77460 bp 0x7ffead6518b0 sp 0x7ffead651890 T0)
==3112757==The signal is caused by a WRITE memory access.
==3112757==Hint: address points to the zero page.
    #0 0x55cfbee77460 in JSFunction::nonLazyScript() const /home/user/fuzz/gecko-dev/js/src/vm/JSFunction.h:459:5
    #1 0x55cfbee77460 in (anonymous namespace)::DebugEnvironmentProxyHandler::getEnvironmentScope(JSObject const&) /home/user/fuzz/gecko-dev/js/src/vm/EnvironmentObject.cpp:1859:44
    #2 0x55cfbeec5581 in (anonymous namespace)::DebugEnvironmentProxyHandler::has(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::PropertyKey>, bool*) const /home/user/fuzz/gecko-dev/js/src/vm/EnvironmentObject.cpp:2396:26
    #3 0x55cfbfafe001 in js::Proxy::has(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::PropertyKey>, bool*) /home/user/fuzz/gecko-dev/js/src/proxy/Proxy.cpp:419:19
    #4 0x55cfbfb07a92 in proxy_LookupProperty(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::PropertyKey>, JS::MutableHandle<JSObject*>, js::PropertyResult*) /home/user/fuzz/gecko-dev/js/src/proxy/Proxy.cpp:842:8
    #5 0x55cfbf0ea58f in js::LookupProperty(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::PropertyKey>, JS::MutableHandle<JSObject*>, js::PropertyResult*) /home/user/fuzz/gecko-dev/js/src/vm/JSObject.cpp:1559:12
    #6 0x55cfbf0ecfdb in js::LookupName(JSContext*, JS::Handle<js::PropertyName*>, JS::Handle<JSObject*>, JS::MutableHandle<JSObject*>, JS::MutableHandle<JSObject*>, js::PropertyResult*) /home/user/fuzz/gecko-dev/js/src/vm/JSObject.cpp:1571:10
    #7 0x55cfbeae9c82 in bool js::GetEnvironmentName<(js::GetNameMode)0>(JSContext*, JS::Handle<JSObject*>, JS::Handle<js::PropertyName*>, JS::MutableHandle<JS::Value>) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter-inl.h:187:8
    #8 0x55cfbea8717f in GetNameOperation(JSContext*, JS::Handle<JSObject*>, JS::Handle<js::PropertyName*>, JSOp, JS::MutableHandle<JS::Value>) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:255:10
    #9 0x55cfbea8717f in js::Interpret(JSContext*, js::RunState&) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:3539:12
    #10 0x55cfbea5f2ae in MaybeEnterInterpreterTrampoline(JSContext*, js::RunState&) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:400:10
    #11 0x55cfbea5e3d6 in js::RunScript(JSContext*, js::RunState&) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:458:13
    #12 0x55cfbea60392 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:612:13
    #13 0x55cfbea62f4d in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>, js::CallReason) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:679:8
    #14 0x55cfbecaf12e in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::MutableHandle<JS::Value>) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.h:116:10
    #15 0x55cfbf32bafb in PromiseReactionJob(JSContext*, unsigned int, JS::Value*) /home/user/fuzz/gecko-dev/js/src/builtin/Promise.cpp:2244:10
    #16 0x55cfbeac54be in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:486:13
    #17 0x55cfbea60566 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:580:12
    #18 0x55cfbea62f4d in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>, js::CallReason) /home/user/fuzz/gecko-dev/js/src/vm/Interpreter.cpp:679:8
    #19 0x55cfbedb6209 in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /home/user/fuzz/gecko-dev/js/src/vm/CallAndConstruct.cpp:119:10
    #20 0x55cfbf00227c in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JSObject*>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /home/user/fuzz/gecko-dev/build_asan/dist/include/js/CallAndConstruct.h:110:10
    #21 0x55cfbf00227c in js::InternalJobQueue::runJobs(JSContext*) /home/user/fuzz/gecko-dev/js/src/vm/JSContext.cpp:865:14
    #22 0x55cfbf0014dd in js::RunJobs(JSContext*) /home/user/fuzz/gecko-dev/js/src/vm/JSContext.cpp:802:17
    #23 0x55cfbe7f4ec9 in RunShellJobs(JSContext*) /home/user/fuzz/gecko-dev/js/src/shell/js.cpp:1315:5
    #24 0x55cfbe7ca9fe in Shell(JSContext*, js::cli::OptionParser*) /home/user/fuzz/gecko-dev/js/src/shell/js.cpp:11146:5
    #25 0x55cfbe7be1aa in main /home/user/fuzz/gecko-dev/js/src/shell/js.cpp:11544:12
    #26 0x7fa4fb029d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #27 0x7fa4fb029e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #28 0x55cfbe6c3748 in _start (/home/user/fuzz/gecko-dev/build_asan/dist/bin/js+0x29f7748) (BuildId: 20aa5237808bfe587005c363369aaac4)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/user/fuzz/gecko-dev/js/src/vm/JSFunction.h:459:5 in JSFunction::nonLazyScript() const
==3112757==ABORTING

Expected results:

SEGV or crash

The Bugbug bot thinks this bug should belong to the 'Core::JavaScript Engine' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → JavaScript Engine
Product: Firefox → Core

I was able to reproduce the assertion failure in a non ASAN build.
I will investigate deeper to better triage it.

Blocks: sm-security
Severity: -- → S4
Flags: needinfo?(nicolas.b.pierron)
Priority: -- → P2

Ok, getting a bit of time to investigate, the problem seems to be related with the Debugger, not being investigated as a root when GC-ing.
The failing stack is:

#0  JSFunction::hasBytecode (this=0x9b8be666cf0) at …/js/src/vm/JSFunction.h:216
#1  0x00005615099a320c in JSFunction::nonLazyScript (this=0x9b8be666cf0) at …/js/src/vm/JSFunction.h:459
#2  0x0000561509cbefca in (anonymous namespace)::DebugEnvironmentProxyHandler::getEnvironmentScope (env=...) at …/js/src/vm/EnvironmentObject.cpp:1850
#3  0x0000561509cc13aa in (anonymous namespace)::DebugEnvironmentProxyHandler::has (this=0x56150d1270f0 <(anonymous namespace)::DebugEnvironmentProxyHandler::singleton>, cx=0x56150dcdae80, proxy=..., id_=..., bp=0x7fff17f9956f)
    at …/js/src/vm/EnvironmentObject.cpp:2370
#4  0x000056150a1bdf3d in js::Proxy::has (cx=0x56150dcdae80, proxy=..., id=..., bp=0x7fff17f9956f) at …/js/src/proxy/Proxy.cpp:420
#5  0x000056150a1bfad9 in proxy_LookupProperty (cx=0x56150dcdae80, obj=..., id=..., objp=..., propp=0x7fff17f996b0) at …/js/src/proxy/Proxy.cpp:843
#6  0x0000561509db61d3 in js::LookupProperty (cx=0x56150dcdae80, obj=..., id=..., objp=..., propp=0x7fff17f996b0) at …/js/src/vm/JSObject.cpp:1572
#7  0x0000561509db62dd in js::LookupName (cx=0x56150dcdae80, name=..., envChain=..., objp=..., pobjp=..., propp=0x7fff17f996b0) at …/js/src/vm/JSObject.cpp:1584
#8  0x0000561509b56b44 in js::GetEnvironmentName<(js::GetNameMode)0> (cx=0x56150dcdae80, envChain=..., name=..., vp=...) at …/js/src/vm/Interpreter-inl.h:186
#9  0x000056150a7258b5 in js::jit::DoGetNameFallback (cx=0x56150dcdae80, frame=0x7fff17f99828, stub=0x56150ddb4ef8, envChain=..., res=...) at …/js/src/jit/BaselineIC.cpp:1142

The sharedData_ field is null which makes the hasBytecode() function return false. The sharedData_ field is nullified at the following stack prior:

#0  0x0000561509dfe2af in RefPtr<js::SharedImmutableScriptData>::assign_assuming_AddRef (this=0x9b8be66d148, aNewPtr=0x0) at …/dist/include/mozilla/RefPtr.h:71
#1  0x0000561509def00b in RefPtr<js::SharedImmutableScriptData>::operator=(decltype(nullptr)) (this=0x9b8be66d148) at …/dist/include/mozilla/RefPtr.h:188
#2  0x0000561509de5fe7 in js::BaseScript::freeSharedData (this=0x9b8be66d100) at …/js/src/vm/JSScript.h:1592
#3  0x0000561509dc5a41 in JSScript::relazify (this=0x9b8be66d100, rt=0x56150dce4950) at …/js/src/vm/JSScript.cpp:2141
#4  0x0000561509d6dd67 in JSFunction::maybeRelazify (this=0x9b8be666cf0, rt=0x56150dce4950) at …/js/src/vm/JSFunction.cpp:1168
#5  0x000056150a554cf1 in RelazifyFunctions (zone=0x56150dd6b260, kind=js::gc::AllocKind::FUNCTION) at …/js/src/gc/GC.cpp:2439
#6  0x000056150a555382 in js::gc::GCRuntime::relazifyFunctionsForShrinkingGC (this=0x56150dce5078) at …/js/src/gc/GC.cpp:2547
#7  0x000056150a5563ea in js::gc::GCRuntime::endPreparePhase (this=0x56150dce5078, reason=JS::GCReason::API) at …/js/src/gc/GC.cpp:2763
#8  0x000056150a559e01 in js::gc::GCRuntime::incrementalSlice (this=0x56150dce5078, budget=..., reason=JS::GCReason::API, budgetWasIncreased=false) at …/js/src/gc/GC.cpp:3590
#9  0x000056150a55c0ef in js::gc::GCRuntime::gcCycle (this=0x56150dce5078, nonincrementalByAPI=true, budgetArg=..., reason=JS::GCReason::API) at …/js/src/gc/GC.cpp:4175
#10 0x000056150a55cba4 in js::gc::GCRuntime::collect (this=0x56150dce5078, nonincrementalByAPI=true, budget=..., reason=JS::GCReason::API) at …/js/src/gc/GC.cpp:4366
#11 0x000056150a55d03d in js::gc::GCRuntime::gc (this=0x56150dce5078, options=JS::GCOptions::Shrink, reason=JS::GCReason::API) at …/js/src/gc/GC.cpp:4443
#12 0x000056150a59d139 in JS::NonIncrementalGC (cx=0x56150dcdae80, options=JS::GCOptions::Shrink, reason=JS::GCReason::API) at …/js/src/gc/GCAPI.cpp:298
#13 0x000056150a0b23f1 in RelazifyFunctions (cx=0x56150dcdae80, argc=0, vp=0x7fff17f99ac0) at …/js/src/builtin/TestingFunctions.cpp:804

Jon, Arai, any idea what might be going wrong?
Is the relazifyFunctions function fuzzing safe?

Blocks: sm-meta
Flags: needinfo?(nicolas.b.pierron)
Flags: needinfo?(jcoppeard)
Flags: needinfo?(arai.unmht)
Status: UNCONFIRMED → NEW
Ever confirmed: true

The issue comes from that the dbg.getNewestFrame().eval creates inner function, but that's not propagated to the enclosing function's (f14) allowRelazify() value.

The value reflects whether there's inner function or direct eval, but it doesn't reflect the "eval in frame".
The debugger should update the flag when it evaluates script in frame.

Assignee: nobody → arai.unmht
Status: NEW → ASSIGNED
Flags: needinfo?(arai.unmht)
Flags: needinfo?(jcoppeard)
Pushed by arai_a@mac.com: https://hg.mozilla.org/integration/autoland/rev/c9b5f3d92c33 Prevent relazifying a function after performing debugger eval-in-frame in the function. r=nbp
Status: ASSIGNED → RESOLVED
Closed: 1 year ago
Resolution: --- → FIXED
Target Milestone: --- → 121 Branch

Credit:

Gandalf4a of PKU-Changsha Institute for Computing and Digital Economy

This issue can apply for a CVE number?

Thank you for your contribution.

This is not security sensitive issue, and less likely get CVE.

The issue requires Debugger interaction with special setup, which is not controllable from the web content side.
The testcase directly triggers the Debugger API (Debugger.getNewestFrame, Debugger.Frame.eval) and shell-only testing functions (relazifyFunctions, gc), thus this is not directly exploitable in the browser context.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: