Bug 341604 - modify CheckMayLoad to allow sandboxed workers to load blob and data URIs r=jst
authorIan Melven <imelven@mozilla.com>
Mon, 20 Aug 2012 11:34:33 -0700
changeset 108824 7bd4f494eb063a845015bd721b808126ec680c22
parent 108823 9eb507cc06e52d4da8abb77403949781a22e2042
child 108825 b5cda76908404feac21cbed1236d97a64947a0e5
push id214
push userakeybl@mozilla.com
push dateWed, 14 Nov 2012 20:38:59 +0000
treeherdermozilla-release@c8b08ec8e1aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs341604
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 341604 - modify CheckMayLoad to allow sandboxed workers to load blob and data URIs r=jst
caps/idl/nsIPrincipal.idl
caps/include/nsNullPrincipal.h
caps/include/nsPrincipal.h
caps/src/nsNullPrincipal.cpp
caps/src/nsPrincipal.cpp
caps/src/nsScriptSecurityManager.cpp
caps/src/nsSystemPrincipal.cpp
content/base/public/nsContentUtils.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsCrossSiteListenerProxy.cpp
content/base/src/nsDocument.cpp
content/base/src/nsXMLHttpRequest.cpp
content/xbl/src/nsXBLService.cpp
content/xml/document/src/nsXMLDocument.cpp
content/xul/document/src/nsXULDocument.cpp
content/xul/templates/src/nsXULTemplateBuilder.cpp
docshell/base/nsDocShell.cpp
dom/workers/ScriptLoader.cpp
layout/style/Loader.cpp
rdf/base/src/nsRDFXMLDataSource.cpp
--- a/caps/idl/nsIPrincipal.idl
+++ b/caps/idl/nsIPrincipal.idl
@@ -16,17 +16,17 @@ struct JSPrincipals;
 
 interface nsIURI;
 interface nsIContentSecurityPolicy;
 
 [ptr] native JSContext(JSContext);
 [ptr] native JSPrincipals(JSPrincipals);
 [ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
 
-[scriptable, uuid(6df7d16d-5b26-42a1-b1f7-069d46c37aa8)]
+[scriptable, uuid(825ffce8-962d-11e1-aef3-8f2b6188709b)]
 interface nsIPrincipal : nsISerializable
 {
     /**
      * Values of capabilities for each principal. Order is
      * significant: if an operation is performed on a set
      * of capabilities, the minimum is computed.
      */
     const short ENABLE_DENIED                = 1;
@@ -168,33 +168,43 @@ interface nsIPrincipal : nsISerializable
      */
     boolean subsumesIgnoringDomain(in nsIPrincipal other);
 
     /**
      * Checks whether this principal is allowed to load the network resource
      * located at the given URI under the same-origin policy. This means that
      * codebase principals are only allowed to load resources from the same
      * domain, the system principal is allowed to load anything, and null
-     * principals are not allowed to load anything.
+     * principals are not allowed to load anything. This is changed slightly
+     * by the optional flag allowIfInheritsPrincipal (which defaults to false)
+     * which allows the load of a data: URI (which inherits the principal of
+     * its loader) or a URI with the same principal as its loader (eg. a 
+     * Blob URI).
+     * In these cases, with allowIfInheritsPrincipal set to true, the URI can
+     * be loaded by a null principal.
      *
      * If the load is allowed this function does nothing. If the load is not
      * allowed the function throws NS_ERROR_DOM_BAD_URI.
      *
      * NOTE: Other policies might override this, such as the Access-Control
      *       specification.
      * NOTE: The 'domain' attribute has no effect on the behaviour of this
      *       function.
      *
      *
      * @param uri    The URI about to be loaded.
      * @param report If true, will report a warning to the console service
      *               if the load is not allowed.
+     * @param allowIfInheritsPrincipal   If true, the load is allowed if the
+     *                                   loadee inherits the principal of the
+     *                                   loader.
      * @throws NS_ERROR_DOM_BAD_URI if the load is not allowed.
      */
-    void checkMayLoad(in nsIURI uri, in boolean report);
+    void checkMayLoad(in nsIURI uri, in boolean report,
+                      in boolean allowIfInheritsPrincipal);
 
     /**
      * The subject name for the certificate.  This actually identifies the
      * subject of the certificate.  This may well not be a string that would
      * mean much to a typical user on its own (e.g. it may have a number of
      * different names all concatenated together with some information on what
      * they mean in between).
      *
--- a/caps/include/nsNullPrincipal.h
+++ b/caps/include/nsNullPrincipal.h
@@ -10,16 +10,17 @@
  */
 
 #ifndef nsNullPrincipal_h__
 #define nsNullPrincipal_h__
 
 #include "nsIPrincipal.h"
 #include "nsJSPrincipals.h"
 #include "nsCOMPtr.h"
+#include "nsPrincipal.h"
 
 class nsIURI;
 
 #define NS_NULLPRINCIPAL_CLASSNAME "nullprincipal"
 #define NS_NULLPRINCIPAL_CID \
 { 0xdd156d62, 0xd26f, 0x4441, \
  { 0x9c, 0xdb, 0xe8, 0xf0, 0x91, 0x07, 0xc2, 0x73 } }
 #define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
--- a/caps/include/nsPrincipal.h
+++ b/caps/include/nsPrincipal.h
@@ -8,16 +8,19 @@
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsVoidArray.h"
 #include "nsHashtable.h"
 #include "nsJSPrincipals.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsIProtocolHandler.h"
+#include "nsNetUtil.h"
+#include "nsScriptSecurityManager.h"
 
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class DomainPolicy; 
 
 class nsBasePrincipal : public nsJSPrincipals
 {
 public:
@@ -118,17 +121,17 @@ public:
   NS_IMETHOD EqualsIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD GetHashValue(PRUint32* aHashValue);
   NS_IMETHOD GetURI(nsIURI** aURI);
   NS_IMETHOD GetDomain(nsIURI** aDomain);
   NS_IMETHOD SetDomain(nsIURI* aDomain);
   NS_IMETHOD GetOrigin(char** aOrigin);
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
+  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
   NS_IMETHOD GetAppId(PRUint32* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
 
@@ -153,16 +156,33 @@ public:
                               bool aIsCert,
                               bool aTrusted,
                               PRUint32 aAppId,
                               bool aInMozBrowser);
 
   virtual void GetScriptLocation(nsACString& aStr) MOZ_OVERRIDE;
   void SetURI(nsIURI* aURI);
 
+  static bool IsPrincipalInherited(nsIURI* aURI) {
+    // return true if the loadee URI has
+    // the URI_INHERITS_SECURITY_CONTEXT flag set.
+    bool doesInheritSecurityContext;
+    nsresult rv =
+    NS_URIChainHasFlags(aURI,
+                        nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+                        &doesInheritSecurityContext);
+
+    if (NS_SUCCEEDED(rv) && doesInheritSecurityContext) {
+      return true;
+    }
+
+    return false;
+  }
+
+
   /**
    * Computes the puny-encoded origin of aURI.
    */
   static nsresult GetOriginForURI(nsIURI* aURI, char **aOrigin);
 
   nsCOMPtr<nsIURI> mDomain;
   nsCOMPtr<nsIURI> mCodebase;
   PRUint32 mAppId;
@@ -197,17 +217,17 @@ public:
   NS_IMETHOD EqualsIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD GetHashValue(PRUint32* aHashValue);
   NS_IMETHOD GetURI(nsIURI** aURI);
   NS_IMETHOD GetDomain(nsIURI** aDomain);
   NS_IMETHOD SetDomain(nsIURI* aDomain);
   NS_IMETHOD GetOrigin(char** aOrigin);
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
+  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
   NS_IMETHOD GetAppId(PRUint32* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
   
--- a/caps/src/nsNullPrincipal.cpp
+++ b/caps/src/nsNullPrincipal.cpp
@@ -287,18 +287,36 @@ nsNullPrincipal::Subsumes(nsIPrincipal *
 
 NS_IMETHODIMP
 nsNullPrincipal::SubsumesIgnoringDomain(nsIPrincipal *aOther, bool *aResult)
 {
   return Subsumes(aOther, aResult);
 }
 
 NS_IMETHODIMP
-nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport)
-{
+nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal)
+ {
+  if (aAllowIfInheritsPrincipal) {
+    if (nsPrincipal::IsPrincipalInherited(aURI)) {
+      return NS_OK;
+    }
+
+    // Also allow the load if the principal of the URI being checked is exactly
+    // us ie this.
+    nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
+    if (uriPrinc) {
+      nsCOMPtr<nsIPrincipal> principal;
+      uriPrinc->GetPrincipal(getter_AddRefs(principal));
+
+      if (principal && principal == this) {
+        return NS_OK;
+      }
+    }
+  }
+
   if (aReport) {
     nsScriptSecurityManager::ReportError(
       nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mURI, aURI);
   }
 
   return NS_ERROR_DOM_BAD_URI;
 }
 
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -841,18 +841,26 @@ URIIsLocalFile(nsIURI *aURI)
 
   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
                                 &isFile)) &&
          isFile;
 }
 
 NS_IMETHODIMP
-nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport)
+nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal)
 {
+   if (aAllowIfInheritsPrincipal) {
+    // If the caller specified to allow loads of URIs that inherit
+    // our principal, allow the load if this URI inherits its principal
+    if (nsPrincipal::IsPrincipalInherited(aURI)) {
+      return NS_OK;
+    }
+  }
+
   if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
     if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
         URIIsLocalFile(aURI)) {
       nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(aURI));
 
       if (!URIIsLocalFile(mCodebase)) {
         // If the codebase is not also a file: uri then forget it
         // (don't want resource: principals in a file: doc)
@@ -1427,21 +1435,21 @@ nsExpandedPrincipal::Subsumes(nsIPrincip
 
 NS_IMETHODIMP
 nsExpandedPrincipal::SubsumesIgnoringDomain(nsIPrincipal* aOther, bool* aResult)
 {
   return ::Subsumes(this, &nsIPrincipal::SubsumesIgnoringDomain, aOther, aResult);
 }
 
 NS_IMETHODIMP
-nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
+nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal)
 {
   nsresult rv;
   for (uint32_t i = 0; i < mPrincipals.Length(); ++i){
-    rv = mPrincipals[i]->CheckMayLoad(uri, aReport);
+    rv = mPrincipals[i]->CheckMayLoad(uri, aReport, aAllowIfInheritsPrincipal);
     if (NS_SUCCEEDED(rv))
       return rv;
   }
 
   return NS_ERROR_DOM_BAD_URI;
 }
 
 NS_IMETHODIMP
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1389,17 +1389,17 @@ nsScriptSecurityManager::CheckLoadURIWit
     // Check for uris that are only loadable by principals that subsume them
     bool hasFlags;
     rv = NS_URIChainHasFlags(targetBaseURI,
                              nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
                              &hasFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (hasFlags) {
-        return aPrincipal->CheckMayLoad(targetBaseURI, true);
+        return aPrincipal->CheckMayLoad(targetBaseURI, true, false);
     }
 
     //-- get the source scheme
     nsCAutoString sourceScheme;
     rv = sourceBaseURI->GetScheme(sourceScheme);
     if (NS_FAILED(rv)) return rv;
 
     if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
--- a/caps/src/nsSystemPrincipal.cpp
+++ b/caps/src/nsSystemPrincipal.cpp
@@ -110,17 +110,17 @@ nsSystemPrincipal::Subsumes(nsIPrincipal
 NS_IMETHODIMP
 nsSystemPrincipal::SubsumesIgnoringDomain(nsIPrincipal *other, bool *result)
 {
     *result = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSystemPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
+nsSystemPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSystemPrincipal::GetHashValue(PRUint32 *result)
 {
     *result = NS_PTR_TO_INT32(this);
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1699,17 +1699,17 @@ public:
    *
    * @param aScriptContext the script context to get the document for; can be null
    *
    * @return the document associated with the script context
    */
   static already_AddRefed<nsIDocument>
   GetDocumentFromScriptContext(nsIScriptContext *aScriptContext);
 
-  static bool CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel);
+  static bool CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal);
 
   /**
    * The method checks whether the caller can access native anonymous content.
    * If there is no JS in the stack or privileged JS is running, this
    * method returns true, otherwise false.
    */
   static bool CanAccessNativeAnon();
 
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1059,17 +1059,17 @@ nsContentSink::ProcessOfflineManifest(co
     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
                                               aManifestSpec, mDocument,
                                               mDocumentURI);
     if (!manifestURI) {
       return;
     }
 
     // Documents must list a manifest from the same origin
-    rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true);
+    rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true, false);
     if (NS_FAILED(rv)) {
       action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
     }
     else {
       // Only continue if the document has permission to use offline APIs.
       if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
         return;
       }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4601,17 +4601,17 @@ nsContentUtils::CheckSecurityBeforeLoad(
 
   // Same Origin
   if ((aAllowData && SchemeIs(aURIToLoad, "data")) ||
       ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) &&
        SchemeIs(aURIToLoad, "chrome"))) {
     return NS_OK;
   }
 
-  return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true);
+  return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true, false);
 }
 
 bool
 nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
 {
   bool isSystem;
   nsresult rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem);
   return NS_SUCCEEDED(rv) && isSystem;
@@ -5751,19 +5751,19 @@ nsContentUtils::CheckSameOrigin(nsIChann
 
   nsCOMPtr<nsIURI> newURI;
   aNewChannel->GetURI(getter_AddRefs(newURI));
   nsCOMPtr<nsIURI> newOriginalURI;
   aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
 
   NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
 
-  nsresult rv = oldPrincipal->CheckMayLoad(newURI, false);
+  nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false);
   if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
-    rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
+    rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
   }
 
   return rv;
 }
 
 NS_IMPL_ISUPPORTS2(SameOriginChecker,
                    nsIChannelEventSink,
                    nsIInterfaceRequestor)
@@ -5924,23 +5924,23 @@ nsContentUtils::GetDocumentFromScriptCon
       CallQueryInterface(domdoc, &doc);
     }
   }
   return doc;
 }
 
 /* static */
 bool
-nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel)
+nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal)
 {
   nsCOMPtr<nsIURI> channelURI;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
   NS_ENSURE_SUCCESS(rv, false);
 
-  return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false));
+  return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false, aAllowIfInheritsPrincipal));
 }
 
 nsContentTypeParser::nsContentTypeParser(const nsAString& aString)
   : mString(aString), mService(nullptr)
 {
   CallGetService("@mozilla.org/network/mime-hdrparam;1", &mService);
 }
 
@@ -6717,17 +6717,17 @@ nsContentUtils::SetUpChannelOwner(nsIPri
   // file: uri special-casing
   //
   // If this is a file: load opened from another file: then it may need
   // to inherit the owner from the referrer so they can script each other.
   // If we don't set the owner explicitly then each file: gets an owner
   // based on its own codebase later.
   //
   if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
-      NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false)) &&
+      NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) &&
       // One more check here.  CheckMayLoad will always return true for the
       // system principal, but we do NOT want to inherit in that case.
       !IsSystemPrincipal(aLoadingPrincipal)) {
     aChannel->SetOwner(aLoadingPrincipal);
     return true;
   }
 
   return false;
--- a/content/base/src/nsCrossSiteListenerProxy.cpp
+++ b/content/base/src/nsCrossSiteListenerProxy.cpp
@@ -738,20 +738,20 @@ nsCORSListenerProxy::UpdateChannel(nsICh
   if (originalURI != uri) {
     rv = nsContentUtils::GetSecurityManager()->
       CheckLoadURIWithPrincipal(mRequestingPrincipal, originalURI,
                                 nsIScriptSecurityManager::STANDARD);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (!mHasBeenCrossSite &&
-      NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, false)) &&
+      NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, false, false)) &&
       (originalURI == uri ||
        NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(originalURI,
-                                                       false)))) {
+                                                       false, false)))) {
     return NS_OK;
   }
 
   // It's a cross site load
   mHasBeenCrossSite = true;
 
   nsCString userpass;
   uri->GetUserPass(userpass);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1060,28 +1060,22 @@ nsExternalResourceMap::PendingLoad::Star
 
   nsIPrincipal* requestingPrincipal = aRequestingNode->NodePrincipal();
 
   nsresult rv = nsContentUtils::GetSecurityManager()->
     CheckLoadURIWithPrincipal(requestingPrincipal, aURI,
                               nsIScriptSecurityManager::STANDARD);
   NS_ENSURE_SUCCESS(rv, rv);
   
-  // Allow data URIs (let them skip the CheckMayLoad call), since we want
+  // Allow data URIs and other URI's that inherit their principal by passing
+  // true as the 3rd argument of CheckMayLoad, since we want
   // to allow external resources from data URIs regardless of the difference
   // in URI scheme.
-  bool doesInheritSecurityContext;
-  rv =
-    NS_URIChainHasFlags(aURI,
-                        nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
-                        &doesInheritSecurityContext);
-  if (NS_FAILED(rv) || !doesInheritSecurityContext) {
-    rv = requestingPrincipal->CheckMayLoad(aURI, true);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  rv = requestingPrincipal->CheckMayLoad(aURI, true, true);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
                                  aURI,
                                  requestingPrincipal,
                                  aRequestingNode,
                                  EmptyCString(), //mime guess
                                  nullptr,         //extra
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1708,28 +1708,19 @@ nsXMLHttpRequest::IsSystemXHR()
 nsresult
 nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
 {
   // First check if cross-site requests are enabled...
   if (IsSystemXHR()) {
     return NS_OK;
   }
 
-  // ...or if this is a same-origin request.
-  if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel)) {
-    return NS_OK;
-  }
-
-  // exempt data URIs from the same origin check.
-  nsCOMPtr<nsIURI> channelURI;
-  bool dataScheme = false;
-  if (NS_SUCCEEDED(NS_GetFinalChannelURI(aChannel,
-                                         getter_AddRefs(channelURI))) &&
-      NS_SUCCEEDED(channelURI->SchemeIs("data", &dataScheme)) &&
-      dataScheme) {
+  // If this is a same-origin request or the channel's URI inherits
+  // its principal, it's allowed.
+  if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel, true)) {
     return NS_OK;
   }
 
   // This is a cross-site request
   mState |= XML_HTTP_REQUEST_USE_XSITE_AC;
 
   // Check if we need to do a preflight request.
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -927,17 +927,17 @@ nsXBLService::LoadBindingDocumentInfo(ns
     NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
 
     if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
       // Also make sure that we're same-origin with the bound document
       // except if the stylesheet has the system principal.
       if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
           !SchemeIs(aBindingURI, "chrome")) {
         rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
-                                                           true);
+                                                           true, false);
         NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
       }
 
       // Finally check if this document is allowed to use XBL at all.
       NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(),
                      NS_ERROR_XBL_BLOCKED);
     }
   }
--- a/content/xml/document/src/nsXMLDocument.cpp
+++ b/content/xml/document/src/nsXMLDocument.cpp
@@ -328,17 +328,17 @@ nsXMLDocument::Load(const nsAString& aUr
   // that we don't end up in a case where code with elevated privileges is
   // calling us and changing the principal of this document.
 
   // Enforce same-origin even for chrome loaders to avoid someone accidentally
   // using a document that content has a reference to and turn that into a
   // chrome document.
   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
   if (!nsContentUtils::IsSystemPrincipal(principal)) {
-    rv = principal->CheckMayLoad(uri, false);
+    rv = principal->CheckMayLoad(uri, false, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
     rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
                                    uri,
                                    principal,
                                    callingDoc ? callingDoc.get() :
                                      static_cast<nsIDocument*>(this),
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -2653,17 +2653,17 @@ nsXULDocument::LoadOverlayInternal(nsIUR
 
     // Chrome documents are allowed to load overlays from anywhere.
     // In all other cases, the overlay is only allowed to load if
     // the master document and prototype document have the same origin.
 
     bool documentIsChrome = IsChromeURI(mDocumentURI);
     if (!documentIsChrome) {
         // Make sure we're allowed to load this overlay.
-        rv = NodePrincipal()->CheckMayLoad(aURI, true);
+        rv = NodePrincipal()->CheckMayLoad(aURI, true, false);
         if (NS_FAILED(rv)) {
             *aFailureFromContent = true;
             return rv;
         }
     }
 
     // Look in the prototype cache for the prototype document with
     // the specified overlay URI. Only use the cache if the containing
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -1323,17 +1323,17 @@ nsXULTemplateBuilder::LoadDataSourceUrls
 
         nsCOMPtr<nsIURI> uri;
         rv = NS_NewURI(getter_AddRefs(uri), uriStr);
         if (NS_FAILED(rv) || !uri)
             continue; // Necko will barf if our URI is weird
 
         // don't add the uri to the list if the document is not allowed to
         // load it
-        if (!isTrusted && NS_FAILED(docPrincipal->CheckMayLoad(uri, true)))
+        if (!isTrusted && NS_FAILED(docPrincipal->CheckMayLoad(uri, true, false)))
           continue;
 
         uriList->AppendElement(uri, false);
     }
 
     nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(mRoot);
     rv = mQueryProcessor->GetDatasource(uriList,
                                         rootNode,
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10067,17 +10067,17 @@ nsDocShell::AddState(nsIVariant *aData, 
 
             if (!docScriptObj) {
                 return NS_ERROR_DOM_SECURITY_ERR;
             }
 
             nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
 
             if (!principal ||
-                NS_FAILED(principal->CheckMayLoad(newURI, true))) {
+                NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
 
                 return NS_ERROR_DOM_SECURITY_ERR;
             }
         }
 
         if (mCurrentURI) {
             mCurrentURI->Equals(newURI, &equalURIs);
         }
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -295,21 +295,22 @@ public:
       // If this script loader is being used to make a new worker then we need
       // to do a same-origin check. Otherwise we need to clear the load with the
       // security manager.
       if (mIsWorkerScript) {
         nsCString scheme;
         rv = uri->GetScheme(scheme);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        // We exempt data URLs from the same origin check.
-        if (!scheme.EqualsLiteral("data")) {
-          rv = principal->CheckMayLoad(uri, false);
-          NS_ENSURE_SUCCESS(rv, rv);
-        }
+        // We pass true as the 3rd argument to checkMayLoad here.
+        // This allows workers in sandboxed documents to load data URLs
+        // (and other URLs that inherit their principal from their
+        // creator.)
+        rv = principal->CheckMayLoad(uri, false, true);
+        NS_ENSURE_SUCCESS(rv, rv);
       }
       else {
         rv = secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       // We need to know which index we're on in OnStreamComplete so we know
       // where to put the result.
@@ -482,19 +483,19 @@ public:
           return NS_ERROR_DOM_BAD_URI;
         }
       }
       else  {
         nsCString scheme;
         rv = finalURI->GetScheme(scheme);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        // We exempt data urls again.
-        if (!scheme.EqualsLiteral("data") &&
-            NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false))) {
+        // We exempt data urls and other URI's that inherit their
+        // principal again.
+        if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false, true))) {
           return NS_ERROR_DOM_BAD_URI;
         }
       }
 
       mWorkerPrivate->SetPrincipal(channelPrincipal);
     }
 
     return NS_OK;
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1540,17 +1540,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
   if (aLoadData->mLoaderPrincipal) {
     bool inherit;
     rv = NS_URIChainHasFlags(aLoadData->mURI,
                              nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                              &inherit);
     if ((NS_SUCCEEDED(rv) && inherit) ||
         (nsContentUtils::URIIsLocalFile(aLoadData->mURI) &&
          NS_SUCCEEDED(aLoadData->mLoaderPrincipal->
-                      CheckMayLoad(aLoadData->mURI, false)))) {
+                      CheckMayLoad(aLoadData->mURI, false, false)))) {
       channel->SetOwner(aLoadData->mLoaderPrincipal);
     }
   }
 
   // We don't have to hold on to the stream loader.  The ownership
   // model is: Necko owns the stream loader, which owns the load data,
   // which owns us
   nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
--- a/rdf/base/src/nsRDFXMLDataSource.cpp
+++ b/rdf/base/src/nsRDFXMLDataSource.cpp
@@ -885,19 +885,19 @@ RDFXMLDataSourceImpl::AsyncOnChannelRedi
 
     nsCOMPtr<nsIURI> newURI;
     aNewChannel->GetURI(getter_AddRefs(newURI));
     nsCOMPtr<nsIURI> newOriginalURI;
     aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
 
     NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
 
-    rv = oldPrincipal->CheckMayLoad(newURI, false);
+    rv = oldPrincipal->CheckMayLoad(newURI, false, false);
     if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
-        rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
+        rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
     }
 
     if (NS_FAILED(rv))
         return rv;
 
     cb->OnRedirectVerifyCallback(NS_OK);
     return NS_OK;
 }