Bug 592366 - Do not execute scripts whose owner doc is not the doc of the inserter parser or not the owner doc at the time of starting the script load. r=jonas, a=blocking2.0-betaN.
authorHenri Sivonen <hsivonen@iki.fi>
Wed, 08 Dec 2010 14:37:19 +0200
changeset 58891 22f53d50851adf2a0585d2d4624ec9f5697a99c9
parent 58890 16847ac492b39d6321cc3d5183c1365beb945eeb
child 58892 6e5bc06304f9f8a6d9b1328c150750513dd32a7f
push idunknown
push userunknown
push dateunknown
reviewersjonas, blocking2
bugs592366
milestone2.0b8pre
Bug 592366 - Do not execute scripts whose owner doc is not the doc of the inserter parser or not the owner doc at the time of starting the script load. r=jonas, a=blocking2.0-betaN.
content/base/src/nsScriptElement.cpp
content/base/src/nsScriptLoader.cpp
content/base/test/Makefile.in
content/base/test/test_bug592366.html
content/test/reftest/bug592366-1.html
content/test/reftest/bug592366-1.xhtml
content/test/reftest/bug592366-2.html
content/test/reftest/bug592366-2.xhtml
content/test/reftest/bug592366-ref.html
content/test/reftest/bug592366-ref.xhtml
content/test/reftest/child592366-1.html
content/test/reftest/child592366-1.xhtml
content/test/reftest/child592366-2.html
content/test/reftest/child592366-2.xhtml
content/test/reftest/reftest.list
content/test/reftest/script592366-2.js
content/xml/document/src/nsXMLContentSink.cpp
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
--- a/content/base/src/nsScriptElement.cpp
+++ b/content/base/src/nsScriptElement.cpp
@@ -41,16 +41,17 @@
 #include "nsContentUtils.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsPresContext.h"
 #include "nsScriptLoader.h"
 #include "nsIParser.h"
 #include "nsAutoPtr.h"
 #include "nsGkAtoms.h"
+#include "nsContentSink.h"
 
 using namespace mozilla::dom;
 
 NS_IMETHODIMP
 nsScriptElement::ScriptAvailable(nsresult aResult,
                                  nsIScriptElement *aElement,
                                  PRBool aIsInline,
                                  nsIURI *aURI,
@@ -157,18 +158,30 @@ nsScriptElement::MaybeProcessScript()
 
   if (mAlreadyStarted || !mDoneAddingChildren || !cont->IsInDoc() ||
       mMalformed || !HasScriptContent()) {
     return NS_OK;
   }
 
   FreezeUriAsyncDefer();
 
-  nsRefPtr<nsScriptLoader> loader = cont->GetOwnerDoc()->ScriptLoader();
   mAlreadyStarted = PR_TRUE;
+
+  nsIDocument* ownerDoc = cont->GetOwnerDoc();
+  nsCOMPtr<nsIParser> parser = ((nsIScriptElement*)this)->GetCreatorParser();
+  if (parser) {
+    nsCOMPtr<nsIDocument> parserDoc =
+        do_QueryInterface(parser->GetContentSink()->GetTarget());
+    if (ownerDoc != parserDoc) {
+      // Willful violation of HTML5 as of 2010-12-01
+      return NS_OK;
+    }
+  }
+
+  nsRefPtr<nsScriptLoader> loader = ownerDoc->ScriptLoader();
   nsresult scriptresult = loader->ProcessScriptElement(this);
 
   // The only error we don't ignore is NS_ERROR_HTMLPARSER_BLOCK
   // However we don't want to override other success values
   // (such as NS_CONTENT_SCRIPT_IS_EVENTHANDLER)
   if (NS_FAILED(scriptresult) &&
       scriptresult != NS_ERROR_HTMLPARSER_BLOCK) {
     scriptresult = NS_OK;
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -834,25 +834,31 @@ nsScriptLoader::EvaluateScript(nsScriptL
 {
   nsresult rv = NS_OK;
 
   // We need a document to evaluate scripts.
   if (!mDocument) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
+  nsIDocument* ownerDoc = scriptContent->GetOwnerDoc();
+  if (ownerDoc != mDocument) {
+    // Willful violation of HTML5 as of 2010-12-01
+    return NS_ERROR_FAILURE;
+  }
+
   nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
   if (!pwin || !pwin->IsInnerWindow()) {
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
   NS_ASSERTION(globalObject, "windows must be global objects");
 
   // Get the script-type to be used by this element.
-  nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
   PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
                                   nsIProgrammingLanguage::JAVASCRIPT;
   // and make sure we are setup for this type of script.
   rv = globalObject->EnsureScriptEnvironment(stid);
   if (NS_FAILED(rv))
     return rv;
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -420,16 +420,17 @@ include $(topsrcdir)/config/rules.mk
 		test_x-frame-options.html \
 		file_x-frame-options_main.html \
 		file_x-frame-options_page.sjs \
 		test_createHTMLDocument.html \
 		test_bug564047.html \
 		test_bug567350.html \
 		test_bug574596.html \
 		test_bug578096.html \
+		test_bug592366.html \
 		test_bug597345.html \
 		script-1_bug597345.sjs \
 		script-2_bug597345.js \
 		test_bug598877.html \
 		test_bug599588.html \
 		test_bug600466.html \
 		test_bug600468.html \
 		test_bug600471.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug592366.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=592366
+-->
+<head>
+  <title>Test for Bug 592366</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=592366">Mozilla Bug 592366</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe onload='runTest();'></iframe>  
+<iframe onload='runTest();'></iframe>  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+/** Test for Bug 592366 **/
+var iframesToLoad = 2;
+function runTest() {
+  --iframesToLoad;
+  if (iframesToLoad) {
+    return;
+  }
+
+  ok(true, "Obligatory succeeding assertion.");
+
+  var s = document.createElement("script");
+  s.src = "data:text/javascript,parent.ok(false, 'This script should not be executed.');"
+  
+  var iframes = document.getElementsByTagName("iframe");
+
+  iframes[0].contentDocument.body.appendChild(s);
+  iframes[1].contentDocument.body.appendChild(s);
+
+  setTimeout(function() {
+    SimpleTest.finish();
+  }, 500);
+}
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe src=child592366-1.html></iframe>After iframe
+</body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-1.xhtml
@@ -0,0 +1,6 @@
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe src="child592366-1.xhtml"></iframe>After iframe
+</body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-2.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe src=child592366-1.html></iframe>After iframe
+</body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-2.xhtml
@@ -0,0 +1,6 @@
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe src="child592366-1.html"></iframe>After iframe
+</body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-ref.html
@@ -0,0 +1,9 @@
+<html><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe></iframe>After iframe
+<div><p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<p>Middle of Page</p>
+<p>End of Page</p>
+</div></body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug592366-ref.xhtml
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<title>Move node during parse</title>
+</head>
+<body>
+<iframe></iframe>After iframe
+<div><p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<p>Middle of Page</p>
+<p>End of Page</p>
+</div></body></html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/child592366-1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Move node during parse</title>
+</head>
+<body>
+<div>
+<p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<script>
+parent.document.documentElement.lastChild.appendChild(document.getElementsByTagName("div")[0]);
+</script>
+<p>Middle of Page</p>
+<script>
+document.body.insertBefore(document.createTextNode("FAIL"), document.body.firstChild);
+</script>
+<p>End of Page</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/child592366-1.xhtml
@@ -0,0 +1,18 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Move node during parse</title>
+</head>
+<body>
+<div>
+<p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<script>
+parent.document.documentElement.lastChild.appendChild(document.getElementsByTagName("div")[0]);
+</script>
+<p>Middle of Page</p>
+<script>
+document.body.insertBefore(document.createTextNode("FAIL"), document.body.firstChild);
+</script>
+<p>End of Page</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/child592366-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Move node during parse</title>
+</head>
+<body>
+<div>
+<p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<script>
+parent.document.documentElement.lastChild.appendChild(document.getElementsByTagName("div")[0]);
+</script>
+<p>Middle of Page</p>
+<script src="script592366-2.js"></script>
+<p>End of Page</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/child592366-2.xhtml
@@ -0,0 +1,16 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Move node during parse</title>
+</head>
+<body>
+<div>
+<p>This text should not show inside the iframe. It should show inside the parent. Furthermore, there should be text saying "Middle of Page" and then "End of Page" below (also in the parent).</p>
+<script>
+parent.document.documentElement.lastChild.appendChild(document.getElementsByTagName("div")[0]);
+</script>
+<p>Middle of Page</p>
+<script src="script592366-2.js"></script>
+<p>End of Page</p>
+</div>
+</body>
+</html>
--- a/content/test/reftest/reftest.list
+++ b/content/test/reftest/reftest.list
@@ -1,8 +1,12 @@
 == bug453105.html bug453105-ref.html
 == optiontext.html optiontext-ref.html
 == bug456008.xhtml bug456008-ref.html
 == bug439965.html bug439965-ref.html
 == bug427779.xml bug427779-ref.xml
 == bug559996.html bug559996-ref.html
 == bug591981-1.html bug591981-ref.html
 == bug591981-2.html bug591981-ref.html
+== bug592366-1.html bug592366-ref.html
+== bug592366-2.html bug592366-ref.html
+== bug592366-1.xhtml bug592366-ref.xhtml
+== bug592366-2.xhtml bug592366-ref.xhtml
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/script592366-2.js
@@ -0,0 +1,2 @@
+document.body.insertBefore(document.createTextNode("FAIL"), document.body.firstChild);
+
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -509,16 +509,17 @@ nsXMLContentSink::CreateElement(const PR
 
   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
 #ifdef MOZ_SVG
       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
 #endif
     ) {
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
     sele->SetScriptLineNumber(aLineNumber);
+    sele->SetCreatorParser(mParser);
     mConstrainSize = PR_FALSE;
   }
 
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     mPrettyPrintHasFactoredElements = PR_TRUE;
   }
   else {
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -885,16 +885,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsParser, nsIParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsParser, nsIParser)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsParser)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIParser)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
 NS_INTERFACE_MAP_END
 
 // The parser continue event is posted only if
 // all of the data to parse has been passed to ::OnDataAvailable
 // and the parser has been interrupted by the content sink
 // because the processing of tokens took too long.
 
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -83,31 +83,33 @@
 #include "nsHTMLTags.h"
 #include "nsDTDUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIContentSink.h"
 #include "nsIParserFilter.h"
 #include "nsCOMArray.h"
 #include "nsIUnicharStreamListener.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsWeakReference.h"
 
 class nsICharsetConverterManager;
 class nsICharsetAlias;
 class nsIDTD;
 class nsScanner;
 class nsSpeculativeScriptThread;
 class nsIThreadPool;
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4275 )
 #endif
 
 
 class nsParser : public nsIParser,
-                 public nsIStreamListener
+                 public nsIStreamListener,
+                 public nsSupportsWeakReference
 {
   public:
     /**
      * Called on module init
      */
     static nsresult Init();
 
     /**