Closed Bug 1997503 (CVE-2025-14330) Opened 10 months ago Closed 10 months ago

Intermittent segfault in JITed code by PreBarrierFastPath for MIRType::Value on riscv64-simulator

Categories

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

RISCV64
Unspecified
defect

Tracking

()

RESOLVED FIXED
146 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr140 146+ fixed
firefox144 --- wontfix
firefox145 --- wontfix
firefox146 --- fixed

People

(Reporter: csmantle, Assigned: csmantle)

References

(Blocks 1 open bug, Regression)

Details

(4 keywords, Whiteboard: [tier 3 platform only][adv-main146+][adv-esr140.6+])

Attachments

(4 files, 1 obsolete file)

131 bytes, application/x-javascript
Details
477 bytes, text/plain
Details
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
Attached file program.js

Running program.js in a js shell on riscv64-simulator produces intermittent (4 in 15 consecutive runs) SIGSEGV:

$ ~/workspace/mozilla-firefox-dev/obj-x86_64-pc-linux-gnu/dist/bin/js ./program.js
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3910502==ERROR: AddressSanitizer: SEGV on unknown address 0x3f529bb00000 (pc 0x55f64f314997 bp 0x7fff7ed850b0 sp 0x7fff7ed84c20 T0)
==3910502==The signal is caused by a READ memory access.
    #0 0x55f64f314997 in long js::jit::Simulator::ReadMem<long>(long, js::jit::Instruction*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1482:13
    #1 0x55f64f314997 in js::jit::Simulator::DecodeRVIType() /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:3463:21
    #2 0x55f64f303e79 in js::jit::Simulator::InstructionDecode(js::jit::Instruction*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1831:7
    #3 0x55f64f3347aa in void js::jit::Simulator::execute<false>() /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1941:5
    #4 0x55f64f3347aa in js::jit::Simulator::callInternal(unsigned char*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:4060:5
    #5 0x55f64f335115 in js::jit::Simulator::call(unsigned char*, int, ...) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:4125:3
    #6 0x55f64f952430 in EnterJit(JSContext*, js::RunState&, unsigned char*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/Jit.cpp:107:5
    #7 0x55f64f952430 in js::jit::MaybeEnterJit(JSContext*, js::RunState&) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/Jit.cpp:255:10
    #8 0x55f64d3152c5 in js::RunScript(JSContext*, js::RunState&) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:450:32
    #9 0x55f64d3169d5 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:618:13
    #10 0x55f64ee4962e in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/BaselineIC.cpp:1697:10
    #11 0x55f64f309316 in js::jit::Simulator::SoftwareInterrupt() /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1629:7
    #12 0x55f64f3121e4 in js::jit::Simulator::DecodeRVIType() /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp
    #13 0x55f64f303e79 in js::jit::Simulator::InstructionDecode(js::jit::Instruction*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1831:7
    #14 0x55f64f3347aa in void js::jit::Simulator::execute<false>() /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1941:5
    #15 0x55f64f3347aa in js::jit::Simulator::callInternal(unsigned char*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:4060:5
    #16 0x55f64f335115 in js::jit::Simulator::call(unsigned char*, int, ...) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:4125:3
    #17 0x55f64f952430 in EnterJit(JSContext*, js::RunState&, unsigned char*) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/Jit.cpp:107:5
    #18 0x55f64f952430 in js::jit::MaybeEnterJit(JSContext*, js::RunState&) /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/Jit.cpp:255:10
    #19 0x55f64d335518 in js::Interpret(JSContext*, js::RunState&) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:3315:40
    #20 0x55f64d3152de in js::RunScript(JSContext*, js::RunState&) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:460:13
    #21 0x55f64d31b5ea in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, js::AbstractFramePtr, JS::MutableHandle<JS::Value>) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:851:13
    #22 0x55f64d31be99 in js::Execute(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, JS::MutableHandle<JS::Value>) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/Interpreter.cpp:884:10
    #23 0x55f64d5bd92a in ExecuteScript(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSScript*>, JS::MutableHandle<JS::Value>) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/CompilationAndEvaluation.cpp:548:10
    #24 0x55f64d5bdccc in JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>) /home/mantle/workspace/mozilla-firefox-dev/js/src/vm/CompilationAndEvaluation.cpp:572:10
    #25 0x55f64d1de88b in RunFile(JSContext*, char const*, _IO_FILE*, CompileUtf8, bool, bool) /home/mantle/workspace/mozilla-firefox-dev/js/src/shell/js.cpp:1315:10
    #26 0x55f64d1dd57b in Process(JSContext*, char const*, bool, FileKind) /home/mantle/workspace/mozilla-firefox-dev/js/src/shell/js.cpp
    #27 0x55f64d160a3b in ProcessArgs(JSContext*, js::cli::OptionParser*) /home/mantle/workspace/mozilla-firefox-dev/js/src/shell/js.cpp:12060:10
    #28 0x55f64d160a3b in Shell(JSContext*, js::cli::OptionParser*) /home/mantle/workspace/mozilla-firefox-dev/js/src/shell/js.cpp:12313:12
    #29 0x55f64d14fe5f in main /home/mantle/workspace/mozilla-firefox-dev/js/src/shell/js.cpp:12716:12
    #30 0x7f529c627674  (/usr/lib/libc.so.6+0x27674) (BuildId: 4fe011c94a88e8aeb6f2201b9eb369f42b4a1e9e)
    #31 0x7f529c627728 in __libc_start_main (/usr/lib/libc.so.6+0x27728) (BuildId: 4fe011c94a88e8aeb6f2201b9eb369f42b4a1e9e)
    #32 0x55f64d058d08 in _start (/home/mantle/workspace/mozilla-firefox-dev/obj-x86_64-pc-linux-gnu/dist/bin/js+0x2a42d08) (BuildId: 1cca63e781db4dbd800668e9b1706abc)

==3910502==Register values:
rax = 0x000007ea53760000  rbx = 0x0000522000001900  rcx = 0x000055f651d39c03  rdx = 0x00002fd4a325a0a0
rdi = 0x0000522000001908  rsi = 0xf2f2f2f2f2f8f8f8  rbp = 0x00007fff7ed850b0  rsp = 0x00007fff7ed84c20
 r8 = 0xf2f8f2f2f2f2f2f8   r9 = 0xf2f8f8f8f8f8f2f2  r10 = 0xffffffffffffffff  r11 = 0x0000000000000000
r12 = 0x00003f529bb00000  r13 = 0x00003f529bb00000  r14 = 0x000010006fda8988  r15 = 0x00000a4400000322
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/mantle/workspace/mozilla-firefox-dev/js/src/jit/riscv64/Simulator-riscv64.cpp:1482:13 in long js::jit::Simulator::ReadMem<long>(long, js::jit::Instruction*)
==3910502==ABORTING
Aborted                    (core dumped) ~/workspace/mozilla-firefox-dev/obj-x86_64-pc-linux-gnu/dist/bin/js ./program.js

To know the exact location in JITed code, I applied the following patch:

diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index a9bb7ad2e3..33e26559f1 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -7970,6 +7970,8 @@
   MOZ_ASSERT(temp2 != PreBarrierReg);
   MOZ_ASSERT(temp3 != PreBarrierReg);
 
+  AutoCreatedBy acb(*this, __FUNCTION__);
+
   // Load the GC thing in temp1.
   if (type == MIRType::Value) {
     unboxGCThingForGCBarrier(Address(PreBarrierReg, 0), temp1);
@@ -7990,6 +7992,9 @@
 #endif
 
   // Load the chunk address in temp2.
+  for (auto i = 0; i < static_cast<int>(type); i++) {
+    nop();
+  }
   andPtr(Imm32(int32_t(~gc::ChunkMask)), temp1, temp2);
 
   // If the GC thing is in the nursery, we don't need to barrier it.

Then loaded the coredump in GDB and examined the number of nops around pc. Turns out that the crash happened in riscv64 code generated by MacroAssembler::emitPreBarrierFastPath, at https://searchfox.org/firefox-main/rev/a7d872e9d28072c2dd6d688d1b6c0493fcf7e94c/js/src/jit/MacroAssembler.cpp#7998-7999.

Attached file mozconfig
Summary: Intermittent segfault in PreBarrierFastPath for MIRType::Value on riscv64-simulator → Intermittent segfault in JITed code by PreBarrierFastPath for MIRType::Value on riscv64-simulator

Commit:

○  poumyyrz rmalicdem@mozilla.com 2025-10-31 03:05:43 main 908469b7
│  Bug 1997370 - Enable toolbar customization in Nightly r=android-reviewers,Roger
Group: core-security → javascript-core-security

I would be worried if fuzzers did not caught this issue in Tier-1 platforms. I CC'ed a few persons in case you have questions.

If you are using the simulator on Linux x64, you might be able to use rr to record executions, and rewind the execution to find what part of the program generated the memory.

Blocks: sm-riscv64
Severity: -- → S4
Priority: -- → P5

I'd suggest stepping through the code emitted by emitPreBarrierFastPath to see if the instructions do what you'd expect.

Skimming the code quickly, I noticed that unboxGCThingForGCBarrier for riscv calls ExtractBits with JSVAL_TAG_SHIFT - 1. Is that right or should it be just JSVAL_TAG_SHIFT?

Flags: needinfo?(webmaster)

(In reply to Jan de Mooij [:jandem] from comment #4)

I'd suggest stepping through the code emitted by emitPreBarrierFastPath to see if the instructions do what you'd expect.

Yes, I'm trying to understand the nature of this bug by replaying a crashing case recorded by rr record --chaos.

Skimming the code quickly, I noticed that unboxGCThingForGCBarrier for riscv calls ExtractBits with JSVAL_TAG_SHIFT - 1. Is that right or should it be just JSVAL_TAG_SHIFT?

It should be JSVAL_TAG_SHIFT since the parameter is size; See (^1). The crash disappears after fixing this (0 out of 35 consecutive runs).

Flags: needinfo?(webmaster)
Attached file (secure)
Assignee: nobody → webmaster
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

Jan, I wonder if I should request sec-approval to land this?

Flags: needinfo?(jdemooij)

(In reply to Rong Bao [:csmantle] from comment #7)

Jan, I wonder if I should request sec-approval to land this?

Oh I already queued the patch for landing. RISC-V is a tier 3 platform so I think it's fine to just land it.

Flags: needinfo?(jdemooij)
Pushed by jdemooij@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/639c749daa5b https://hg.mozilla.org/integration/autoland/rev/6e5da1c25f66 [riscv64] Supply good tag shift to ExtractBits when unboxing for GC barrier. r=jandem

(In reply to Jan de Mooij [:jandem] from comment #8)

Oh I already queued the patch for landing. RISC-V is a tier 3 platform so I think it's fine to just land it.\

Sure. Just for completeness (wrt. sec-approval questionnaire), this bug originates directly from Bug 1800431, so maybe backporting it to branches supporting riscv64 JIT would be nice.

Keywords: regression
Regressed by: 1800431
Whiteboard: [tier 3 platform only]

firefox-beta Uplift Approval Request

  • User impact if declined: Fixes potential crashes with Firefox builds for RISC-V.
  • Code covered by automated testing: no
  • Fix verified in Nightly: no
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Code is only used on RISC-V (tier 3 platform)
  • String changes made/needed: N/A
  • Is Android affected?: no
Attachment #9524741 - Flags: approval-mozilla-beta?
Attached file (secure) (obsolete) —

firefox-esr140 Uplift Approval Request

  • User impact if declined: Fixes crashes with Firefox builds for RISC-V (tier 3 platform)
  • Code covered by automated testing: no
  • Fix verified in Nightly: no
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Code is only used on RISC-V (tier 3 platform)
  • String changes made/needed: N/A
  • Is Android affected?: no
Attachment #9524743 - Flags: approval-mozilla-esr140?

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

Group: javascript-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 146 Branch

I wonder should this bug be tagged with one of those sec-* severity tags?

(needinfo-ing Nicolas for the initial flags setup in comment 3.)

Flags: needinfo?(nicolas.b.pierron)

(In reply to Rong Bao [:csmantle] from comment #17)

I wonder should this bug be tagged with one of those sec-* severity tags?

Probably yes, especially since we are backtracking patches.

Flags: needinfo?(nicolas.b.pierron)
Keywords: sec-moderate

Submitting this for bounty consideration :)

Flags: sec-bounty?
Attachment #9524741 - Flags: approval-mozilla-beta? → approval-mozilla-release?
QA Whiteboard: [sec] [qa-triage-done-c147/b146]

Rong Bao: Unfortunately this bug does not qualify for our bounty program because we only cover the platforms that are in versions of Firefox shipped by Mozilla. In addition this would be disqualified because you appear to be the maintainer or contributor to this part of the code.

Flags: sec-bounty? → sec-bounty-

(In reply to Daniel Veditz [:dveditz] from comment #20)

Rong Bao: Unfortunately this bug does not qualify for our bounty program because we only cover the platforms that are in versions of Firefox shipped by Mozilla.

Thanks for clarification. However, I do notice that https://launchpad.net/~mozillateam/+archive/ubuntu/ppa/+packages ships various beta and esr versions targeting riscv64. Should this be considered as "shipped by Mozilla"? Or are there any official documents explicitly stating that scope of bounty program excludes Tier-3 platforms or said PPA?

In addition this would be disqualified because you appear to be the maintainer or contributor to this part of the code.

I beg to differ on this point. As per https://www.mozilla.org/en-US/security/bug-bounty/, the only rule that could justify this decision is:

  • You must not have written the buggy code or otherwise been involved in contributing the buggy code to the Mozilla project.

I'd like to point out that I am not the contributor of the buggy code -- it's proposed by Yahan Lu (<yahan@iscas.ac.cn>) in 2023 with no further modifications since then; Xref https://searchfox.org/firefox-main/rev/80de3bfc92ff505f458fe9a03a74f09ae0733d8c/js/src/jit/riscv64/MacroAssembler-riscv64.h#847. Thus, I am neither the author nor the regressor. My contribution started in July, 2025 as both part of my tutor's assignment and personal interest. I am not, in any way, affiliated with Yahan or their organization. So, I am not convinced that the bullet point mentioned is a valid blocker.

Flags: needinfo?(dveditz)

I'd like to point out that I am not the contributor of the buggy code

I apologize for not checking deeper. someone said you were the module owner for that port, which generally confers responsibility for the code whether you wrote that specific bit or not. But it's a murky area for ports. In any case that was a secondary thing.

I do notice that https://launchpad.net/~mozillateam/+archive/ubuntu/ppa/+packages ships various beta and esr versions targeting riscv64. Should this be considered as "shipped by Mozilla"?

That launchpad "MozillaTeam" is not us. "Shipped by Mozilla" means the binaries available from https://www.firefox.com/en-US/download/all/.

Flags: needinfo?(dveditz)

(In reply to Daniel Veditz [:dveditz] from comment #22)

someone said you were the module owner for that port, which generally confers responsibility for the code whether you wrote that specific bit or not.

I'm flattered to know that my contributions are recognized, but I'd have to say that I'm not the module owner either. But yes, it's a minor point and I'm glad that we can reach consensus here.

That launchpad "MozillaTeam" is not us. "Shipped by Mozilla" means the binaries available from https://www.firefox.com/en-US/download/all/.

Thanks, after following this link I see that "MozillaTeam" at Launchpad is indeed a third-party vendor. I'll check more carefully next time.

Attachment #9524743 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Hardware: Unspecified → RISCV64
Attachment #9524741 - Attachment is obsolete: true
Attachment #9524741 - Flags: approval-mozilla-release?
Whiteboard: [tier 3 platform only] → [tier 3 platform only][adv-main146+]
Whiteboard: [tier 3 platform only][adv-main146+] → [tier 3 platform only][adv-main146+][adv-esr140.6+]
Component: JavaScript: GC → JavaScript Engine: JIT
Alias: CVE-2025-14330
Flags: sec-bounty-hof+
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: