Closed
Bug 1154923
Opened 9 years ago
Closed 8 years ago
Compartment mismatch in js::ScriptSourceObject::initFromOptions
Categories
(Core :: DOM: Core & HTML, defect)
Core
DOM: Core & HTML
Tracking
()
RESOLVED
FIXED
mozilla50
People
(Reporter: mccr8, Assigned: mccr8)
References
Details
(Keywords: sec-high, Whiteboard: [post-critsmash-triage][adv-main48+][adv-esr45.3+])
Attachments
(1 file, 1 obsolete file)
3.55 KB,
patch
|
terrence
:
review+
Sylvestre
:
approval-mozilla-aurora+
Sylvestre
:
approval-mozilla-beta+
Sylvestre
:
approval-mozilla-esr45+
abillings
:
sec-approval+
|
Details | Diff | Splinter Review |
I found these stacks on crash-stats: https://crash-stats.mozilla.com/report/index/b543869b-c423-4b63-af9b-b52ad2150412 https://crash-stats.mozilla.com/report/index/e761453d-caab-41e9-a8f9-6cd162150413 This is similar, but the compartment mismatch is happening right after the call to ParseTask::finish(): https://crash-stats.mozilla.com/report/index/130afcfa-408b-4701-a063-882bc2150413 I'm not sure what the cause is. GlobalHelperThreadState::finishParseTask() calls gc::MergeCompartments() before this.
Assignee | ||
Comment 1•9 years ago
|
||
I'm marking this sec-high because it is a mismatch, but because it is in the parser I'm not sure if it could really be exploited.
Keywords: sec-high
Updated•9 years ago
|
Group: javascript-core-security
Assignee | ||
Comment 2•9 years ago
|
||
Can you look at this Jim? I'm still seeing this on trunk on crash-stats.
Flags: needinfo?(jimb)
Assignee | ||
Comment 3•9 years ago
|
||
Here are more recent examples: https://crash-stats.mozilla.com/report/index/ebccf39b-3a58-4b6b-92e9-1ca052150530 https://crash-stats.mozilla.com/report/index/1a5499da-c77c-4da5-a512-36a962150601
Updated•9 years ago
|
Flags: needinfo?(jimb)
Comment 4•9 years ago
|
||
In all these crashes: - We start an off-thread compilation of a <script> element. - The SpiderMonkey helper thread completes the compilation and calls OffThreadScriptLoaderCallback, which queues a NotifyOffThreadScriptLoadCompletedRunnable to the main thread. - The main thread event loop eventually calls NotifyOffThreadScriptLoadCompletedRunnable::Run. Now we've reached the stacks appearing in the crash reports. - From here, nsScriptLoader::EvaluateScript chooses a global object to finish the compilation in: https://dxr.mozilla.org/mozilla-central/source/dom/base/nsScriptLoader.cpp#1123 - That's passed in to nsJSUtils::EvaluateString, which enters that global on the JSContext here: https://dxr.mozilla.org/mozilla-central/source/dom/base/nsJSUtils.cpp#239 - It then calls JS::FinishOffThreadScript, which notices that the JSContext is in a compartment different from the script the compilation produced. It seems to me that Gecko is trying to enter the compilation's compartment on its JSContext, but SpiderMonkey is correct that this compartment is not the one the compilation was actually started in. I wonder, is it possible that nsScriptLoader starts a compilation in one compartment, and then something happens that changes the JSObject global (inner window) associated with the nsScriptLoader, and then the compilation completes, but we don't recognize that we don't care about running the script any more?
Flags: needinfo?(khuey)
The script loader is tied to the document, iirc, so if something changes the inner but not the document we could have a bad time.
Flags: needinfo?(khuey)
Comment 6•9 years ago
|
||
And document.open()/write() after document load creates a new inner window, yet keeps the old document.
Comment 7•9 years ago
|
||
I think it could be exploited, because it does introduce cross-compartment edges that should not be there, and those edges refer to script. So I think the sec-high mark is probably appropriate.
Assignee | ||
Updated•9 years ago
|
Component: JavaScript Engine → DOM
Comment 8•9 years ago
|
||
Ok, so presumably the scenario here is an async script that finishes loading, we start the off-thread parse, and while it's parsing the page does a document.open(). What _should_ the DOM do in this case exactly? We need to execute the script in the new global document.open() creates. What are our options? Clone the script into the new global? Throw away the off-thread compile and restart the compile? Something else?
Comment 9•9 years ago
|
||
Assuming this is some async script, I'd assume we should not process the script if it is loaded after someone called document.open() after page load, since document.open() removes all the elements from document. (but I haven't checked what the spec says about this) I don't see nsScriptLoader::ProcessRequest doing any IsIn*Doc() checks.
Comment 10•9 years ago
|
||
> since document.open() removes all the elements from document. Removing a <script> tag for a script that's started loading doesn't prevent it from running when the load finishes. Simple testcase: <script> var s = document.createElement("script"); s.src = "data:text/plain,alert('hello')"; document.documentElement.appendChild(s); s.remove(); </script> > I don't see nsScriptLoader::ProcessRequest doing any IsIn*Doc() checks Because it's not supposed to...
Assignee | ||
Comment 11•9 years ago
|
||
I guess I'll try to figure out something here.
Assignee: nobody → continuation
Assignee | ||
Comment 12•9 years ago
|
||
I tried looking at this, but I have no idea what is going on here. Could you look at this, Boris? Thanks.
Assignee: continuation → nobody
Flags: needinfo?(bzbarsky)
Updated•9 years ago
|
Flags: needinfo?(bzbarsky)
Comment 13•9 years ago
|
||
Well, we know what's going wrong. See comment 4. The question is what behavior Spidermonkey will let us have here, from the options in comment 8... Jason, Eric, who might be able to look into those options on the SpiderMonkey end here?
Flags: needinfo?(efaustbmo)
Updated•9 years ago
|
Flags: needinfo?(jorendorff)
Comment 14•9 years ago
|
||
(In reply to Boris Zbarsky [:bz] from comment #8) > Throw away the off-thread compile and restart the compile? This seems like the best option to me. Is a |document.open()| while an async script is off-thread-parsing a relatively rare occurrence? If so, we can probably discard the compile and re-schedule it. So the logic would be to check the new global, and if it differs, throw away the compile compartment and re-schedule a parse?
Comment 15•9 years ago
|
||
> Is a |document.open()| while an async script is off-thread-parsing a relatively rare > occurrence? Yes. > So the logic would be to check the new global, and if it differs, throw away the compile > compartment and re-schedule a parse? That's the idea. Should that happen in SpiderMonkey or the scriptloader? I think the scriptloader hands over ownership of the buffer to SpiderMonkey, so if we can do all this inside SpiderMonkey that would be ideal...
Updated•9 years ago
|
Flags: needinfo?(efaustbmo) → needinfo?(kvijayan)
Updated•9 years ago
|
Flags: needinfo?(jorendorff)
Comment 16•9 years ago
|
||
(In reply to Boris Zbarsky [:bz] from comment #15) > That's the idea. Should that happen in SpiderMonkey or the scriptloader? I > think the scriptloader hands over ownership of the buffer to SpiderMonkey, > so if we can do all this inside SpiderMonkey that would be ideal... This would be difficult. The interaction for off-main-thread parsing goes back and forth between the scriptloader and spidermonkey. Scriptloader starts the off-main-thread parse, which causes spidermonkey to schedule the parse on a different thread, and when that completes, spidermonkey dispatches an event back to scriptloader, which calls FinishOffThreadScript back on the main thread. The particular invocation of FinishOffThreadScript happens inside nsJSUtils::EvaluateString. When the scriptloader calls EvaluateString, it expects the script to run synchronously. It may be OK for the script to be re-scheduled at that point, but that change in behaviour would need to be carefully verified and might cause weird breakages in assumptions (I don't know the code well enough to say that it wouldn't). It seems best if ScriptLoader handles this itself. When it gets notified that a parse is complete (via NotifyOffThreadScriptLoadCompletedRunnable::Run() - which runs on the main thread), it needs to immediately call into spidermonkey to finish the off-thread parse. If a mismatched global is detected at that point, it can re-schedule without ever going into the script execution codepath.
Flags: needinfo?(kvijayan)
Updated•9 years ago
|
Group: core-security → dom-core-security
Updated•9 years ago
|
Group: javascript-core-security
Assignee | ||
Comment 19•8 years ago
|
||
My most recent patch leaks: https://treeherder.mozilla.org/#/jobs?repo=try&revision=c813c7fd7e75 Calling GetScriptGlobalObject() inside nsScriptLoader::ProcessOffThreadRequest() is doing that somehow. Maybe I should just throw a release compartment check into ParseTask::finish() and call it a day.
Flags: needinfo?(continuation)
Assignee | ||
Comment 20•8 years ago
|
||
This is what I have so far. The try run is green, but if I make the code in nsScriptLoader::ProcessOffThreadRequest() always fail then pages aren't loading correctly, while I think the desired behavior is that things load properly, just more slowly. So I may not be inserting the check in the right place.
Assignee | ||
Comment 21•8 years ago
|
||
Maybe I should just make these two compartment checks fatal and be done with it. This wasn't happening very much in the wild, so it shouldn't negatively affect stability.
Assignee | ||
Comment 22•8 years ago
|
||
Not the most elegant solution, but this has been sitting around for too long. try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=3d074ec9baaa
Attachment #8755525 -
Flags: review?(terrence)
Assignee | ||
Updated•8 years ago
|
Attachment #8723691 -
Attachment is obsolete: true
Comment 23•8 years ago
|
||
Comment on attachment 8755525 [details] [diff] [review] Add a version of assertSameCompartment that works in all versions. Review of attachment 8755525 [details] [diff] [review]: ----------------------------------------------------------------- This seems fine as a short-term hack. Let's just make sure that the real bug gets fixed as well.
Attachment #8755525 -
Flags: review?(terrence) → review+
Assignee | ||
Comment 24•8 years ago
|
||
Comment on attachment 8755525 [details] [diff] [review] Add a version of assertSameCompartment that works in all versions. [Security approval request comment] How easily could an exploit be constructed based on the patch? Not very easily. 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 older supported branches are affected by this flaw? all If not all supported branches, which bug introduced the flaw? Do you have backports for the affected branches? If not, how different, hard to create, and risky will they be? should be easy How likely is this patch to cause regressions; how much testing does it need? This patch detects a bad situation and just crashes. I can't be sure how much this actually happens. It didn't happen much in the wild on Nightly and Aurora, as of a year ago, but who knows now. So that's a risk.
Attachment #8755525 -
Flags: sec-approval?
Comment 25•8 years ago
|
||
This is too late for 47. We're making release builds in less than a week. This can check in on June 21, 2016, two weeks into the next cycle. We'll want branch patches at that time as well, including ESR45.
status-firefox47:
--- → wontfix
status-firefox48:
--- → affected
status-firefox49:
--- → affected
status-firefox-esr38:
--- → affected
Whiteboard: [checkin on 6/21]
Updated•8 years ago
|
Attachment #8755525 -
Flags: sec-approval? → sec-approval+
Comment 26•8 years ago
|
||
(This sec-approval+ only applies to checkin on 6/21)
Assignee | ||
Updated•8 years ago
|
Keywords: checkin-needed
Comment 27•8 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/88213a36d165
Keywords: checkin-needed
Whiteboard: [checkin on 6/21]
https://hg.mozilla.org/mozilla-central/rev/88213a36d165
Status: NEW → RESOLVED
Closed: 8 years ago
status-firefox50:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla50
Updated•8 years ago
|
Group: dom-core-security → core-security-release
Assignee | ||
Comment 29•8 years ago
|
||
Comment on attachment 8755525 [details] [diff] [review] Add a version of assertSameCompartment that works in all versions. Approval Request Comment [Feature/regressing bug #]: old [User impact if declined]: sec-high [Describe test coverage new/current, TreeHerder]: this code runs frequently [Risks and why]: This turns a very rare Nightly/Aurora crash into one that will happen on all branches. The main risk is that this gets triggered frequently on beta or release. But, if it is, then probably bad things are happening anyways, so maybe it isn't too bad to just crash safely. [String/UUID change made/needed]: none
Attachment #8755525 -
Flags: approval-mozilla-esr45?
Attachment #8755525 -
Flags: approval-mozilla-beta?
Attachment #8755525 -
Flags: approval-mozilla-aurora?
Assignee | ||
Updated•8 years ago
|
status-firefox40:
wontfix → ---
status-firefox-esr38:
affected → ---
status-firefox-esr45:
--- → affected
Assignee | ||
Comment 30•8 years ago
|
||
This has been on Nightly for a few days, and it doesn't seem to have caused any issues.
Comment 31•8 years ago
|
||
Comment on attachment 8755525 [details] [diff] [review] Add a version of assertSameCompartment that works in all versions. Fix a sec-high, taking it
Attachment #8755525 -
Flags: approval-mozilla-esr45?
Attachment #8755525 -
Flags: approval-mozilla-esr45+
Attachment #8755525 -
Flags: approval-mozilla-beta?
Attachment #8755525 -
Flags: approval-mozilla-beta+
Attachment #8755525 -
Flags: approval-mozilla-aurora?
Attachment #8755525 -
Flags: approval-mozilla-aurora+
https://hg.mozilla.org/releases/mozilla-aurora/rev/f96fe0adc4e6 https://hg.mozilla.org/releases/mozilla-beta/rev/b101ef9dfd00 https://hg.mozilla.org/releases/mozilla-esr45/rev/2786beb35a38
Updated•8 years ago
|
Whiteboard: [post-critsmash-triage]
Updated•8 years ago
|
Whiteboard: [post-critsmash-triage] → [post-critsmash-triage][adv-main48+][adv-esr45.3+]
Updated•8 years ago
|
tracking-firefox-esr45:
--- → 48+
Updated•8 years ago
|
Group: core-security-release
Updated•5 years ago
|
Component: DOM → DOM: Core & HTML
You need to log in
before you can comment on or make changes to this bug.
Description
•