SpiderMonkey uninitialized memory leads to Type Confusion between "undefined" with any object
Categories
(Core :: JavaScript Engine, defect, P1)
Tracking
()
People
(Reporter: soulchen8650, Assigned: jandem)
Details
(Keywords: regression, sec-moderate, Whiteboard: [adv-main69+][adv-esr68.1+][post-critsmash-triage])
Attachments
(4 files)
826 bytes,
text/html
|
Details | |
1.20 KB,
application/x-javascript
|
Details | |
47 bytes,
text/x-phabricator-request
|
RyanVM
:
approval-mozilla-beta+
RyanVM
:
approval-mozilla-esr68+
|
Details | Review |
47 bytes,
text/x-phabricator-request
|
Details | Review |
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Steps to reproduce:
- open the html file with the latest firefox
- firefox renderer process crash.
Actual results:
- firefox will crash as type confusion happen between "undefined" and a normal object:
00000071cb00f521 4c395908 cmp qword ptr [rcx+8],r11 ds:00078000
00000008=????????????????
Expected results:
- not crash
Reporter | ||
Comment 1•6 years ago
|
||
Here is a type confusion bug in SpiderMonkey.
The root cause is in function |AnalyzeNewScriptDefiniteProperties|, the in parm |group| is the finial |initializedGroup_|, but this
group will call |detachNewScript|.
So in the function |AnalyzeNewScriptDefiniteProperties| => |AnalyzePoppedThis| => |AddClearDefiniteGetterSetterForPrototypeChain|, the in parm still |initializedGroup_| which will be detach NewScript soon.
So even if we change the |proto| of prototype chain, SpiderMonkey will call |newPropertyState| => |group->clearNewScript|, because the group was call |detachNewScript|, so it will nothing happen in |clearNewScript|.
I think we should use |initialGroup|(in |maybeAnalyze|) in function |AddClearDefiniteGetterSetterForPrototypeChain|
Comment 2•6 years ago
|
||
Just moving this to JS land - I can reproduce a tab crash on nightly, though I see a nullptr crash there: https://crash-stats.mozilla.org/report/index/e581285c-71db-4ac5-9b67-1d39f0190724 , but I'm not familiar with the JS engine myself so don't know about comment #1. Jan?
Comment 3•6 years ago
|
||
Comment 4•6 years ago
|
||
Testcase in comment 3 is reduced from the original testcase attached. Looks like the usual type confusion MIR assert, we have to assume this is exploitable somehow until Jan has investigated this. Marking sec-high until we know more. Also assuming all branches are affected because it was reported on 68.
Gary, can you bisect the testcase in comment 3 please?
Sure, thanks :decoder!
m = {
get e() {
function g(z) {
return z.y.x;
}
for (let i = 0; i < 1; i++) {
g(x);
}
g(this);
}
};
p = new Proxy({}, {
set: function(a, b, c) {
x = c;
new f("", 3);
}
});
function f(u, v) {
if (v == 3) {
f.prototype.__proto__ = m;
}
this.e;
this.y = u;
if (v == 2) {
p = this;
}
this.n = 2;
p.h = this;
}
new f([]);
Further reduced from decoder's testcase in comment 3. Asserts js shell compiled with --enable-debug on m-c rev c05f61052576 and run with --fuzzing-safe --no-threads --ion-eager at:
Assertion failure: MIR instruction returned value with unexpected type, at jit/MacroAssembler.cpp:1704
Trace/breakpoint trap
This is an old bug. Before m-c rev 410d733097ac, the assertion failure was a crash at a weird memory address. I went back as far as m-c rev 514c80664661 (Mar 2015) but the crash still happens.
Jan will have to take this on.
Comment 7•6 years ago
|
||
I poked at this a little bit this afternoon. I'm attaching a slightly more reduced testcase (the proxy is irrelevant) with some comments explaining what (I think) is going on.
I have no idea what the fix is.
Comment 8•6 years ago
•
|
||
And here's a version of gkw's testcase without the proxy:
m = {
get e() {
function g(z) {
return z.y.x;
}
for (let i = 0; i < 1; i++) {
g(x);
}
g(this);
}
};
function foo(c) {
x = c;
new f("", 3);
}
function f(u, v) {
if (v == 3) {
f.prototype.__proto__ = m;
}
this.e;
this.y = u;
if (v == 2) {
global = this
}
this.n = 2;
foo(this)
}
new f([]);
Reporter | ||
Comment 9•6 years ago
|
||
Hello,
In face, the root cause I was explained in comment 1, so you can generate a minimization poc through it if you want.
And how to fix this bug is the same.
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 10•6 years ago
|
||
The definite properties analysis handles these two cases:
- The set of properties found by the analysis exactly matches the ones of the preliminary objects. This is the simple case: these properties are marked as definite properties, there's a single group for everything.
- The preliminary objects have more properties than the analysis found. That's what happens here.
To handle case 2:
- We create a new group (initialGroup). This group has just the properties found by the analysis.
- The initialGroup becomes the default group for new objects and this group has the TypeNewScript associated with it, instead of the original (fully initialized) group.
- The TypeNewScript stores the original shape and group: whenever a property addition results in an object having that shape, we change its group from initialGroup to the fully initialized group.
The reporter is correct about the problem with this scheme: the prototype constraints still reference the original (fully initialized) group and that group does not have the TypeNewScript anymore (it's on the initialGroup now) so these constraints effectively become no-ops and we fail to fix up a partially initialized object.
Assignee | ||
Comment 11•6 years ago
|
||
Unboxed object removal helped a lot: I think you can unbox an |undefined| value as something else and get nullptr for objects/strings so it's not easy to exploit. Additionally, on 64-bit platforms our Spectre Value mitigations (XOR unboxing) means some high bits are set after unboxing so you can't do much with that pointer and not crash.
I'm wondering if we can stop handling case 2 in comment 10.
Assignee | ||
Comment 12•6 years ago
•
|
||
(In reply to Jan de Mooij [:jandem] from comment #11)
I'm wondering if we can stop handling case 2 in comment 10.
Case 1 is more common but removing case 2 would regress some Octane tests a lot (say 40%) so that's not a great spot fix.
As relatively safe fix we could allocate the initial group upfront and pass it also to AnalyzeNewScriptDefiniteProperties and the constraints added there. Then the constraints could call clearNewScript on both groups. That way we don't affect group assignment etc.
Assignee | ||
Comment 13•6 years ago
|
||
We now add information about the constraints to a new class (DPAConstraintInfo)
so we can then finish all constraints at the end. This is also nice to avoid
adding unnecessary constraints when the analysis fails.
Assignee | ||
Comment 14•6 years ago
|
||
Depends on D40444
Assignee | ||
Updated•6 years ago
|
Updated•6 years ago
|
Assignee | ||
Comment 15•6 years ago
|
||
I think sec-moderate makes sense considering the only effect we know of is confusion with nullptr. However we should probably keep this closed, backport in a few days, and not land the test yet.
Reporter | ||
Comment 16•6 years ago
|
||
May be |undefined| type confusion with BigInt may be crash in a valid address.
Assignee | ||
Comment 17•6 years ago
|
||
![]() |
||
Comment 18•6 years ago
|
||
Backed out changeset for JS raptor crashes:
https://hg.mozilla.org/integration/autoland/rev/e4922316f2b078de8040f9151bab7d9cd718fa82
Push which ran failing job: https://treeherder.mozilla.org/#/jobs?repo=autoland&group_state=expanded&resultStatus=testfailed%2Cbusted%2Cexception%2Cusercancel%2Cretry%2Csuperseded&revision=00aef750a2e9a5ae3fc05dba2a1e693a4c02e015&selectedJob=261355202
Failure log: https://treeherder.mozilla.org/logviewer.html#?job_id=261355202&repo=autoland
PROCESS-CRASH | runner.py | application crashed [@ js::TypeNewScript::maybeAnalyze(JSContext*, js::ObjectGroup*, bool*, bool)]
![]() |
||
Comment 19•6 years ago
|
||
Closing as there is no leave-open
in the keywords.
https://hg.mozilla.org/integration/autoland/rev/0cb31b4bc6f4d5a06b21441c500fe5bf31c976b7
https://hg.mozilla.org/mozilla-central/rev/0cb31b4bc6f4
Comment 20•6 years ago
|
||
Please nominate this for Beta and ESR68 approval when you get a chance. Also, is this something we should consider for ESR60 also given it being near EOL?
Assignee | ||
Comment 21•6 years ago
|
||
(In reply to Ryan VanderMeulen [:RyanVM] from comment #20)
Please nominate this for Beta and ESR68 approval when you get a chance. Also, is this something we should consider for ESR60 also given it being near EOL?
I'll request uplift after the weekend; some Nightly/fuzz testing would be good. I don't think we need this on ESR60 given almost-EOL (as you said) and not critical.
Updated•6 years ago
|
Assignee | ||
Comment 22•6 years ago
|
||
Comment on attachment 9082657 [details]
Bug 1568397 part 1 - Fix definite properties analysis to use the correct group for constraints. r?iain!,tcampbell!
Beta/Release Uplift Approval Request
- User impact if declined: Crashes, correctness issues.
- Is this code covered by automated tests?: Yes
- Has the fix been verified in Nightly?: Yes
- Needs manual test from QE?: No
- If yes, steps to reproduce:
- List of other uplifts needed: None
- Risk to taking this patch: Medium
- Why is the change risky/not risky? (and alternatives if risky): The patch itself is not extremely complicated or big and has had some Nightly testing, but the code is still pretty complicated.
- String changes made/needed: None
Comment 23•6 years ago
|
||
Comment on attachment 9082657 [details]
Bug 1568397 part 1 - Fix definite properties analysis to use the correct group for constraints. r?iain!,tcampbell!
Fixes a JS stability and security issue. Approved for 69.0b15 and 68.1esr.
Comment 24•6 years ago
|
||
uplift |
Updated•6 years ago
|
Updated•6 years ago
|
Updated•6 years ago
|
Updated•5 years ago
|
Comment 25•5 years ago
|
||
Assignee | ||
Updated•5 years ago
|
Comment 26•5 years ago
|
||
Bugbug thinks this bug is a regression, but please revert this change in case of error.
Comment 27•5 years ago
|
||
bugherder |
Description
•