Changeset 77333 in webkit


Ignore:
Timestamp:
Feb 1, 2011 4:22:52 PM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2011-02-01 chris reiss <christopher.reiss@nokia.com>

Reviewed by Adam Barth.

Self-replicating code makes Safari hang and eventually crash
https://bugs.webkit.org/show_bug.cgi?id=15123

  • fast/dom/Document/document-close-iframe-load-expected.txt: Added.
  • fast/dom/Document/document-close-iframe-load.html: Added.
  • fast/dom/Document/document-close-nested-iframe-load-expected.txt: Added.
  • fast/dom/Document/document-close-nested-iframe-load.html: Added.
  • fast/dom/Document/document-write-recursion-expected.txt: Added.
  • fast/dom/Document/document-write-recursion.html: Added.

2011-02-01 chris reiss <christopher.reiss@nokia.com>

Reviewed by Adam Barth.

Self-replicating code makes Safari hang and eventually crash
https://bugs.webkit.org/show_bug.cgi?id=15123

Here we are replicating the Firefox safeguard against
recursive document.write( ) 's.

See https://bug197052.bugzilla.mozilla.org/attachment.cgi?id=293907 in bug
https://bugzilla.mozilla.org/show_bug.cgi?id=197052 . Firefox does two things -

a) imposes a recursion limit of 20 on document.write( ) and
b) once that limit is passed, panics all the way the call stack (rather than just returning one level.)

To see why this is necessary, consider the script :

<script>

var t = document.body.innerHTML;
document.write(t);

</script>

This will create a tree both broad and deep as the script keeps appending itself to the text. If
we just return one level after the recursion limit is reached, we still allow millions of copies to
duplicate (and execute).

The recursion is fortunately depth-first, so as soon as we cross this limit, we panic up the callstack
to prevent this situation. (IE apparently does the same thing, with a lower recursion limit.)

Test: fast/dom/Document/document-write-recursion.html
Test: fast/dom/Document/document-close-iframe-load.html
Test: fast/dom/Document/document-close-nested-iframe-load.html

  • dom/Document.cpp: (WebCore::Document::Document): (WebCore::Document::write):
  • dom/Document.h:
Location:
trunk
Files:
6 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r77332 r77333  
     12011-02-01  chris reiss  <christopher.reiss@nokia.com>
     2
     3        Reviewed by Adam Barth.
     4
     5        Self-replicating code makes Safari hang and eventually crash
     6        https://bugs.webkit.org/show_bug.cgi?id=15123
     7
     8        * fast/dom/Document/document-close-iframe-load-expected.txt: Added.
     9        * fast/dom/Document/document-close-iframe-load.html: Added.
     10        * fast/dom/Document/document-close-nested-iframe-load-expected.txt: Added.
     11        * fast/dom/Document/document-close-nested-iframe-load.html: Added.
     12        * fast/dom/Document/document-write-recursion-expected.txt: Added.
     13        * fast/dom/Document/document-write-recursion.html: Added.
     14
    1152011-02-01  Dimitri Glazkov  <dglazkov@chromium.org>
    216
  • trunk/Source/WebCore/ChangeLog

    r77329 r77333  
     12011-02-01  chris reiss  <christopher.reiss@nokia.com>
     2
     3        Reviewed by Adam Barth.
     4
     5        Self-replicating code makes Safari hang and eventually crash
     6        https://bugs.webkit.org/show_bug.cgi?id=15123
     7
     8       
     9        Here we are replicating the Firefox safeguard against
     10        recursive document.write( ) 's.
     11
     12        See  https://bug197052.bugzilla.mozilla.org/attachment.cgi?id=293907 in bug
     13        https://bugzilla.mozilla.org/show_bug.cgi?id=197052 .   Firefox does two things -
     14            a) imposes a recursion limit of 20 on document.write( ) and
     15            b) once that limit is passed, panics all the way the call stack (rather than just returning one level.)
     16        To see why this is necessary, consider the script :
     17
     18        <script>
     19           var t = document.body.innerHTML;
     20           document.write(t);
     21        </script>
     22
     23        This will create a tree both broad and deep as the script keeps appending itself to the text.   If
     24        we just return one level after the recursion limit is reached, we still allow millions of copies to
     25        duplicate (and execute).   
     26
     27        The recursion is fortunately depth-first, so as soon as we cross this limit, we panic up the callstack
     28        to prevent this situation.    (IE apparently does the same thing, with a lower recursion limit.)
     29
     30        Test: fast/dom/Document/document-write-recursion.html       
     31        Test: fast/dom/Document/document-close-iframe-load.html
     32        Test: fast/dom/Document/document-close-nested-iframe-load.html
     33
     34
     35        * dom/Document.cpp:
     36        (WebCore::Document::Document):
     37        (WebCore::Document::write):
     38        * dom/Document.h:
     39
    1402011-02-01  Johnny Ding  <jnd@chromium.org>
    241
  • trunk/Source/WebCore/dom/Document.cpp

    r77262 r77333  
    103103#include "MutationEvent.h"
    104104#include "NameNodeList.h"
     105#include "NestingLevelIncrementer.h"
    105106#include "NodeFilter.h"
    106107#include "NodeIterator.h"
     
    222223// #define INSTRUMENT_LAYOUT_SCHEDULING 1
    223224
     225static const unsigned cMaxWriteRecursionDepth = 21;
     226
    224227// This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
    225228// FIXME: For faster machines this value can really be lowered to 200.  250 is adequate, but a little high
     
    425428    , m_directionSetOnDocumentElement(false)
    426429    , m_writingModeSetOnDocumentElement(false)
     430    , m_writeRecursionIsTooDeep(false)
     431    , m_writeRecursionDepth(0)
    427432#if ENABLE(REQUEST_ANIMATION_FRAME)
    428433    , m_nextRequestAnimationFrameCallbackId(0)
     
    21672172void Document::write(const SegmentedString& text, Document* ownerDocument)
    21682173{
     2174    NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth);
     2175
     2176    m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep;
     2177    m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep;
     2178
     2179    if (m_writeRecursionIsTooDeep)
     2180       return;
     2181
    21692182#ifdef INSTRUMENT_LAYOUT_SCHEDULING
    21702183    if (!ownerElement())
  • trunk/Source/WebCore/dom/Document.h

    r77239 r77333  
    13831383    DocumentTiming m_documentTiming;
    13841384    RefPtr<MediaQueryMatcher> m_mediaQueryMatcher;
     1385    bool m_writeRecursionIsTooDeep;
     1386    unsigned m_writeRecursionDepth;
    13851387
    13861388#if ENABLE(REQUEST_ANIMATION_FRAME)
Note: See TracChangeset for help on using the changeset viewer.