Last Comment Bug 474456 - [1.9.0]Mozilla Firefox XUL Linked Clones Double Free Vulnerability (ZDI-CAN-423)
: [1.9.0]Mozilla Firefox XUL Linked Clones Double Free Vulnerability (ZDI-CAN-423)
[sg:critical] fixed in 1.9.1+ by bug ...
: crash, fixed1.9.1, testcase, verified1.9.0.7
Product: Core
Classification: Components
Component: XPConnect (show other bugs)
: 1.9.0 Branch
: x86 All
P1 critical (vote)
: mozilla1.9.2a1
Assigned To: Peter Van der Beken [:peterv]
: Andrew Overholt [:overholt]
Depends on: 457022
Blocks: 453751
  Show dependency treegraph
Reported: 2009-01-20 10:22 PST by Daniel Veditz [:dveditz]
Modified: 2009-10-27 23:07 PDT (History)
20 users (show)
jst: blocking1.9.1-
dveditz: blocking1.9.0.7+
dveditz: wanted1.9.0.x+
samuel.sidler+old: wanted1.8.1.x-
asac: wanted1.8.0.x-
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---

v1 (1.48 KB, patch)
2009-02-04 12:39 PST, Peter Van der Beken [:peterv]
no flags Details | Diff | Splinter Review
v1 (1.43 KB, patch)
2009-02-04 12:46 PST, Peter Van der Beken [:peterv]
bzbarsky: review+
bzbarsky: superreview+
jst: approval1.9.1+
dveditz: approval1.9.0.7+
Details | Diff | Splinter Review

Description User image Daniel Veditz [:dveditz] 2009-01-20 10:22:10 PST
TippingPoint has identified a vulnerability affecting the following 
products: Mozilla Firefox 3.0.x

-- VULNERABILITY DETAILS -----------------------------------------------

This vulnerability allows remote attackers to execute arbitrary code on
vulnerable installations of Mozilla Firefox. User interaction is
required to exploit this vulnerability in that the target must visit a
malicious page.

The specific flaw exists during the browsers garbage collection process.
When multiple DOM elements are cloned and linked to one another and the
browser is reloaded a memory corruption occurs resulting in a double
free. This can be leveraged to execute arbitrary code under the context
of the current user.

The following basic JavaScript will reproduce the issue:

body = document.getElementById('mainbody');
noti = document.createElementNS(xulns,'notification');
elem = document.createElement("div");
statusbar = document.createElementNS(xulns,'statusbarpanel');
clone = statusbar.cloneNode(1);
for(var x=0;x<10;x++) hs();

The body element must be connected to the DOM. After a few reloads of
the website the browser will crash, in most cases during garbage
collection, because it tries to free an object twice. The elem object
can be any element (HTML, SVG, XUL, etc.) The notification object has to
be created and appended to the body element. Just cloning the
statusbarpanel object and appending it to any element, will not trigger
the vulnerability.

-- CREDIT --------------------------------------------------------------

This vulnerability was discovered by:
    * Anonymous
Comment 1 User image Daniel Veditz [:dveditz] 2009-01-20 10:23:27 PST
Seeking more detail and PoC from ZDI. E.g. what does the hs() function do? Seems like it might be an important part of this.
Comment 2 User image Benjamin Smedberg [:bsmedberg] 2009-01-20 10:43:39 PST
Also is this a XUL document or an HTML document?
Comment 3 User image Daniel Veditz [:dveditz] 2009-01-26 15:14:42 PST
Created attachment 358928 [details]
PoC from ZDI (load hold.html)
Comment 4 User image Daniel Veditz [:dveditz] 2009-01-26 15:21:17 PST
Testcase crashes on Mac during GC.

0   libxpconnect.dylib            	0x00d28eca XPCJSRuntime::GCCallback(JSContext*, JSGCStatus) + 1716 (xpcjsruntime.cpp:818)
1   libgklayout.dylib             	0x131dda74 DOMGCCallback(JSContext*, JSGCStatus) + 48 (nsJSEnvironment.cpp:3517)
2   libmozjs.dylib                	0x00232899 js_GC + 4378 (jsgc.c:3536)
3   libmozjs.dylib                	0x0022e1ff js_NewGCThing + 673 (jsgc.c:1765)
4   libmozjs.dylib                	0x002af224 js_NewString + 72 (jsstr.c:2467)
5   libmozjs.dylib                	0x002a76ec js_ConcatStrings + 986 (jsstr.c:167)
6   libmozjs.dylib                	0x00239fb5 js_Interpret + 27544 (jsinterp.c:3684)
7   libmozjs.dylib                	0x0024fde3 js_Execute + 865 (jsinterp.c:1544)
8   libmozjs.dylib                	0x001ef8b0 JS_EvaluateUCScriptForPrincipals + 221 (jsapi.c:4999)
9   libgklayout.dylib             	0x131e11d2 nsJSContext::EvaluateString(nsAString_internal const&, void*, nsIPrincipal*, char const*, unsigned int, unsigned int, nsAString_internal*, int*) + 916 (nsJSEnvironment.cpp:1530)
10  libgklayout.dylib             	0x13210f1f nsGlobalWindow::RunTimeout(nsTimeout*) + 1423 (nsGlobalWindow.cpp:7875)
11  libgklayout.dylib             	0x132115d8 nsGlobalWindow::TimerCallback(nsITimer*, void*) + 54 (nsGlobalWindow.cpp:8228)
12  libxpcom_core.dylib           	0x003b1d60 nsTimerImpl::Fire() + 868 (nsTimerImpl.cpp:401)
13  libxpcom_core.dylib           	0x003b1f8e nsTimerEvent::Run() + 192 (nsTimerImpl.cpp:492)
14  libxpcom_core.dylib           	0x003ab77a nsThread::ProcessNextEvent(int, int*) + 676 (nsThread.cpp:511)
15  libxpcom_core.dylib           	0x003365d4 NS_ProcessPendingEvents_P(nsIThread*, unsigned int) + 146 (nsThreadUtils.cpp:180)
16  libwidget_mac.dylib           	0x11b44d0b nsBaseAppShell::NativeEventCallback() + 181 (nsBaseAppShell.cpp:122)
17  libwidget_mac.dylib           	0x11b003d6 nsAppShell::ProcessGeckoEvents(void*) + 518 (
18      	0x945e063f CFRunLoopRunSpecific + 3215
19      	0x945e0cd8 CFRunLoopRunInMode + 88
20           	0x948382c0 RunCurrentEventLoopInMode + 283
21           	0x948380d9 ReceiveNextEventCommon + 374
22           	0x94837f4d BlockUntilNextEventMatchingListInMode + 106
23              	0x94e7cd7d _DPSNextEvent + 657
24              	0x94e7c630 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
25              	0x94e7566b -[NSApplication run] + 795
26  libwidget_mac.dylib           	0x11afed8c nsAppShell::Run() + 288 (
27  libtoolkitcomps.dylib         	0x127566cc nsAppStartup::Run() + 148 (nsAppStartup.cpp:181)
28  XUL                           	0x000f7a11 XRE_main + 13853 (nsAppRunner.cpp:3193)
29  org.mozilla.firefox           	0x000026d3 main + 709 (nsBrowserApp.cpp:158)
30  org.mozilla.firefox           	0x00001d00 _start + 210
31  org.mozilla.firefox           	0x00001c2d start + 41
Comment 5 User image Daniel Veditz [:dveditz] 2009-01-26 15:30:07 PST
This may be fixed in 1.9.1, my Mac hasn't crashed. I'll try the testcase in a
windows VM next but it may have been fixed by one of the JS bugs Jesse already
smoked out.
Comment 6 User image Martijn Wargers [:mwargers] 2009-01-26 15:58:42 PST
This seems to have been fixed between 2008-11-13 and 2008-11-14:
Fixed somehow by bug 425153?
Comment 7 User image Boris Zbarsky [:bz] (still a bit busy) 2009-01-26 19:06:41 PST
That doesn't seem very likely.... Bug 457022 is in the range too, but also doesn't seem that likely.

Is someone willing to try bisecting?
Comment 8 User image Robert O'Callahan (:roc) (email my personal email if necessary) 2009-01-27 15:12:10 PST
This is surely JS, XPConnect or content. Moving to XPConnect.
Comment 9 User image Johnny Stenback (:jst, 2009-01-27 15:42:04 PST
Sounds like this is not an issue in 1.9.1, so not blocking.
Comment 10 User image Daniel Veditz [:dveditz] 2009-01-28 15:32:31 PST
peterv: looking at that fix range you're the most likely fixer, could you investigate whether your checkins fixed this 1.9.0-blocking externally-reported security bug? Thanks!
Comment 11 User image Samuel Sidler (old account; do not CC) 2009-02-02 07:54:18 PST
Peterv: Any luck on this?
Comment 12 User image Peter Van der Beken [:peterv] 2009-02-03 15:36:55 PST
I bisected and this is definitely fixed by 457022, but we can't take that on branch. Trying to figure out what's going on.
Comment 13 User image Peter Van der Beken [:peterv] 2009-02-04 12:39:46 PST
Created attachment 360558 [details] [diff] [review]

This was a hard one to debug, but it's a simple problem. An element is destroyed and its destructor calls UnbindFromTree on its children, one of which is a XUL element. UnbindFromTree unhooks any XBL bindings and we end up in nsXBLBinding::ChangeDocument. ChangeDocument tries to wrap the XUL element but for some reason there's no existing wrapper anymore (we probably unlinked the document from cycle collection?) and we create a new wrapper. The PreCreate hook for the XUL element uses the parent node as the parent for the wrapper, the parent node is the element that is being destroyed and so we wrap that dying object. At some point the wrapper tries to access its native object, but it is already dead.

The fix is to null out the parent before unhooking XBL bindings. I made nulling the parent the first thing in UnbindFromTree, none of the things we did before it really need the parent. The reason why this is fixed on trunk is probably because we store the wrapper in the element and not in a hash in the ownerDocument, so the wrapper for XBL-bound nodes stays alive even when the ownerDocument is unlinked or dies (and the parent is kept alive too). I think we should still take this fix on trunk too, it looks safer.
Comment 14 User image Peter Van der Beken [:peterv] 2009-02-04 12:46:01 PST
Created attachment 360562 [details] [diff] [review]

Sorry, wrong patch. We must not unset PARENT_BIT_INDOCUMENT before calling GetCurrentDoc.
Comment 15 User image Daniel Veditz [:dveditz] 2009-02-04 15:31:01 PST
Comment on attachment 360562 [details] [diff] [review]

Approved for, a=dveditz for release-drivers.
Comment 16 User image Peter Van der Beken [:peterv] 2009-02-05 01:56:39 PST
Checked in to trunk and 1.9.0.x branch. Haven't checked in the testcase.
Comment 17 User image Daniel Veditz [:dveditz] 2009-02-12 09:37:14 PST
Comment on attachment 360562 [details] [diff] [review]

This is already in 1.9.1
Comment 18 User image Daniel Veditz [:dveditz] 2009-02-12 10:13:08 PST
peterv: Although the fixed code in UnbindFromTree looks similar on the 1.8 branch, this exploit doesn't crash the browser. I'm sure notifications have changed a lot between the two branches. I'm assuming we don't need this fix on the 1.8 branch, but please renominate for if you think it would be safer if we took it.
Comment 19 User image Peter Van der Beken [:peterv] 2009-02-12 13:52:40 PST
Comment on attachment 360562 [details] [diff] [review]

This hasn't landed on 1.9.1. Like on trunk the crash is already fixed by bug 457022 but I still think it'd be a good idea to take this patch on branch because it's safer and low-risk.
Comment 20 User image Peter Van der Beken [:peterv] 2009-02-12 14:15:00 PST
(In reply to comment #18)
> I'm assuming we don't need this fix on
> the 1.8 branch, but please renominate for if you think it
> would be safer if we took it.

I think we probably don't need it on 1.8.1 because we don't have cycle collection and so the wrappers don't get unlinked.
Comment 21 User image Al Billings [:abillings] 2009-02-13 12:20:56 PST
Verified the crashes using the POC testcase with and the fix in with Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv: Gecko/2009021304 GranParadiso/3.0.7pre. This is fixed now.
Comment 22 User image Johnny Stenback (:jst, 2009-02-19 11:27:06 PST
Comment on attachment 360562 [details] [diff] [review]

I think we should take this on the branch to be consistent with the trunk, even if it's not strictly needed there.
Comment 23 User image Johnny Stenback (:jst, 2009-03-18 23:08:10 PDT
Um, I'm guessing my above comment was either meant for a different bug, or I was really confused when I made the above comment...
Comment 24 User image Jesse Ruderman 2009-05-25 19:24:14 PDT
peterv, do you know if there's a simple testcase for this bug that can be used as a crashtest?

Note You need to log in before you can comment on or make changes to this bug.