Propagate the node's principal as the owner to <object> loads as needed, and allow <object data="javascript:"> to work. Bug 353334 and bug 300263, r=biesi, sr=jst, a=dsicore
authorbzbarsky@mit.edu
Mon, 03 Dec 2007 13:57:17 -0800
changeset 8608 6e1c7a6ac8b56f8f1b3855d5c4af901e41b63cb0
parent 8607 1eac563ab419288677dbf2723ad08df24a898322
child 8609 c43741037cb996b2204293e70fef8c3b7fd37fa2
push idunknown
push userunknown
push dateunknown
reviewersbiesi, jst, dsicore
bugs353334, 300263
milestone1.9b2pre
Propagate the node's principal as the owner to <object> loads as needed, and allow <object data="javascript:"> to work. Bug 353334 and bug 300263, r=biesi, sr=jst, a=dsicore
content/base/src/nsObjectLoadingContent.cpp
content/base/test/Makefile.in
content/base/test/test_bug353334.html
docshell/base/nsDocShell.cpp
dom/src/jsurl/nsJSProtocolHandler.cpp
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -55,16 +55,17 @@
 #include "nsIPresShell.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamConverterService.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebNavigationInfo.h"
+#include "nsIScriptChannel.h"
 
 #include "nsPluginError.h"
 
 // Util headers
 #include "prlog.h"
 
 #include "nsAutoPtr.h"
 #include "nsCURILoader.h"
@@ -852,16 +853,33 @@ nsObjectLoadingContent::LoadObject(const
     return NS_OK;
   }
 
   NS_TryToSetImmutable(uri);
 
   return LoadObject(uri, aNotify, aTypeHint, aForceLoad);
 }
 
+static PRBool
+IsAboutBlank(nsIURI* aURI)
+{
+  // XXXbz this duplicates an nsDocShell function, sadly
+  NS_PRECONDITION(aURI, "Must have URI");
+    
+  // GetSpec can be expensive for some URIs, so check the scheme first.
+  PRBool isAbout = PR_FALSE;
+  if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
+    return PR_FALSE;
+  }
+    
+  nsCAutoString str;
+  aURI->GetSpec(str);
+  return str.EqualsLiteral("about:blank");  
+}
+
 nsresult
 nsObjectLoadingContent::LoadObject(nsIURI* aURI,
                                    PRBool aNotify,
                                    const nsCString& aTypeHint,
                                    PRBool aForceLoad)
 {
   LOG(("OBJLC [%p]: Loading object: URI=<%p> notify=%i type=<%s> forceload=%i\n",
        this, aURI, aNotify, aTypeHint.get(), aForceLoad));
@@ -1135,16 +1153,33 @@ nsObjectLoadingContent::LoadObject(nsIUR
     httpChan->SetReferrer(doc->GetDocumentURI());
   }
 
   // MIME Type hint
   if (!aTypeHint.IsEmpty()) {
     chan->SetContentType(aTypeHint);
   }
 
+  // Set up the channel's principal and such, like nsDocShell::DoURILoad does
+  PRBool inheritPrincipal;
+  rv = NS_URIChainHasFlags(aURI,
+                           nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+                           &inheritPrincipal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (inheritPrincipal || IsAboutBlank(aURI)) {
+    chan->SetOwner(thisContent->NodePrincipal());
+  }
+
+  nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
+  if (scriptChannel) {
+    // Allow execution against our context if the principals match
+    scriptChannel->
+      SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
+  }
+
   // AsyncOpen can fail if a file does not exist.
   // Show fallback content in that case.
   rv = chan->AsyncOpen(this, nsnull);
   if (NS_SUCCEEDED(rv)) {
     LOG(("OBJLC [%p]: Channel opened.\n", this));
     mChannel = chan;
     mType = eType_Loading;
   }
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -60,16 +60,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug338541.xhtml \
 		test_bug338679.html \
 		test_bug339494.html \
 		test_bug339494.xhtml \
 		test_bug339494.xul \
 		test_bug343596.html \
 		test_bug352728.html \
 		test_bug352728.xhtml \
+		test_bug353334.html \
 		test_bug355026.html \
 		test_bug357450.js \
 		test_bug357450.html \
 		test_bug357450.xhtml \
 		test_bug357450.xul \
 		test_bug357450_svg.xhtml \
 		test_bug357509.html \
 		test_bug358660.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug353334.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=353334
+-->
+<head>
+  <title>Test for Bug 353334</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" />
+  <script>var x = "PASS"</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=353334">Mozilla Bug 353334</a>
+<p id="display">
+<iframe id="one"></iframe>
+<object id="two" data="about:blank"></object>
+<iframe id="three" src="data:text/html,<body>test</body>"></iframe>
+<object id="four" data="data:text/html,<body>test</body>"></object>
+<iframe id="five" src="javascript:parent.x"></iframe>
+<object id="six" data="javascript:x"></object>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 353334 **/
+SimpleTest.waitForExplicitFinish();
+
+function doPrincipalTest(id) {
+  var doc = $(id).contentDocument;
+
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  is(doc.nodePrincipal, document.nodePrincipal,
+     "Wrong principal for document in node with id='" + id + "'");
+}
+
+function doContentTest(id) {
+  is($(id).contentDocument.documentElement.textContent, "PASS",
+     "Script executed in wrong context in node with id='" + id + "'");
+}
+
+function checkPrincipal() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  is(document.nodePrincipal instanceof Components.interfaces.nsIPrincipal,
+     true,
+     "Should be a principal");
+}
+
+addLoadEvent(function() {
+  checkPrincipal();
+
+  for each (var i in [ "one", "two", "three", "four" ]) {
+    doPrincipalTest(i);
+  }
+
+  for each (i in [ "five", "six" ]) {
+    doContentTest(i);
+  }
+
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
+
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7262,29 +7262,31 @@ nsDocShell::DoURILoad(nsIURI * aURI,
     //      passing in.  In particular, see the code and comments in LoadURI
     //      where we fall back on inheriting the owner if called
     //      from chrome.  That would be very wrong if this code changed
     //      anything but channels that can't provide their own security context!
     //
     //      (Currently chrome URIs set the owner when they are created!
     //      So setting a NULL owner would be bad!)
     //
-
+    // If this code ever changes, change nsObjectLoadingContent::LoadObject
+    // accordingly.
     PRBool inherit;
     // We expect URIInheritsSecurityContext to return success for an
     // about:blank URI, so don't call IsAboutBlank() if this call fails.
     rv = URIInheritsSecurityContext(aURI, &inherit);
     if (NS_SUCCEEDED(rv) && (inherit || IsAboutBlank(aURI))) {
         channel->SetOwner(aOwner);
-        nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
-        if (scriptChannel) {
-            // Allow execution against our context if the principals match
-            scriptChannel->
-                SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
-        }
+    }
+
+    nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
+    if (scriptChannel) {
+        // Allow execution against our context if the principals match
+        scriptChannel->
+            SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
     }
 
     if (aIsNewWindowTarget) {
         nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
         if (props) {
             props->SetPropertyAsBool(
                 NS_LITERAL_STRING("docshell.newWindowTarget"),
                 PR_TRUE);
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -871,16 +871,38 @@ NS_IMETHODIMP
 nsJSChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
 {
     return mStreamChannel->GetLoadGroup(aLoadGroup);
 }
 
 NS_IMETHODIMP
 nsJSChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
 {
+    if (aLoadGroup) {
+        PRBool streamPending;
+        nsresult rv = mStreamChannel->IsPending(&streamPending);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (streamPending) {
+            nsCOMPtr<nsILoadGroup> curLoadGroup;
+            mStreamChannel->GetLoadGroup(getter_AddRefs(curLoadGroup));
+
+            if (aLoadGroup != curLoadGroup) {
+                // Move the stream channel to our new loadgroup.  Make sure to
+                // add it before removing it, so that we don't trigger onload
+                // by accident.
+                aLoadGroup->AddRequest(mStreamChannel, nsnull);
+                if (curLoadGroup) {
+                    curLoadGroup->RemoveRequest(mStreamChannel, nsnull,
+                                                NS_BINDING_RETARGETED);
+                }
+            }
+        }
+    }
+    
     return mStreamChannel->SetLoadGroup(aLoadGroup);
 }
 
 NS_IMETHODIMP
 nsJSChannel::GetOwner(nsISupports* *aOwner)
 {
     return mStreamChannel->GetOwner(aOwner);
 }