Bug 576078 (ZDI-CAN-852)

FrameManager Remote Code Execution Vulnerability (ZDI-CAN-852) (-moz-column, position:absolute)




9 years ago
5 years ago


(Reporter: reed, Assigned: mats)


(Blocks: 1 bug, {regression})

1.9.2 Branch
Dependency tree / graph

Firefox Tracking Flags

(blocking2.0 -, status2.0 unaffected, blocking1.9.2 .13+, status1.9.2 .13-fixed, status1.9.1 unaffected)


(Whiteboard: [sg:dos frame-poisoned][regressed by 411835, dupe of 526217])


(1 attachment)

Posted file PoC
ZDI-CAN-852: Mozilla Firefox FrameManager 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 

    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 implementation of a particular CSS
style when applied to a frame. If an element's contents are replaced
without having a parent, the application will access memory that has
been freed when trying to contact the parent container. This can lead to
code execution under the context of the application.

The bug is triggered when a root frame containing an absolutely
positioned element is removed. Upon removal, the application will
attempt to notify the parent frame to remove the target. This will cause
the application to access the non-existent parent frame and attempt to
fetch a method. Due to the parent frame being freed, this will trigger
an exploitable condition.

nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
                                      nsIContent* aChild,
                                      PRInt32     aIndexInContainer,
                                      RemoveFlags aFlags,
                                      PRBool*     aDidReconstruct)
      // Recover childFrame and parentFrame
      childFrame = mPresShell->GetPrimaryFrameFor(aChild);
      if (!childFrame || childFrame->GetContent() != aChild) {
        // XXXbz the GetContent() != aChild check is needed due to bug
        // Remove it once that's fixed.
        frameManager->ClearUndisplayedContentIn(aChild, aContainer);
        return NS_OK;
      parentFrame = childFrame->GetParent();
      parentType = parentFrame->GetType();
    // See if the child frame is an out-of-flow
    if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
      nsPlaceholderFrame* placeholderFrame =
      NS_ASSERTION(placeholderFrame, "No placeholder for

      // Now we remove the out-of-flow frame
      // XXX has to be done first for now: for floats, the block's line
      // contains an array of pointers to the placeholder - we have to
      // remove the float first (which gets rid of the lines
      // reference to the placeholder and float) and then remove the
      // placeholder
      rv = frameManager->RemoveFrame(parentFrame,

      // Remove the placeholder frame first (XXX second for now) (so
      // that it doesn't retain a dangling pointer to memory)
      nsIFrame* placeholderParent = placeholderFrame->GetParent();
      ::DeletingFrameSubtree(frameManager, placeholderFrame);
      rv |= frameManager->RemoveFrame(placeholderParent,
                                      nsnull, placeholderFrame);     //
    } else {
      // Notify the parent frame that it should delete the frame
      // check for a table caption which goes on an additional child
list with a different parent
      nsIFrame* outerTableFrame; 
      if (GetCaptionAdjustedParent(parentFrame, childFrame,
&outerTableFrame)) {
        rv = frameManager->RemoveFrame(outerTableFrame,
      else {
        rv = frameManager->RemoveFrame(parentFrame, nsnull,

When removing the frame, the application will call the method from
already freed aParentFrame object.

nsFrameManager::RemoveFrame(nsIFrame*       aParentFrame,
                            nsIAtom*        aListName,
                            nsIFrame*       aOldFrame)
  PRBool wasDestroyingFrames = mIsDestroyingFrames;
  mIsDestroyingFrames = PR_TRUE;

  // In case the reflow doesn't invalidate anything since it just
  // a gap where the old frame was, we invalidate it here.  (This is
  // reasonably likely to happen when removing a last child in a way
  // that doesn't change the size of the parent.)
  // This has to sure to invalidate the entire overflow rect; this
  // is important in the presence of absolute positioning

  nsresult rv = aParentFrame->RemoveFrame(aListName, aOldFrame);    //

  mIsDestroyingFrames = wasDestroyingFrames;

  return rv;

Version(s)  tested: Mozilla Firefox 3.6.3
Platform(s) tested: Windows XP SP3

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

This vulnerability was discovered by:
    * wushi of team509


9 years ago
Summary: FrameManager Remote Code Execution Vulnerability (ZDI-CAN-852) → FrameManager Remote Code Execution Vulnerability (ZDI-CAN-852) (-moz-column, position:absolute)


9 years ago
blocking1.9.1: --- → ?
blocking1.9.2: --- → ?
blocking2.0: --- → ?
status1.9.1: --- → ?
status1.9.2: --- → ?
status2.0: --- → ?

Mozilla/5.0 (X11; U; Linux i686; en-US; rv: Gecko/20100630 Namoroka/3.6.7pre
Can't get this to crash on trunk... Maybe some other change fixed this already?

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:2.0b2pre) Gecko/20100630 Minefield/4.0b2pre
(In reply to comment #3)
> Are you bisecting to figure out what, or should somebody else?

Somebody else should, please.

Comment 5

9 years ago
Before the crash I get:

###!!! ASSERTION: out-of-flow is already in the destroy queue: 'aDestroyQueue.IndexOf(outOfFlowFrame) == kNotFound', file /Users/jruderman/moz192/layout/base/nsCSSFrameConstructor.cpp, line 7104

Since this bug's crash signature is [@ nsFrameManager::RemoveFrame], it could be the same as bug 526217, which was fixed on trunk in bug 508473.
That seems to be the case, since it was in fact fixed between the 2009-12-23-03-mozilla-central and 2009-12-24-03-mozilla-central Linux x86_64 nightlies.
I couldn't get 3.5.x to crash (on mac). Is the problem merely masked or did we introduce it along the way?

The 3.6 crash looks like a frame-poisoned address -- are we really vulnerable?
status1.9.2: ? → wanted
Keywords: regression, regressionwindow-wanted
zwol thought 3.5.x continuing to work might be a bad sign -- maybe we used a dead but not overwritten frame? But I ran it in a debug build and still had no problems.
Clearing sg:critical pending an answer to the frame-poisoning question in comment 9.
Whiteboard: [sg:critical?]


9 years ago
Whiteboard: [sg:critical]
blocking1.9.1: ? → needed
blocking1.9.2: ? → needed
status1.9.1: ? → wanted
No longer depends on: 536721
Whiteboard: [sg:critical] → [sg:critical?] frame-poisoning DoS on 1.9.2+
Depends on: 536721
Version: unspecified → 1.9.2 Branch

Comment 12

9 years ago
For Firefox 3.5, some alternatives to backporting bug 508473:
* Backport frame poisoning
* Disable -moz-column
* Accelerate EOL (it's been 6 months since Firefox 3.6's release)
Whiteboard: [sg:critical?] frame-poisoning DoS on 1.9.2+ → [sg:critical?] frame-poisoning DoS on 1.9.2+ [critsmash:investigating]

Comment 13

9 years ago
cc'ing wu shi

Comment 14

9 years ago
from today's triage session we summarized from commments 9 and 10 that a crash can't be reproduced on 3.5.x so not exploitable there, and 3.6.x crashes at a frame poisoned address so no exploit there either.   roc may have more, but does that summary sound correct?


9 years ago
Blocks: 526587
This doesn't affect trunk, so not blocking.
blocking2.0: ? → -
status2.0: ? → unaffected


9 years ago
Whiteboard: [sg:critical?] frame-poisoning DoS on 1.9.2+ [critsmash:investigating] → [sg:dos (critical w/out frame-poisoning)][mysteriously, can't reproduce on 1.9.1][critsmash:investigating]
This does look like a dupe of Martijn's bug 526217, which was a regression from bug 411835. That never landed on the 1.9.1 branch which explains why it's unaffected.
Blocks: 411835
blocking1.9.1: needed → ---
status1.9.1: wanted → unaffected
Whiteboard: [sg:dos (critical w/out frame-poisoning)][mysteriously, can't reproduce on 1.9.1][critsmash:investigating] → [sg:dos (critical w/out frame-poisoning)][regressed from 411835, dupe of 526217?][critsmash:investigating]
Alias: ZDI-CAN-852


9 years ago
Alias: ZDI-CAN-852
Alias: ZDI-CAN-852
Whiteboard: [sg:dos (critical w/out frame-poisoning)][regressed from 411835, dupe of 526217?][critsmash:investigating] → [sg:dos frame-poisoned][regressed by 411835, dupe of 526217]
Fixed by bug 526217.
Last Resolved: 9 years ago
status1.9.2: wanted → .13-fixed
Resolution: --- → FIXED


9 years ago
Assignee: nobody → matspal
(In reply to comment #18)
> Fixed by bug 526217.

er, I mean bug 468563.
setting blocking to match bug 468563 (also, ZDI is already expecting this to be fixed in the December release)
blocking1.9.2: needed → .13+
Group: core-security
Issue is resolved - clearing old keywords - qa-wanted clean-up
Keywords: regressionwindow-wanted
You need to log in before you can comment on or make changes to this bug.