Closed Bug 2013573 (CVE-2026-4723) Opened 8 months ago Closed 8 months ago

AddressSanitizer: heap-use-after-free [@ operator bool] with READ of size 8 with ErrorReportBuilder and nukeCCW

Categories

(Core :: JavaScript Engine, defect, P1)

x86_64
Linux
defect

Tracking

()

VERIFIED FIXED
149 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr140 --- wontfix
firefox147 --- wontfix
firefox148 --- wontfix
firefox149 + verified

People

(Reporter: decoder, Assigned: jandem)

References

Details

(8 keywords, Whiteboard: [bugmon:update,bisected,confirmed][adv-main149+])

Attachments

(2 files, 1 external file)

The following testcase crashes on mozilla-central revision 20260130-20b1a1e6c530 (fuzzing-asan-opt build, run with --fuzzing-safe --no-threads):

See attachment.

Backtrace:

=================================================================
==1738598==ERROR: AddressSanitizer: heap-use-after-free on address 0x6f3b743e28d0 at pc 0x5d17680bec81 bp 0x7ffdc3ee2e00 sp 0x7ffdc3ee2df8
READ of size 8 at 0x6f3b743e28d0 thread T0
    #0 0x5d17680bec80 in operator bool /builds/worker/workspace/obj-build/dist/include/js/CharacterEncoding.h:164:43
    #1 0x5d17680bec80 in JSErrorBase::newMessageString(JSContext*) /js/src/jsapi.cpp:4153:8
    #2 0x5d1769fa9ac9 in ErrorReportToString /js/src/vm/ErrorObject.cpp:1495:24
    #3 0x5d1769fa9ac9 in JS::ErrorReportBuilder::init(JSContext*, JS::ExceptionStack const&, JS::ErrorReportBuilder::SniffingBehavior) /js/src/vm/ErrorObject.cpp:1585:11
    #4 0x5d1767eacc26 in _ZZN2js5shell19AutoReportExceptionD1EvENK3$_0clIN2JS18ErrorReportBuilderENS4_14ExceptionStackEEEDaP9JSContextRT_RKT0_PKc /js/src/shell/js.cpp:11198:17
    #5 0x5d1767eac3f2 in js::shell::AutoReportException::~AutoReportException() /js/src/shell/js.cpp:11243:8
    #6 0x5d1767ec5efc in Shell(JSContext*, js::cli::OptionParser*) /js/src/shell/js.cpp:12366:5
    #7 0x5d1767eaeee7 in main /js/src/shell/js.cpp:12769:12
    #8 0x728b7502a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #9 0x728b7502a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #10 0x5d1767db61f8 in _start (/home/decoder/Mozilla/Anthropic/.builds/asan/js/dist/bin/js+0x2d201f8) (BuildId: b9b60630d05b45547bce8211e76c23e091144ce3)

0x6f3b743e28d0 is located 0 bytes inside of 110-byte region [0x6f3b743e28d0,0x6f3b743e293e)
freed by thread T0 here:
    #0 0x5d1767e572f6 in free /builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:51:3
    #1 0x5d1768b75d51 in doFinalize /builds/worker/workspace/obj-build/dist/include/js/Class.h:663:5
    #2 0x5d1768b75d51 in finalize /js/src/vm/JSObject-inl.h:90:10
    #3 0x5d1768b75d51 in unsigned long js::gc::Arena::finalize<JSObject, (js::gc::FinalizeKind)2>(JS::GCContext*, js::gc::AllocKind, unsigned long) /js/src/gc/Sweeping.cpp:162:12
    #4 0x5d1768b7ea0a in bool FinalizeTypedArenas<JSObject, (js::gc::FinalizeKind)1, (js::gc::ReleaseEmpty)0>(JS::GCContext*, js::gc::ArenaList&, js::gc::SortedArenaList&, js::gc::AllocKind, JS::SliceBudget&) /js/src/gc/Sweeping.cpp:220:16
    #5 0x5d1768b1fcd8 in void js::gc::ArenaLists::backgroundFinalize<(js::gc::ReleaseEmpty)0>(JS::GCContext*, js::gc::AllocKind, js::gc::Arena**) /js/src/gc/Sweeping.cpp:314:3
    #6 0x5d1768b1f96e in js::gc::GCRuntime::sweepBackgroundThings(js::gc::ZoneList&) /js/src/gc/Sweeping.cpp:395:18
    #7 0x5d1768b2145b in js::gc::GCRuntime::sweepFromBackgroundThread(js::AutoLockHelperThreadState&) /js/src/gc/Sweeping.cpp:527:5
    #8 0x5d1768a8e7d8 in js::GCParallelTask::runTask(JS::GCContext*, js::AutoLockHelperThreadState&) /js/src/gc/GCParallelTask.cpp:218:3
    #9 0x5d1768a5fca7 in runFromMainThread /js/src/gc/GCParallelTask.cpp:174:3
    #10 0x5d1768a5fca7 in js::GCParallelTask::runFromMainThread() /js/src/gc/GCParallelTask.cpp:161:3
    #11 0x5d1768b20ff2 in js::gc::GCRuntime::queueZonesAndStartBackgroundSweep(js::gc::ZoneList&&) /js/src/gc/Sweeping.cpp:510:15
    #12 0x5d1768b30645 in js::gc::GCRuntime::endSweepingSweepGroup(JS::GCContext*, JS::SliceBudget&) /js/src/gc/Sweeping.cpp:1853:3
    #13 0x5d1768b7fe37 in sweepaction::SweepActionSequence::run(js::gc::SweepAction::Args&) /js/src/gc/Sweeping.cpp:2348:23
    #14 0x5d1768b67f97 in sweepaction::SweepActionForEach<js::gc::SweepGroupsIter, JSRuntime*>::run(js::gc::SweepAction::Args&) /js/src/gc/Sweeping.cpp:2383:19
    #15 0x5d1768b3bd6e in js::gc::GCRuntime::performSweepActions(JS::SliceBudget&) /js/src/gc/Sweeping.cpp:2567:53
    #16 0x5d1768a78f93 in js::gc::GCRuntime::incrementalSlice(JS::SliceBudget&, JS::GCReason, bool) /js/src/gc/GC.cpp:4081:11
    #17 0x5d1768a7e0a5 in js::gc::GCRuntime::gcCycle(bool, JS::SliceBudget const&, JS::GCReason) /js/src/gc/GC.cpp:4634:3
    #18 0x5d1768a7fb3d in js::gc::GCRuntime::collect(bool, JS::SliceBudget const&, JS::GCReason) /js/src/gc/GC.cpp:4823:9
    #19 0x5d1768a5ea5e in js::gc::GCRuntime::gc(JS::GCOptions, JS::GCReason) /js/src/gc/GC.cpp:4903:3
    #20 0x5d1768a04520 in js::gc::GCRuntime::attemptLastDitchGC() /js/src/gc/Allocator.cpp:250:3
    #21 0x5d1768a043f9 in js::gc::CellAllocator::RetryTenuredAlloc(JS::Zone*, js::gc::AllocKind) /js/src/gc/Allocator.cpp:228:15
    #22 0x5d17680eed65 in NewObject<js::NativeObject, (js::AllowGC)1> /js/src/gc/Allocator-inl.h:112:16
    #23 0x5d17680eed65 in NewCell<js::NativeObject, (js::AllowGC)1, js::gc::AllocKind &, js::gc::Heap &, const JSClass *&, js::gc::AllocSite *&> /js/src/gc/Allocator-inl.h:35:12
    #24 0x5d17680eed65 in newCell<js::NativeObject, (js::AllowGC)1, js::gc::AllocKind &, js::gc::Heap &, const JSClass *&, js::gc::AllocSite *&> /js/src/vm/JSContext-inl.h:379:10
    #25 0x5d17680eed65 in js::NativeObject::create(JSContext*, js::gc::AllocKind, js::gc::Heap, JS::Handle<js::SharedShape*>, js::gc::AllocSite*) /js/src/vm/NativeObject-inl.h:482:28
    #26 0x5d176a099828 in NewObject /js/src/vm/JSObject.cpp:764:23
    #27 0x5d176a099828 in js::NewObjectWithGivenTaggedProto(JSContext*, JSClass const*, JS::Handle<js::TaggedProto>, js::gc::AllocKind, js::NewObjectKind, js::EnumFlags<js::ObjectFlag>) /js/src/vm/JSObject.cpp:776:10
    #28 0x5d1769fa21dc in NewObjectWithGivenTaggedProto<(js::NewObjectKind)0> /js/src/vm/JSObject-inl.h:346:10
    #29 0x5d1769fa21dc in NewObjectWithGivenProto /js/src/vm/JSObject-inl.h:381:10
    #30 0x5d1769fa21dc in js::ErrorObject::create(JSContext*, JSExnType, JS::Handle<JSObject*>, JS::Handle<JSString*>, unsigned int, unsigned int, JS::ColumnNumberOneOrigin, std::unique_ptr<JSErrorReport, JS::DeletePolicy<JSErrorReport>>, JS::Handle<JSString*>, JS::Handle<mozilla::Maybe<JS::Value>>, JS::Handle<JSObject*>) /js/src/vm/ErrorObject.cpp:671:21
    #31 0x5d1769fa7d72 in js::ErrorToException(JSContext*, JSErrorReport*, JSErrorFormatString const* (*)(void*, unsigned int), void*) /js/src/vm/ErrorObject.cpp:1374:7
    #32 0x5d1769fb0726 in ReportError /js/src/vm/ErrorReporting.cpp:175:10
    #33 0x5d1769fb0726 in js::ReportErrorNumberVA(JSContext*, js::IsWarning, JSErrorFormatString const* (*)(void*, unsigned int), void*, unsigned int, js::ErrorArgumentsType, __va_list_tag*) /js/src/vm/ErrorReporting.cpp:489:8
    #34 0x5d176809dc62 in JS_ReportErrorNumberASCIIVA /js/src/jsapi.cpp:3904:3
    #35 0x5d176809dc62 in JS_ReportErrorNumberASCII(JSContext*, JSErrorFormatString const* (*)(void*, unsigned int), void*, unsigned int, ...) /js/src/jsapi.cpp:3894:3
    #36 0x5d1769b6a86b in ReportDead /js/src/proxy/DeadObjectProxy.cpp:22:3
    #37 0x5d1769b6a86b in js::DeadObjectProxy::regexp_toShared(JSContext*, JS::Handle<JSObject*>) const /js/src/proxy/DeadObjectProxy.cpp:28:3
    #38 0x5d1769b5decf in js::BaseProxyHandler::get(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::Handle<JS::PropertyKey>, JS::MutableHandle<JS::Value>) const /js/src/proxy/BaseProxyHandler.cpp:88:8
    #39 0x5d1769b6fde2 in getInternal /js/src/proxy/Proxy.cpp:524:19
    #40 0x5d1769b6fde2 in js::Proxy::get(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::Handle<JS::PropertyKey>, JS::MutableHandle<JS::Value>) /js/src/proxy/Proxy.cpp:532:10
    #41 0x5d1767f452e8 in GetProperty /js/src/vm/ObjectOperations-inl.h:110:12
    #42 0x5d1767f452e8 in GetProperty /js/src/vm/ObjectOperations-inl.h:120:10
    #43 0x5d1767f452e8 in js::GetProperty(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSObject*>, js::PropertyName*, JS::MutableHandle<JS::Value>) /js/src/vm/ObjectOperations-inl.h:134:10
    #44 0x5d1769fa9a95 in GetPropertyNoException /js/src/vm/ErrorObject.cpp:1437:12
    #45 0x5d1769fa9a95 in ErrorReportToString /js/src/vm/ErrorObject.cpp:1488:7
    #46 0x5d1769fa9a95 in JS::ErrorReportBuilder::init(JSContext*, JS::ExceptionStack const&, JS::ErrorReportBuilder::SniffingBehavior) /js/src/vm/ErrorObject.cpp:1585:11

previously allocated by thread T0 here:
    #0 0x5d1767e576b9 in calloc /builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:74:3
    #1 0x5d1768504484 in js_arena_calloc /builds/worker/workspace/obj-build/dist/include/js/Utility.h:403:10
    #2 0x5d1768504484 in js_pod_arena_calloc<unsigned char> /builds/worker/workspace/obj-build/dist/include/js/Utility.h:616:26
    #3 0x5d1768504484 in maybe_pod_arena_calloc<unsigned char> /js/src/vm/MallocProvider.h:66:12
    #4 0x5d1768504484 in unsigned char* js::MallocProvider<JSContext>::pod_arena_calloc<unsigned char>(unsigned long, unsigned long) /js/src/vm/MallocProvider.h:163:12
    #5 0x5d1769fa3233 in pod_calloc<unsigned char> /js/src/vm/MallocProvider.h:181:12
    #6 0x5d1769fa3233 in CopyErrorHelper<JSErrorReport> /js/src/vm/ErrorObject.cpp:1185:25
    #7 0x5d1769fa3233 in js::CopyErrorReport(JSContext*, JSErrorReport*) /js/src/vm/ErrorObject.cpp:1230:10
    #8 0x5d1769fa2dd9 in js::ErrorObject::getOrCreateErrorReport(JSContext*) /js/src/vm/ErrorObject.cpp:727:35
    #9 0x5d1769fa7391 in js::ErrorFromException(JSContext*, JS::Handle<JSObject*>) /js/src/vm/ErrorObject.cpp:1279:50
    #10 0x5d1769fa948f in JS::ErrorReportBuilder::init(JSContext*, JS::ExceptionStack const&, JS::ErrorReportBuilder::SniffingBehavior) /js/src/vm/ErrorObject.cpp:1573:15
    #11 0x5d1767eacc26 in _ZZN2js5shell19AutoReportExceptionD1EvENK3$_0clIN2JS18ErrorReportBuilderENS4_14ExceptionStackEEEDaP9JSContextRT_RKT0_PKc /js/src/shell/js.cpp:11198:17
    #12 0x5d1767eac3f2 in js::shell::AutoReportException::~AutoReportException() /js/src/shell/js.cpp:11243:8
    #13 0x5d1767ec5efc in Shell(JSContext*, js::cli::OptionParser*) /js/src/shell/js.cpp:12366:5
    #14 0x5d1767eaeee7 in main /js/src/shell/js.cpp:12769:12
    #15 0x728b7502a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #16 0x728b7502a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #17 0x5d1767db61f8 in _start (/home/decoder/Mozilla/Anthropic/.builds/asan/js/dist/bin/js+0x2d201f8) (BuildId: b9b60630d05b45547bce8211e76c23e091144ce3)

SUMMARY: AddressSanitizer: heap-use-after-free /builds/worker/workspace/obj-build/dist/include/js/CharacterEncoding.h:164:43 in operator bool
Shadow bytes around the buggy address:
  0x6f3b743e2600: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 07 fa
  0x6f3b743e2680: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x6f3b743e2700: fd fd fd fd fd fd fa fa fa fa fa fa fa fa fd fd
  0x6f3b743e2780: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x6f3b743e2800: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
=>0x6f3b743e2880: fd fd fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd
  0x6f3b743e2900: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x6f3b743e2980: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
  0x6f3b743e2a00: fa fa fa fa fa fa fd fd fd fd fd fd fd fd fd fd
  0x6f3b743e2a80: fd fd fd fa fa fa fa fa fa fa fa fa 00 00 00 00
  0x6f3b743e2b00: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1738598==ABORTING

This bug is part of a series of bugs reported by Anthropic, thank you for your contributions to Firefox!

Attached file Testcase —
Flags: needinfo?(jdemooij)

Verified bug as reproducible on mozilla-central 20260130092147-20b1a1e6c530.
Unable to bisect testcase (Testcase reproduces on start build!):

Start: d0c1a4b1cb725aaff109054e060729eb71099baf (20251102212929)
End: 20b1a1e6c530f3506d5378bf5f4da504b6f03661 (20260130092147)
BuildFlags: BuildFlags(asan=True, tsan=False, debug=False, fuzzing=True, coverage=False, valgrind=False, no_opt=False, fuzzilli=False, nyx=False, searchfox=False, afl=False)

Whiteboard: [bugmon:update,bisect] → [bugmon:update,bisected,confirmed]
See Also: → 2013540

This is another nukeCCW test case. In the browser, I think the source of always chrome and the target is always content, which mitigates things a bit, but this specific case all that the "chrome" JS is doing is getting a reference to a "content" error and throwing it. That seems kind of plausible that some chrome JS might do that. The "content" JS is the part doing all of the fancy weird stuff. I'm not sure if that's enough to raise this to sec-high but maybe.

Keywords: csectype-uaf

jandem pointed out that in the case of chrome JS running this, X-ray wrappers would keep it from accessing the fake name property, so the chrome JS would have to waive the wrappers or something. I think this can be sec-moderate then, though maybe even that is an overestimate.

Keywords: sec-moderate
Severity: -- → S3
Priority: -- → P1
Assignee: nobody → jdemooij
Status: NEW → ASSIGNED
Attached file (secure) —

This adds a JS::BorrowedErrorReport type and uses it for ErrorFromException
and JS_ErrorFromException. This avoids problems with CCW nuking because
BorrowedErrorReport roots the wrapper's target object instead of the CCW.

Flags: needinfo?(jdemooij)
Group: javascript-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 8 months ago
Resolution: --- → FIXED
Target Milestone: --- → 149 Branch

The bot should request uplifts tomorrow.
This doesn't graft cleanly to ESR115/ESR140, so we will need rebased patches for uplift if needed there

Verified bug as fixed on rev mozilla-central 20260204214433-73cbf17ce89d.
Removing bugmon keyword as no further action possible. Please review the bug and re-add the keyword for further analysis.

Status: RESOLVED → VERIFIED
Keywords: bugmon

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 can ride the trains. Also not trivial to uplift because there have been some code changes affecting this.

Whiteboard: [bugmon:update,bisected,confirmed] → [bugmon:update,bisected,confirmed][adv-main149+r]
Whiteboard: [bugmon:update,bisected,confirmed][adv-main149+r] → [bugmon:update,bisected,confirmed][adv-main149+]
Alias: CVE-2026-4723
Group: core-security-release
Keywords: keep-hidden
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: