Baseline RetAddrEntry PC Offset Truncation
Categories
(Core :: JavaScript Engine: JIT, defect, P1)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox150 | + | fixed |
| firefox151 | + | fixed |
| firefox152 | + | fixed |
People
(Reporter: gaddofpwn, Assigned: jandem)
References
(Blocks 2 open bugs, Regression)
Details
(5 keywords, Whiteboard: [client-bounty-form][pp1][adv-main150.0.3+])
Attachments
(8 files)
|
124.48 KB,
application/zip
|
Details | |
|
171 bytes,
text/html
|
Details | |
|
2.62 KB,
text/x-python
|
Details | |
|
123.29 KB,
application/zip
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
tjr
:
sec-approval+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-release+
|
Details | Review |
Baseline RetAddrEntry PC Offset Truncation
Summary
The Baseline JIT return-address table stores the bytecode PC offset in the 28-bit RetAddrEntry::pcOffset_ bitfield. The normal Baseline entry path rejects oversized scripts on x86-64 with BaselineMaxScriptLength == 0x0fffffff, matching that 28-bit storage limit. The eager Baseline compilation path used during stencil instantiation does not apply the same length check.
As a result, content can first seed a JitHint and then load a larger script with the same script key. If the larger script places an IC at a bytecode offset above the 28-bit limit, the off-thread eager Baseline compiler attempts to store that oversized PC offset in RetAddrEntry. Debug builds abort on pcOffset_ == pcOffset. Release builds truncate the high bits in the bitfield, producing incorrect BaselineScript return-address metadata.
Affected Component
- SpiderMonkey Baseline JIT
- off-thread eager Baseline compilation
- JitHints-based eager compilation
- BaselineScript return-address table
Impact
Confirmed impact:
- Firefox content process assertion failure at
js/src/jit/BaselineJIT.h:150 - The content process exits with signal 11 after the assertion.
- The symbolized stack enters
RetAddrEntry::RetAddrEntryfromBaselineCodeGen::emitNextIC,emit_GetGName, andBaselineCompileTask::runTask.
Security relevance:
- This is not only a debug assertion.
pcOffset_is a 28-bit bitfield, so release builds store a truncated PC offset. - The Baseline return-address table maps native return addresses back to bytecode PCs for ICs, VM calls, exception handling, stack walking, and related runtime operations.
- A truncated PC offset can make those operations use a bytecode location different from the actual execution site.
- In exception handling, this can select the wrong try-note or stack depth and cause Baseline frame stack slots to be interpreted incorrectly.
- A controlled memory-corruption primitive has not been established in this report.
Suggested severity: high, pending exploitability assessment.
Root Cause
RetAddrEntry stores the bytecode PC offset in a 28-bit bitfield.
Relevant source:
js/src/jit/BaselineJIT.h:100-164
The failing checks are debug-only:
uint32_t pcOffset_ : 28;
MOZ_ASSERT(pcOffset_ == pcOffset);
MOZ_ASSERT(pcOffset <= BaselineMaxScriptLength);
The normal x86-64 Baseline script length limit is aligned with the 28-bit bound.
js/src/jit/BaselineJIT.h:66-74
The eager Baseline compilation path queues scripts during stencil instantiation without checking BaselineMaxScriptLength.
Relevant source:
js/src/frontend/Stencil.cpp:2720-2798js/src/frontend/Stencil.cpp:2819-2826
emitNextIC creates an IC return-address entry using the current bytecode pcOffset.
js/src/jit/BaselineCodeGen.cpp:783-788
A high-offset GetGName IC reaches this path.
js/src/jit/BaselineCodeGen.cpp:3683-3690
Firefox default settings enable JitHints-based eager Baseline compilation.
modules/libpref/init/StaticPrefList.yaml:9073-9142dom/script/ScriptLoader.cpp:2742-2766
Reproducer
poc.html
payload.js
server.py
PoC structure:
poc.htmlloadspayload.jstwice from the same URL.- The first
payload.jsresponse is a small seed script that creates a JitHint. - The second
payload.jsresponse is a large script from the same URL, placing aGetGNameIC after a bytecode offset above the 28-bit limit. server.pyserves different responses for the first and second requests to the same/payload.jsURL.- No shell-only function or preference change is required.
Default-Settings Reproduction
Command:
<firefox> --headless --no-remote --profile <empty-profile> <poc-url>
Result:
firefox_status=11
reason=debug-assertion-after-done
done=1
assertion=1
Assertion:
Assertion failure: pcOffset_ == pcOffset, at js/src/jit/BaselineJIT.h:150
Program firefox received signal 11.
Symbolized stack:
js::jit::RetAddrEntry::RetAddrEntry
mozilla::Vector<js::jit::RetAddrEntry>::emplaceBack
js::jit::BaselineCodeGen<js::jit::BaselineCompilerHandler>::emitNextIC
js::jit::BaselineCodeGen<js::jit::BaselineCompilerHandler>::emit_GetGName
js::jit::BaselineCompiler::emitBody
js::jit::BaselineCompiler::compileImpl
js::jit::BaselineCompileTask::runTask
js::jit::BaselineCompileTask::runHelperThreadTask
JS::RunHelperThreadTask
Expected Behavior
The Baseline compiler should do one of the following:
- enforce
script->length() <= BaselineMaxScriptLengthin the eager Baseline path as well; - safely fail Baseline compilation for scripts whose PC offsets cannot be represented in
RetAddrEntry; - widen or change return-address metadata encoding so PC offsets are not truncated.
Release builds must not create BaselineScripts containing truncated bytecode PC offsets.
Suggested Fix
Minimum fix:
- Before queueing a script for eager Baseline compilation, reject scripts with
script->length() > BaselineMaxScriptLengthusing a release-enforced compile failure. - Share script length validation between the normal Baseline entry path and the eager Baseline path.
More robust fix:
- Validate
pcOffset <= BaselineMaxScriptLengthin release builds before storing aRetAddrEntry. - Widen
RetAddrEntry::pcOffset_or move the kind field out of the packed value to eliminate truncation. - Add a regression test that reloads a large same-key script through JitHints-based eager Baseline compilation.
Updated•4 months ago
|
Comment 1•4 months ago
|
||
Please attach files individually and not in a zip. This aides triage. Thanks.
Comment 2•4 months ago
|
||
Jan, would you be the right person to look at this issue?
(In reply to Andrew McCreight [:mccr8] from comment #1)
Please attach files individually and not in a zip. This aides triage. Thanks.
The payload.js file is over 100 MB, so I’m unable to attach it.(In reply to Andrew McCreight [:mccr8] from comment #1)
Please attach files individually and not in a zip. This aides triage. Thanks.
The payload.js file is over 100 MB, so I’m unable to attach it.
Comment 4•4 months ago
|
||
(In reply to ggwhyp from comment #3)
The payload.js file is over 100 MB, so I’m unable to attach it.
Ah, okay. Well, you can attach the other two files then. Thanks.
| Assignee | ||
Updated•4 months ago
|
| Assignee | ||
Comment 8•4 months ago
•
|
||
The eager baseline compilation mode added in bug 1980830 wasn't hooked up to the JS shell, that's probably why we didn't find this sooner.
| Assignee | ||
Updated•4 months ago
|
Comment 9•4 months ago
|
||
Set release status flags based on info from the regressing bug 1980830
| Assignee | ||
Comment 10•4 months ago
|
||
| Assignee | ||
Comment 11•4 months ago
|
||
The test doesn't generate a huge function because it makes the test very slow,
but it has all the scaffolding for a fuzzer to mutate.
Updated•4 months ago
|
Updated•4 months ago
|
| Assignee | ||
Comment 12•4 months ago
|
||
Comment on attachment 9583793 [details]
(secure)
Security Approval Request
- How easily could an exploit be constructed based on the patch?: Not very easily but it's doable.
- Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: No
- Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?: beta, release
- If not all supported branches, which bug introduced the flaw?: Bug 1980830
- Do you have backports for the affected branches?: Yes
- If not, how different, hard to create, and risky will they be?: Patch should apply or should be easy to backport.
- How likely is this patch to cause regressions; how much testing does it need?: Unlikely.
- Is the patch ready to land after security approval is given?: Yes
- Is Android affected?: Yes
Updated•4 months ago
|
Updated•4 months ago
|
Comment 13•4 months ago
|
||
Comment 14•4 months ago
|
||
(In reply to Jan de Mooij [:jandem] from comment #8)
The eager baseline compilation mode added in bug 1980830 was never hooked up to the JS shell, that's probably why we didn't find this sooner.
That looks like useful follow-up work. Is it tracked in a bug elsewhere?
| Assignee | ||
Comment 15•4 months ago
|
||
(In reply to Frederik Braun [:freddy] from comment #14)
That looks like useful follow-up work. Is it tracked in a bug elsewhere?
The follow-up patch here adds a new testing function option + a shell test that uses it :)
Updated•4 months ago
|
Comment 17•4 months ago
|
||
https://hg-edge.mozilla.org/mozilla-central/rev/f40113af5ca5
Please add Beta and Release uplift nominations for this when you get chance.
Comment 18•4 months ago
|
||
firefox-beta Uplift Approval Request
- User impact if declined/Reason for urgency: Security bug.
- Code covered by automated testing?: yes
- Fix verified in Nightly?: yes
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: Pretty small and safe patch moving some checks into a shared function.
- String changes made/needed?: N/A
- Is Android affected?: yes
| Assignee | ||
Comment 19•4 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D298875
Comment 20•4 months ago
|
||
firefox-release Uplift Approval Request
- User impact if declined/Reason for urgency: Security bug.
- Code covered by automated testing?: yes
- Fix verified in Nightly?: yes
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: Pretty small and safe patch moving some checks into a shared function.
- String changes made/needed?: N/A
- Is Android affected?: yes
| Assignee | ||
Comment 21•4 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D298875
Updated•4 months ago
|
Updated•4 months ago
|
Comment 22•4 months ago
|
||
| uplift | ||
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Comment 23•4 months ago
|
||
| 150.0.3 uplift | ||
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Updated•27 days ago
|
Comment 24•23 days ago
|
||
Updated•23 days ago
|
Comment 25•22 days ago
|
||
| bugherder | ||
Description
•