Closed
Bug 586878
(ZDI-CAN-883)
Opened 14 years ago
Closed 13 years ago
nsFrameManager Remote Code Execution Vulnerability (ZDI-CAN-883)
Categories
(Core :: CSS Parsing and Computation, defect)
Core
CSS Parsing and Computation
Tracking
()
RESOLVED
FIXED
mozilla2.0
Tracking | Status | |
---|---|---|
status2.0 | --- | unaffected |
blocking1.9.2 | --- | - |
status1.9.2 | --- | wontfix |
status1.9.1 | --- | ? |
People
(Reporter: reed, Unassigned)
References
(Blocks 1 open bug)
Details
(Keywords: crash, regression, testcase, Whiteboard: [sg:dos] frame-poisoned crash, fixed on trunk by 508473)
Attachments
(2 files)
ZDI-CAN-883: Mozilla Firefox nsFrameManager Remote Code Execution Vulnerability -- CVSS ---------------------------------------------------------------- 10, (AV:N/AC:L/Au:N/C:C/I:C/A:C) -- ABSTRACT ------------------------------------------------------------ TippingPoint has identified a vulnerability affecting the following products: Mozilla Firefox 3.6.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 or open a malicious file. The specific flaw exists within the way the application recursively destroys frames. When a frame contains a child element with a particular style during destruction, the application will add 2 references of the overflown element to a list. On destruction of the frame, the application will then iterate through this list, and then free the reference twice. This can lead to code execution under the context of the application. The issue is located within the implementation of nsCSSFrameConstructor.cpp. When calling DoDeletingFrameSubtree, the application will add a reference to the div with the large attribute to the destroyQueue. When the application destroys the current frame, the following function will get called. This will determine which frames will be destroyed by calling a recursive function and then adding each subelement to a list called destroyQueue. This will then call DoDeletingFrameSubtree. layout/base/nsCSSFrameConstructor.cpp:7129 static nsresult DeletingFrameSubtree(nsFrameManager* aFrameManager, nsIFrame* aFrame) { NS_ENSURE_TRUE(aFrame, NS_OK); // XXXldb Remove this sometime in the future. // If there's no frame manager it's probably because the pres shell is // being destroyed. if (NS_UNLIKELY(!aFrameManager)) { return NS_OK; } nsAutoTArray<nsIFrame*, 8> destroyQueue; // If it's a "special" block-in-inline frame, then we can't really deal. // That really shouldn't be happening. NS_ASSERTION(!IsFrameSpecial(aFrame), "DeletingFrameSubtree on a special frame. Prepare to crash."); do { DoDeletingFrameSubtree(aFrameManager, destroyQueue, aFrame, aFrame); // XXX ... This will enter the recursive function. This function will identify containers and frames that are out of flow and will add them to an argument that's provided by the caller. layout/base/nsCSSFrameConstructor.cpp:7148 static void DoDeletingFrameSubtree(nsFrameManager* aFrameManager, nsTArray<nsIFrame*>& aDestroyQueue, nsIFrame* aRemovedFrame, nsIFrame* aFrame) { #undef RECURSE #define RECURSE(top, child) \ DoDeletingFrameSubtree(aFrameManager, aDestroyQueue, (top), (child)); \ // XXX DoDeletingOverflowContainers(aFrameManager, aDestroyQueue, (top), (child)); // XXX // Remove the mapping from the content object to its frame. nsIContent* content = aFrame->GetContent(); if (content) { aFrameManager->RemoveAsPrimaryFrame(content, aFrame); aFrameManager->ClearAllUndisplayedContentIn(content); } nsIAtom* childListName = nsnull; PRInt32 childListIndex = 0; ... // Queue the out-of-flow frame to be destroyed only if aRemovedFrame is _not_ // one of its ancestor frames or if it is a popup frame. // If aRemovedFrame is an ancestor of the out-of-flow frame, then // the out-of-flow frame will be destroyed by aRemovedFrame. if (outOfFlowFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP || !nsLayoutUtils::IsProperAncestorFrame(aRemovedFrame, outOfFlowFrame)) { NS_ASSERTION(aDestroyQueue.IndexOf(outOfFlowFrame) == kNotFound, "out-of-flow is already in the destroy queue"); aDestroyQueue.AppendElement(outOfFlowFrame); // XXX // Recurse into the out-of-flow, it is now the aRemovedFrame. RECURSE(outOfFlowFrame, outOfFlowFrame); } else { // Also recurse into the out-of-flow when it's a descendant of aRemovedFrame // since we don't walk those lists, see |childListName| increment below. RECURSE(aRemovedFrame, outOfFlowFrame); } } } One of the recursive functions will add an overflown container to the destroyQueue. layout/base/nsCSSFrameConstructor.cpp:7014 static void DoDeletingOverflowContainers(nsFrameManager* aFrameManager, nsTArray<nsIFrame*>& aDestroyQueue, nsIFrame* aRemovedFrame, nsIFrame* aFrame) { // The invariant that "continuing frames should be found as part of the // walk over the top-most frame's continuing frames" does not hold for // out-of-flow overflow containers, so we need to walk them too. // Note that DoDeletingFrameSubtree() skips the child lists where // overflow containers live so we won't process them twice. const PRBool orphanSubtree = aRemovedFrame == aFrame; for (nsIFrame* next = aFrame->GetNextContinuation(); next && (next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER); next = next->GetNextContinuation()) { DoDeletingFrameSubtree(aFrameManager, aDestroyQueue, // XXX orphanSubtree ? next : aRemovedFrame, next); } } After populating the destroyQueue via the recursive function, the application will iterate through each element and destroy them. This will free the element twice. layout/base/nsCSSFrameConstructor.cpp:7125 // Now destroy any out-of-flow frames that have been enqueued for // destruction. for (PRInt32 i = destroyQueue.Length() - 1; i >= 0; --i) { nsIFrame* outOfFlowFrame = destroyQueue[i]; // Ask the out-of-flow's parent to delete the out-of-flow // frame from the right list. aFrameManager->RemoveFrame(outOfFlowFrame->GetParent(), // XXX GetChildListNameFor(outOfFlowFrame), outOfFlowFrame); } return NS_OK; } Version(s) tested: Mozilla Firefox Platform(s) tested: Windows XP SP3 -- CREDIT -------------------------------------------------------------- This vulnerability was discovered by: * regenrecht
Reporter | ||
Updated•14 years ago
|
blocking1.9.1: --- → ?
blocking1.9.2: --- → ?
blocking2.0: --- → ?
status1.9.1:
--- → ?
status1.9.2:
--- → ?
Reporter | ||
Comment 1•14 years ago
|
||
I am unable to get this to crash on trunk or 3.6.x on Linux 32-bit... Mozilla/5.0 (X11; Linux i686; rv:2.0b4pre) Gecko/20100812 Minefield/4.0b4pre Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.9pre) Gecko/20100812 Namoroka/3.6.9pre
Keywords: crash
Whiteboard: [sg:critical?]
Comment 2•14 years ago
|
||
In FF3.5.x I only see the assertion ###!!! ASSERTION: Nothing to handle this event!: 'frame', file /Users/daniel/dev/ffcentral/moz191/layout/base/nsPresShell.cpp, line 6006 ten times with the PoC, but no crash.
Comment 3•14 years ago
|
||
With a slight tweak, it is crashing for me, by removing the style of the first styled element. This crashes in 3.6.8, but not in trunk: http://crash-stats.mozilla.com/report/index/0efe3227-7adf-43fa-aa1c-12fe12100813 0 xul.dll nsFrameManager::RemoveFrame layout/base/nsFrameManager.cpp:735 1 xul.dll nsCSSFrameConstructor::ContentRemoved
Comment 4•14 years ago
|
||
On trunk, this was fixed between 2009-12-16 and 2009-12-26, I guess bug 508473 fixed this.
Comment 5•14 years ago
|
||
On 3.6.9pre I get bp-7aab4c4c-cc7a-4b32-a44c-b1fba2100814 so that's looking like a frame-poisoned crash in 3.6.x I still don't crash in 3.5.x even with Martijn's modified testcase.
Keywords: regression,
regressionwindow-wanted
Whiteboard: [sg:dos] frame-poisoned crash
Comment 6•14 years ago
|
||
Not blocking a 1.9.2 release if it's not exploitable. Appears WFM on 2.0 (I agree w/Martijn in comment 4 that bug 508473 looks like a likely fix). Unsure whether 3.5 is truly unaffected or if it's just masked and could be exposed through a different testcase.
blocking1.9.1: ? → ---
blocking1.9.2: ? → -
blocking2.0: ? → ---
Keywords: crash
Version: unspecified → 1.9.2 Branch
Updated•14 years ago
|
Blocks: PoisonFrameCrash
Updated•14 years ago
|
Alias: ZDI-CAN-883
Reporter | ||
Updated•14 years ago
|
Alias: ZDI-CAN-883
Updated•14 years ago
|
Whiteboard: [sg:dos] frame-poisoned crash → [sg:dos] frame-poisoned crash, fixed on trunk by 508473
Reporter | ||
Updated•14 years ago
|
Alias: ZDI-CAN-883
Comment 7•13 years ago
|
||
We decided bug 508473 is out of scope for the 1.9.2 branch to fix a DoS so not much point to tracking this as a branch bug. Fixed on trunk, wontfix on branch.
Status: NEW → RESOLVED
Closed: 13 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla2.0
Version: 1.9.2 Branch → unspecified
Updated•9 years ago
|
Group: core-security
Updated•9 years ago
|
Keywords: regressionwindow-wanted
You need to log in
before you can comment on or make changes to this bug.
Description
•