Closed Bug 2010943 (CVE-2026-2783) Opened 8 months ago Closed 8 months ago

Assertion failure: payload->toStackSlot()->width() == LStackSlot::width(LDefinition::GENERAL), at jit/shared/CodeGenerator-shared.cpp:603

Categories

(Core :: JavaScript Engine: JIT, defect, P1)

defect

Tracking

()

RESOLVED FIXED
149 Branch
Tracking Status
firefox-esr115 --- unaffected
firefox-esr140 148+ fixed
firefox147 --- wontfix
firefox148 + fixed
firefox149 + fixed

People

(Reporter: x0e, Assigned: iain)

References

(Blocks 2 open bugs)

Details

(4 keywords, Whiteboard: [adv-main148+] [adv-esr140.8+])

Attachments

(4 files)

48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review

Steps to reproduce:

Steps to reproduce

Version: c081f3f7d21922047379fe76320cfbc3abf7f2b3 (2026-01-16)
Args: js --fuzzing-safe test.js

Test case:

try {
  for (;;) {
    function a() {
      a;
    }
    for (let b = 0; b < 5; b++) {
      new SharedArrayBuffer();
      a(BigInt.asUintN(64, BigInt(b)));
    }
  }
} catch {}

Actual results

[71353] Assertion failure: payload->toStackSlot()->width() == LStackSlot::width(LDefinition::GENERAL), at js/src/jit/shared/CodeGenerator-shared.cpp:603
#01: ???[dist/bin/js +0x2b50d23]
#02: ???[dist/bin/js +0x2b51cb5]
#03: ???[dist/bin/js +0x2bb41de]
#04: ???[dist/bin/js +0x2bb4140]
#05: ???[dist/bin/js +0x2e8d88a]
#06: ???[dist/bin/js +0x2e23865]
#07: ???[dist/bin/js +0x2e21a25]
#08: ???[dist/bin/js +0x2eeab02]
#09: ???[dist/bin/js +0x2fcb3fb]
#10: ???[dist/bin/js +0x301308e]
#11: ???[dist/bin/js +0x36594a6]
#12: ???[dist/bin/js +0x368b8fd]
#13: ???[dist/bin/js +0x368b518]
#14: ???[dist/bin/js +0x3699ca4]
#15: ???[/lib/x86_64-linux-gnu/libc.so.6 +0x9caa4]
#16: ???[/lib/x86_64-linux-gnu/libc.so.6 +0x129c6c]
#17: ??? (???:???)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==71353==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x58a8abc47d3b bp 0x774bd99fe540 sp 0x774bd99fe4d0 T71355)
==71353==The signal is caused by a WRITE memory access.
==71353==Hint: address points to the zero page.
    #0 0x58a8abc47d3b in MOZ_CrashSequence(void*, long) dist/include/mozilla/Assertions.h:237:3
    #1 0x58a8abc47d3b in js::jit::CodeGeneratorShared::encodeAllocation(js::jit::LSnapshot*, js::jit::MDefinition*, unsigned int*, bool) js/src/jit/shared/CodeGenerator-shared.cpp:602:9
    #2 0x58a8abc48cb4 in js::jit::CodeGeneratorShared::encode(js::jit::LSnapshot*) js/src/jit/shared/CodeGenerator-shared.cpp:726:5
    #3 0x58a8abcab1dd in void js::jit::CodeGeneratorX86Shared::bailout<js::jit::BailoutLabel>(js::jit::BailoutLabel const&, js::jit::LSnapshot*) js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp:520:3
    #4 0x58a8abcab13f in js::jit::CodeGeneratorX86Shared::bailoutFrom(js::jit::Label*, js::jit::LSnapshot*) js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp:549:3
    #5 0x58a8abf84889 in js::jit::CodeGenerator::visitLexicalCheck(js::jit::LLexicalCheck*) js/src/jit/CodeGenerator.cpp:21714:3
    #6 0x58a8abf1a864 in js::jit::CodeGenerator::generateBlock(js::jit::LBlock*, unsigned long, js::jit::IonScriptCounts*, bool) js/src/jit/CodeGenerator.cpp:8664:7
    #7 0x58a8abf18a24 in js::jit::CodeGenerator::generateBody() js/src/jit/CodeGenerator.cpp:8573:10
    #8 0x58a8abfe1b01 in js::jit::CodeGenerator::generate(js::jit::WarpSnapshot const*) js/src/jit/CodeGenerator.cpp:17454:8
    #9 0x58a8ac0c23fa in js::jit::GenerateCode(js::jit::MIRGenerator*, js::jit::LIRGraph*, js::jit::WarpSnapshot const*) js/src/jit/Ion.cpp:1674:17
    #10 0x58a8ac0c23fa in js::jit::CompileBackEnd(js::jit::MIRGenerator*, js::jit::WarpSnapshot*) js/src/jit/Ion.cpp:1704:28
    #11 0x58a8ac10a08d in js::jit::IonCompileTask::runTask() js/src/jit/IonCompileTask.cpp:52:24
    #12 0x58a8ac10a08d in js::jit::IonCompileTask::runHelperThreadTask(js::AutoLockHelperThreadState&) js/src/jit/IonCompileTask.cpp:30:5
    #13 0x58a8ac7504a5 in js::GlobalHelperThreadState::runTaskLocked(JS::HelperThreadTask*, js::AutoLockHelperThreadState&) js/src/vm/HelperThreads.cpp:667:11
    #14 0x58a8ac7828fc in js::GlobalHelperThreadState::runOneTask(JS::HelperThreadTask*, js::AutoLockHelperThreadState&) js/src/vm/HelperThreads.cpp:623:3
    #15 0x58a8ac7828fc in js::HelperThread::threadLoop(js::InternalThreadPool*) js/src/vm/InternalThreadPool.cpp:324:25
    #16 0x58a8ac782517 in js::HelperThread::ThreadMain(js::InternalThreadPool*, js::HelperThread*) js/src/vm/InternalThreadPool.cpp:251:11
    #17 0x58a8ac790ca3 in void js::detail::ThreadTrampoline<void (&)(js::InternalThreadPool*, js::HelperThread*), js::InternalThreadPool*&, js::HelperThread*>::callMain<0ul, 1ul>(std::integer_sequence<unsigned long, 0ul, 1ul>) js/src/threading/Thread.h:226:5
    #18 0x58a8ac790ca3 in js::detail::ThreadTrampoline<void (&)(js::InternalThreadPool*, js::HelperThread*), js::InternalThreadPool*&, js::HelperThread*>::Start(void*) js/src/threading/Thread.h:215:11
    #19 0x774bdaf01aa3 in start_thread nptl/pthread_create.c:447:8
    #20 0x774bdaf8ec6b in clone3 misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

==71353==Register values:
rax = 0x0000000000000000  rbx = 0x0000000000000000  rcx = 0x000000000000025b  rdx = 0x0000774bdb069563
rdi = 0x0000774bdb06a700  rsi = 0x0000000000000000  rbp = 0x0000774bd99fe540  rsp = 0x0000774bd99fe4d0
 r8 = 0x0000000000000000   r9 = 0x0000000000000003  r10 = 0x0000000000000002  r11 = 0x0000000000000293
r12 = 0x0000774bd87d0000  r13 = 0x0000774bd87a1770  r14 = 0x0000774bd879dc68  r15 = 0x0000774bd99fe5ac
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV dist/include/mozilla/Assertions.h:237:3 in MOZ_CrashSequence(void*, long)
==71353==ABORTING
Group: firefox-core-security → core-security
Component: Untriaged → JavaScript Engine: JIT
Product: Firefox → Core
Group: core-security → javascript-core-security

This looks vaguely similar to bug 1947141. We inline a into the inner loop. We generate an Int32ToIntPtr -> IntPtrToInt64 -> Int64ToBigInt chain, which is unused except for in recovery instructions. We spill b to a 32-bit stack slot (probably because of the new SharedArrayBuffer call). When we try to encode a snapshot, we assert for the IntPtrToInt64, because we have a MIRType::Int64 value with a 32-bit LStackSlot allocation.

We marked bug 1947141 as sec-moderate because it was possible that it could lead to an information leak. (See the analysis in this comment). I managed to reproduce a similar leak using the current bug with this testcase:

function opt() {
  let v0 = 0;
  do {
    var v1 = v0++;
  } while (v0 != 1000);

  const v3 = BigInt.asUintN(64, BigInt(v0));
  try { throw 65536; } catch {}
  return v3;
}

for (var i = 0; i < 20; i++) {
  assertEq(opt(), 1000n);
}

With some work, this could potentially be used to leak the bottom 32 bits of a pointer.

We fixed bug 1947141 by adding support for reading IntPtr values from Int32 slots. I think the fix here is to do the same with Int64 values.

Keywords: sec-moderate
Attached file (secure)
Assignee: nobody → iireland
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Attached file (secure)
Flags: sec-bounty?
Severity: -- → S4
Priority: -- → P1
Pushed by chorotan@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/c3f4d7cd80bf https://hg.mozilla.org/integration/autoland/rev/5daa12ae75b3 Revert "Bug 2010943: Support reading int64 from int32 stack slot r=jandem" for causing bustages on testJitRValueAlloc.cpp
[task 2026-01-20T22:57:59.396+00:00] 22:57:59    ERROR -  /builds/worker/checkouts/gecko/js/src/jsapi-tests/testJitRValueAlloc.cpp(388,32): error: no member named 'Int64Int32' in 'js::jit::RValueAllocation'; did you mean 'IntPtrInt32'?
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -    388 |     auto s = RValueAllocation::Int64Int32(i);
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -        |              ~~~~~~~~~~~~~~~~~~^~~~~~~~~~
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -        |                                IntPtrInt32
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -  /builds/worker/checkouts/gecko/js/src/jit/Snapshots.h(311,27): note: 'IntPtrInt32' declared here
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -    311 |   static RValueAllocation IntPtrInt32(int32_t offset) {
[task 2026-01-20T22:57:59.397+00:00] 22:57:59     INFO -        |                           ^
[task 2026-01-20T22:57:59.398+00:00] 22:57:59     INFO -  In file included from Unified_cpp_js_src_jsapi-tests14.cpp:2:
[task 2026-01-20T22:57:59.398+00:00] 22:57:59     INFO -  In file included from /builds/worker/checkouts/gecko/js/src/jsapi-tests/testJitMacroAssembler.cpp:18:
[task 2026-01-20T22:57:59.398+00:00] 22:57:59     INFO -  /builds/worker/checkouts/gecko/js/src/jsapi-tests/tests.h(523,14): warning: Usage of ASCII file functions (here fopen) is forbidden on Windows.
[task 2026-01-20T22:57:59.398+00:00] 22:57:59     INFO -    523 |     stream = fopen(fileName, "wb+");
[task 2026-01-20T22:57:59.398+00:00] 22:57:59     INFO -        |              ^
[task 2026-01-20T22:57:59.399+00:00] 22:57:59     INFO -  /builds/worker/checkouts/gecko/js/src/jsapi-tests/tests.h(523,14): note: On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.
[task 2026-01-20T22:57:59.399+00:00] 22:57:59     INFO -  1 warning and 1 error generated.
[task 2026-01-20T22:57:59.399+00:00] 22:57:59    ERROR -  gmake[4]: *** [/builds/worker/checkouts/gecko/config/rules.mk:668: Unified_cpp_js_src_jsapi-tests14.obj] Error 1
Flags: needinfo?(iireland)

Oops, that test has to be 64-bit only.

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

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

For more information, please visit BugBot documentation.

Flags: needinfo?(iireland)

To add to comment 10, it will also require an ESR140 uplift request. It grafts cleanly to ESR140.

firefox-beta Uplift Approval Request

  • User impact if declined: Potential information leak exposing the bottom 32 bits of pointers.
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing: None
  • Risk associated with taking this patch: low
  • Explanation of risk level: The approach for fixing this has already been used successfully in a very similar case.
  • String changes made/needed: None
  • Is Android affected?: yes
Attachment #9539151 - Flags: approval-mozilla-beta?
Attached file (secure)

firefox-esr140 Uplift Approval Request

  • User impact if declined: Potential information leak exposing the bottom 32 bits of pointers.
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing: None
  • Risk associated with taking this patch: low
  • Explanation of risk level: The approach for fixing this has already been used successfully in a very similar case.
  • String changes made/needed: None
  • Is Android affected?: yes
Attachment #9539152 - Flags: approval-mozilla-esr140?
Attached file (secure)
Flags: needinfo?(iireland)
Attachment #9539151 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Flags: sec-bounty? → sec-bounty+
QA Whiteboard: [sec] [uplift] [qa-triage-done-c149/b148]
Attachment #9539152 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Whiteboard: [adv-main148+]
Whiteboard: [adv-main148+] → [adv-main148+] [adv-esr140.8+]
Alias: CVE-2026-2783
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: