Bug 1308889 - Try to explicitly pass aTriggeringPrincipal and aPrincipalToInherit to DoURILoad(). r=bz
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Tue, 08 Nov 2016 07:23:12 +0100
changeset 351660 57d473c3ca22cd2c6e7720ab796501ee68df4559
parent 351659 3e74d390dea4d3311b2eea00be094331dfe3f64f
child 351661 efc9b52a218f7ffd40ba346de74fd846a9059ceb
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1308889
milestone52.0a1
Bug 1308889 - Try to explicitly pass aTriggeringPrincipal and aPrincipalToInherit to DoURILoad(). r=bz
caps/nsScriptSecurityManager.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIDocShell.idl
dom/base/nsObjectLoadingContent.cpp
dom/html/nsHTMLDocument.cpp
dom/jsurl/nsJSProtocolHandler.cpp
ipc/glue/BackgroundUtils.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/nsILoadInfo.idl
netwerk/ipc/NeckoChannelParams.ipdlh
toolkit/mozapps/extensions/amContentHandler.js
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -332,17 +332,21 @@ nsresult
 nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
                                                    nsIPrincipal** aPrincipal,
                                                    bool aIgnoreSandboxing)
 {
     NS_PRECONDITION(aChannel, "Must have channel!");
     // Check whether we have an nsILoadInfo that says what we should do.
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     if (loadInfo && loadInfo->GetForceInheritPrincipalOverruleOwner()) {
-      NS_ADDREF(*aPrincipal = loadInfo->PrincipalToInherit());
+      nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
+      if (!principalToInherit) {
+        principalToInherit = loadInfo->TriggeringPrincipal();
+      }
+      principalToInherit.forget(aPrincipal);
       return NS_OK;
     }
 
     nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
     if (owner) {
         CallQueryInterface(owner, aPrincipal);
         if (*aPrincipal) {
@@ -372,29 +376,36 @@ nsScriptSecurityManager::GetChannelResul
           // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of
           // sandboxing:
           if (loadInfo->GetLoadingSandboxed() &&
               loadInfo->GetForceInheritPrincipalDropped()) {
             forceInherit = true;
           }
         }
         if (forceInherit) {
-            NS_ADDREF(*aPrincipal = loadInfo->PrincipalToInherit());
+            nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
+            if (!principalToInherit) {
+              principalToInherit = loadInfo->TriggeringPrincipal();
+            }
+            principalToInherit.forget(aPrincipal);
             return NS_OK;
         }
 
         nsSecurityFlags securityFlags = loadInfo->GetSecurityMode();
         if (securityFlags == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS ||
             securityFlags == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS ||
             securityFlags == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
 
             nsCOMPtr<nsIURI> uri;
             nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
             NS_ENSURE_SUCCESS(rv, rv); 
             nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
+            if (!principalToInherit) {
+              principalToInherit = loadInfo->TriggeringPrincipal();
+            }
             bool inheritForAboutBlank = loadInfo->GetAboutBlankInherits();
 
             if (nsContentUtils::ChannelShouldInheritPrincipal(principalToInherit,
                                                               uri,
                                                               inheritForAboutBlank,
                                                               false)) {
                 principalToInherit.forget(aPrincipal);
                 return NS_OK;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1501,16 +1501,36 @@ nsDocShell::LoadURI(nsIURI* aURI,
     inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
   }
 
   if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
     inheritPrincipal = false;
     principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this);
   }
 
+  // If the triggeringPrincipal is not passed explicitly, we first try to create
+  // a principal from the referrer, since the referrer URI reflects the web origin
+  // that triggered the load. If there is no referrer URI, we fall back to using
+  // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
+  // and no referrer simulate a load that was triggered by the system.
+  // It's important to note that this block of code needs to appear *after* the block
+  // where we munge the principalToInherit, because otherwise we would never enter
+  // code blocks checking if the principalToInherit is null and we will end up with
+  // a wrong inheritPrincipal flag.
+  if (!triggeringPrincipal) {
+    if (referrer) {
+      nsresult rv = CreatePrincipalFromReferrer(referrer,
+                                                getter_AddRefs(triggeringPrincipal));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
+    }
+  }
+
   uint32_t flags = 0;
 
   if (inheritPrincipal) {
     flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
   }
 
   if (!sendReferrer) {
     flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
@@ -5324,17 +5344,18 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
   errorPageUrl.AppendASCII(escapedDescription.get());
 
   nsCOMPtr<nsIURI> errorPageURI;
   rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return InternalLoad(errorPageURI, nullptr, false, nullptr,
                       mozilla::net::RP_Default,
-                      nullptr, nullptr, INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL, EmptyString(),
+                      nsContentUtils::GetSystemPrincipal(), nullptr,
+                      INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
                       nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
                       nullptr, true, NullString(), this, nullptr, nullptr,
                       nullptr);
 }
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags)
 {
@@ -5367,52 +5388,56 @@ nsDocShell::Reload(uint32_t aReloadFlags
   /* If you change this part of code, make sure bug 45297 does not re-occur */
   if (mOSHE) {
     rv = LoadHistoryEntry(mOSHE, loadType);
   } else if (mLSHE) { // In case a reload happened before the current load is done
     rv = LoadHistoryEntry(mLSHE, loadType);
   } else {
     nsCOMPtr<nsIDocument> doc(GetDocument());
 
+    if (!doc) {
+      return NS_OK;
+    }
+
     // Do not inherit owner from document
     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
     nsAutoString srcdoc;
-    nsIPrincipal* principal = nullptr;
-    nsAutoString contentTypeHint;
     nsCOMPtr<nsIURI> baseURI;
     nsCOMPtr<nsIURI> originalURI;
     bool loadReplace = false;
-    if (doc) {
-      principal = doc->NodePrincipal();
-      doc->GetContentType(contentTypeHint);
-
-      if (doc->IsSrcdocDocument()) {
-        doc->GetSrcdocData(srcdoc);
-        flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
-        baseURI = doc->GetBaseURI();
-      }
-      nsCOMPtr<nsIChannel> chan = doc->GetChannel();
-      if (chan) {
-        uint32_t loadFlags;
-        chan->GetLoadFlags(&loadFlags);
-        loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
-        nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
-        if (httpChan) {
-          httpChan->GetOriginalURI(getter_AddRefs(originalURI));
-        }
-      }
-    }
+
+    nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
+    nsAutoString contentTypeHint;
+    doc->GetContentType(contentTypeHint);
+
+    if (doc->IsSrcdocDocument()) {
+      doc->GetSrcdocData(srcdoc);
+      flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+      baseURI = doc->GetBaseURI();
+    }
+    nsCOMPtr<nsIChannel> chan = doc->GetChannel();
+    if (chan) {
+      uint32_t loadFlags;
+      chan->GetLoadFlags(&loadFlags);
+      loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
+      nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
+      if (httpChan) {
+        httpChan->GetOriginalURI(getter_AddRefs(originalURI));
+      }
+    }
+
+    MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
 
     rv = InternalLoad(mCurrentURI,
                       originalURI,
                       loadReplace,
                       mReferrerURI,
                       mReferrerPolicy,
-                      principal,
-                      principal,
+                      triggeringPrincipal,
+                      triggeringPrincipal,
                       flags,
                       EmptyString(),   // No window target
                       NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
                       NullString(),    // No forced download
                       nullptr,         // No post data
                       nullptr,         // No headers data
                       loadType,        // Load type
                       nullptr,         // No SHEntry
@@ -9650,29 +9675,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                          nsISHEntry* aSHEntry,
                          bool aFirstParty,
                          const nsAString& aSrcdoc,
                          nsIDocShell* aSourceDocShell,
                          nsIURI* aBaseURI,
                          nsIDocShell** aDocShell,
                          nsIRequest** aRequest)
 {
-  // In most cases both principals (aTriggeringPrincipal and aPrincipalToInherit)
-  // are both null or both non-null. For the exceptional cases let's make sure that:
-  // * if aTriggeringPrincipal is null then either aPrincipalToInherit is null or
-  //   it's a NullPrincipal
-  // * if aPrincipalToInherit is null then either aTriggeringPrincipal is null or
-  //   it's a NullPrincipal or INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL is set.
-  MOZ_ASSERT(aTriggeringPrincipal ||
-             (!aPrincipalToInherit ||
-              aPrincipalToInherit->GetIsNullPrincipal()));
-  MOZ_ASSERT(aPrincipalToInherit ||
-             (!aTriggeringPrincipal ||
-              aTriggeringPrincipal->GetIsNullPrincipal() ||
-              (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL)));
+  MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
 
   nsresult rv = NS_OK;
   mOriginalUriString.Truncate();
 
   if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
     PR_LogPrint("DOCSHELL %p InternalLoad %s\n",
                 this, aURI ? aURI->GetSpecOrDefault().get() : "");
   }
@@ -9861,36 +9874,22 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   // done by someone from chrome manually messing with our nsIWebNavigation
   // or by C++ setting document.location) don't get a funky principal.  If
   // callers want something interesting to happen with the about:blank
   // principal in this case, they should pass aPrincipalToInherit in.
   //
   {
     bool inherits;
     // One more twist: Don't inherit the principal for external loads.
-    if (!principalToInherit && 
-        NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
-                                                                &inherits)) &&
-        inherits) {
-      if (aLoadType != LOAD_NORMAL_EXTERNAL && 
-          (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL)) {
-        principalToInherit = GetInheritedPrincipal(true);
-      }
-
-      // In case we don't have a principalToInherit and the TriggeringPrincipal
-      // either already is a SystemPrincipal or would fall back to become
-      // a SystemPrincipal within the loadInfo then we should explicitly set
-      // the principalToInherit to a freshly created NullPrincipal.
-      if (!principalToInherit && 
-          (nsContentUtils::IsSystemPrincipal(aTriggeringPrincipal) ||
-           (!aTriggeringPrincipal && !aReferrer))) {
-        // We're going to default to inheriting our system triggering principal, 
-        // more or less by accident.  This doesn't seem like a good idea.
-        principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this);
-      }
+    if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
+        (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&   
+         NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
+                                                                 &inherits)) &&
+         inherits) {
+      principalToInherit = GetInheritedPrincipal(true);
     }
   }
 
   // Don't allow loads that would inherit our security context
   // if this document came from an unsafe channel.
   {
     bool willInherit;
     // This condition needs to match the one in
@@ -10804,34 +10803,18 @@ nsDocShell::DoURILoad(nsIURI* aURI,
       // to load this resource. This docshell is scheduled for destruction
       // already, so bail out here.
       return NS_OK;
     }
   }
 
   // Getting the right triggeringPrincipal needs to be updated and is only
   // ready for use once bug 1182569 landed. Until then, we cannot rely on
-  // the triggeringPrincipal for TYPE_DOCUMENT loads. Please note that the
-  // triggeringPrincipal falls back to the systemPrincipal below.
-  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
-
-  // Make sure that we always get a non null triggeringPrincipal for
-  // loads of type TYPE_SUBDOCUMENT.
-  MOZ_ASSERT(aContentPolicyType != nsIContentPolicy::TYPE_SUBDOCUMENT ||
-             triggeringPrincipal, "Need a valid triggeringPrincipal");
-
-  if (!triggeringPrincipal) {
-    if (aReferrerURI) {
-      rv = CreatePrincipalFromReferrer(aReferrerURI,
-                                       getter_AddRefs(triggeringPrincipal));
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
-      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
-    }
-  }
+  // the triggeringPrincipal for TYPE_DOCUMENT loads.
+  MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
 
   bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
   // only inherit if we have a aPrincipalToInherit
   bool inherit = false;
 
   if (aPrincipalToInherit) {
     inherit = nsContentUtils::ChannelShouldInheritPrincipal(
       aPrincipalToInherit,
@@ -10858,19 +10841,19 @@ nsDocShell::DoURILoad(nsIURI* aURI,
     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
   if (isSandBoxed) {
     securityFlags |= nsILoadInfo::SEC_SANDBOXED;
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
-      new LoadInfo(loadingWindow, triggeringPrincipal,
+      new LoadInfo(loadingWindow, aTriggeringPrincipal,
                    securityFlags) :
-      new LoadInfo(loadingPrincipal, triggeringPrincipal, loadingNode,
+      new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
                    securityFlags, aContentPolicyType);
 
   if (aPrincipalToInherit) {
     loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
   }
 
   // We have to do this in case our OriginAttributes are different from the
   // OriginAttributes of the parent document. Or in case there isn't a
@@ -12484,16 +12467,24 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
   if (isSrcdoc) {
     aEntry->GetSrcdocData(srcdoc);
     aEntry->GetBaseURI(getter_AddRefs(baseURI));
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   } else {
     srcdoc = NullString();
   }
 
+  // If there is no triggeringPrincipal we can fall back to using the
+  // SystemPrincipal as the triggeringPrincipal for loading the history
+  // entry, since the history entry can only end up in history if security
+  // checks passed in the initial loading phase.
+  if (!triggeringPrincipal) {
+    triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
+  }
+
   // Passing nullptr as aSourceDocShell gives the same behaviour as before
   // aSourceDocShell was introduced. According to spec we should be passing
   // the source browsing context that was used when the history entry was
   // first created. bug 947716 has been created to address this issue.
   rv = InternalLoad(uri,
                     originalURI,
                     loadReplace,
                     referrerURI,
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -343,24 +343,28 @@ protected:
   // Get the principal that we'll set on the channel if we're inheriting. If
   // aConsiderCurrentDocument is true, we try to use the current document if
   // at all possible. If that fails, we fall back on the parent document.
   // If that fails too, we force creation of a content viewer and use the
   // resulting principal. If aConsiderCurrentDocument is false, we just look
   // at the parent.
   nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument);
 
-  // Actually open a channel and perform a URI load. Note: whatever principal is
-  // passed to this function will be set on the channel. Callers who wish to
-  // not have an principal on the channel should just pass null.
+  // Actually open a channel and perform a URI load. Callers need to pass a
+  // non-null aTriggeringPrincipal which initiated the URI load. Please note
+  // that aTriggeringPrincipal will be used for performing security checks.
+  // If the argument aURI is provided by the web, then please do not pass a
+  // SystemPrincipal as the triggeringPrincipal. If principalToInherit is
+  // null, then no inheritance of any sort will happen and the load will
+  // get a principal based on the URI being loaded.
   // If aSrcdoc is not void, the load will be considered as a srcdoc load,
   // and the contents of aSrcdoc will be loaded instead of aURI.
   // aOriginalURI will be set as the originalURI on the channel that does the
   // load. If aOriginalURI is null, aURI will be set as the originalURI.
-  // If aLoadReplace is true, OLOAD_REPLACE flag will be set to the nsIChannel.
+  // If aLoadReplace is true, LOAD_REPLACE flag will be set to the nsIChannel.
   nsresult DoURILoad(nsIURI* aURI,
                      nsIURI* aOriginalURI,
                      bool aLoadReplace,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
                      nsIPrincipal* aTriggeringPrincipal,
                      nsIPrincipal* aPrincipalToInherit,
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -127,45 +127,35 @@ interface nsIDocShell : nsIDocShellTreeI
    * @param aOriginalURI         - The URI to set as the originalURI on the channel
    *                               that does the load. If null, aURI will be set as
    *                               the originalURI.
    * @param aLoadReplace         - If set LOAD_REPLACE flag will be set on the
    *                               channel. aOriginalURI is null, this argument is
    *                               ignored.
    * @param aReferrer            - Referring URI
    * @param aReferrerPolicy      - Referrer policy
-   * @param aTriggeringPrincipal - Principal that initiated that load. If passing
-   *                               null for this argument, then internally a
-   *                               principal is created from aReferrer. If
-   *                               aReferrer is also null, then the
-   *                               triggeringPrincipal defaults to the
-   *                               SystemPrincipal. Please note that this is the
-   *                               principal that is used for security checks. If
-   *                               the argument aURI is provided by the web, then
-   *                               please pass an explicit triggeringPrincipal to
-   *                               avoid the fallback to SystemPrincipal and
-   *                               hence a potential security risk.
-   *                               If aTriggeringPrincipal is null then either
-   *                               aPrincipalToInherit is null or it's
-   *                               a NullPrincipal.
-   * @param aPrincipalToInherit  - Principal to be inherited for that load. If
-   *                               passing null for this argument, then internally
-   *                               the triggeringPrincipal is also used for the
-   *                               principalToInherit. There are cases where those
-   *                               two principals need to be different though.
-   *                               E.g. the system might initiate a load for
-   *                               'about:blank', hence SystemPrincipal is passed
-   *                               for aTriggeringPrincipal. But the principal to
-   *                               be inherited for that load should be a
-   *                               NullPrincipal and not the SystemPrincipal.
-   *                               In that case, please pass a non null
-   *                               principalToInherit.
-   *                               If aPrincipalToInherit is null then either
-   *                               aTriggeringPrincipal is null or
-   *                               INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL is set.
+   * @param aTriggeringPrincipal - A non-null principal that initiated that load.
+   *                               Please note that this is the principal that is
+   *                               used for security checks. If the argument aURI
+   *                               is provided by the web, then please do not pass
+   *                               a SystemPrincipal as the triggeringPrincipal.
+   * @param aPrincipalToInherit  - Principal to be inherited for that load. If this
+   *                               argument is null then principalToInherit is
+   *                               computed as follows:
+   *                               a) If INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL, and
+   *                                  aLoadType is not LOAD_NORMAL_EXTERNAL, and the
+   *                                  URI would normally inherit a principal, then
+   *                                  principalToInherit is set to the current
+   *                                  document's principal, or parent document if
+   *                                  there is not a current document.
+   *                               b) If principalToInherit is still null (e.g. if
+   *                                  some of the conditions of (a) were not satisfied),
+   *                                  then no inheritance of any sort will happen: the
+   *                                  load will just get a principal based on the URI
+   *                                  being loaded.
    * @param aFlags               - Any of the load flags defined within above.
    * @param aStopActiveDoc       - Flag indicating whether loading the current
    *                               document should be stopped.
    * @param aWindowTarget        - Window target for the load.
    * @param aTypeHint            - A hint as to the content-type of the resulting
    *                               data.  May be null or empty if no hint.
    * @param aFileName            - Non-null when the link should be downloaded as
                                    the given filename.
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -2671,18 +2671,21 @@ nsObjectLoadingContent::OpenChannel()
                      thisContent,
                      securityFlags,
                      contentPolicyType,
                      group, // aLoadGroup
                      shim,  // aCallbacks
                      nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
                      nsIChannel::LOAD_CLASSIFY_URI |
                      nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
-
   NS_ENSURE_SUCCESS(rv, rv);
+  if (inherit) {
+    nsCOMPtr<nsILoadInfo> loadinfo = chan->GetLoadInfo();
+    loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
+  }
 
   // Referrer
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
   if (httpChan) {
     httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
                                     doc->GetReferrerPolicy());
 
     // Set the initiator type
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -2306,18 +2306,19 @@ nsHTMLDocument::CreateAndAddWyciwygChann
   // document.write() script to cache
   nsCOMPtr<nsIChannel> channel;
   // Create a wyciwyg Channel
   rv = NS_NewChannel(getter_AddRefs(channel),
                      wcwgURI,
                      NodePrincipal(),
                      nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                      nsIContentPolicy::TYPE_OTHER);
-
   NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+  loadInfo->SetPrincipalToInherit(NodePrincipal());
 
   mWyciwygChannel = do_QueryInterface(channel);
 
   mWyciwygChannel->SetSecurityInfo(mSecurityInfo);
 
   // Note: we want to treat this like a "previous document" hint so that,
   // e.g. a <meta> tag in the document.write content can override it.
   SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -156,16 +156,19 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
     if (!principal) {
         nsCOMPtr<nsILoadInfo> loadInfo;
         aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
         if (loadInfo && loadInfo->GetForceInheritPrincipal()) {
             principal = loadInfo->PrincipalToInherit();
+            if (!principal) {
+                principal = loadInfo->TriggeringPrincipal();
+            }
         } else {
             // No execution without a principal!
             NS_ASSERTION(!owner, "Non-principal owner?");
             NS_WARNING("No principal to execute JS with");
             return NS_ERROR_DOM_RETVAL_UNDEFINED;
         }
     }
 
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -221,19 +221,24 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
     NS_ENSURE_SUCCESS(rv, rv);
     loadingPrincipalInfo = loadingPrincipalInfoTemp;
   }
 
   PrincipalInfo triggeringPrincipalInfo;
   rv = PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(),
                                 &triggeringPrincipalInfo);
 
-  PrincipalInfo principalToInheritInfo;
-  rv = PrincipalToPrincipalInfo(aLoadInfo->PrincipalToInherit(),
-                                &principalToInheritInfo);
+  OptionalPrincipalInfo principalToInheritInfo = mozilla::void_t();
+  if (aLoadInfo->PrincipalToInherit()) {
+    PrincipalInfo principalToInheritInfoTemp;
+    rv = PrincipalToPrincipalInfo(aLoadInfo->PrincipalToInherit(),
+                                  &principalToInheritInfoTemp);
+    NS_ENSURE_SUCCESS(rv, rv);
+    principalToInheritInfo = principalToInheritInfoTemp;
+  }
 
   nsTArray<PrincipalInfo> redirectChainIncludingInternalRedirects;
   for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChainIncludingInternalRedirects()) {
     rv = PrincipalToPrincipalInfo(principal, redirectChainIncludingInternalRedirects.AppendElement());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsTArray<PrincipalInfo> redirectChain;
@@ -292,19 +297,21 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIPrincipal> triggeringPrincipal =
     PrincipalInfoToPrincipal(loadInfoArgs.triggeringPrincipalInfo(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIPrincipal> principalToInherit =
-  PrincipalInfoToPrincipal(loadInfoArgs.principalToInheritInfo(), &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIPrincipal> principalToInherit;
+  if (loadInfoArgs.principalToInheritInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
+    principalToInherit = PrincipalInfoToPrincipal(loadInfoArgs.principalToInheritInfo(), &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   nsTArray<nsCOMPtr<nsIPrincipal>> redirectChainIncludingInternalRedirects;
   for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChainIncludingInternalRedirects()) {
     nsCOMPtr<nsIPrincipal> redirectedPrincipal =
       PrincipalInfoToPrincipal(principalInfo, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     redirectChainIncludingInternalRedirects.AppendElement(redirectedPrincipal.forget());
   }
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -40,17 +40,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    nsIPrincipal* aTriggeringPrincipal,
                    nsINode* aLoadingContext,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType)
   : mLoadingPrincipal(aLoadingContext ?
                         aLoadingContext->NodePrincipal() : aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal ?
                            aTriggeringPrincipal : mLoadingPrincipal.get())
-  , mPrincipalToInherit(mTriggeringPrincipal)
+  , mPrincipalToInherit(nullptr)
   , mLoadingContext(do_GetWeakReference(aLoadingContext))
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
   , mEnforceSRI(false)
   , mForceInheritPrincipalDropped(false)
@@ -63,17 +63,16 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mIsThirdPartyContext(false)
   , mForcePreflight(false)
   , mIsPreflight(false)
   , mForceHSTSPriming(false)
   , mMixedContentWouldBlock(false)
 {
   MOZ_ASSERT(mLoadingPrincipal);
   MOZ_ASSERT(mTriggeringPrincipal);
-  MOZ_ASSERT(mPrincipalToInherit);
 
 #ifdef DEBUG
   // TYPE_DOCUMENT loads initiated by javascript tests will go through
   // nsIOService and use the wrong constructor.  Don't enforce the
   // !TYPE_DOCUMENT check in those cases
   bool skipContentTypeCheck = false;
   skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
 #endif
@@ -214,17 +213,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
  * This constructor should only be used for TYPE_DOCUMENT loads, since they
  * have a null loadingNode and loadingPrincipal.
 */
 LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsSecurityFlags aSecurityFlags)
   : mLoadingPrincipal(nullptr)
   , mTriggeringPrincipal(aTriggeringPrincipal)
-  , mPrincipalToInherit(mTriggeringPrincipal)
+  , mPrincipalToInherit(nullptr)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
   , mEnforceSRI(false)
   , mForceInheritPrincipalDropped(false)
   , mInnerWindowID(0)
@@ -238,17 +237,16 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   , mIsPreflight(false)
   , mForceHSTSPriming(false)
   , mMixedContentWouldBlock(false)
 {
   // Top-level loads are never third-party
   // Grab the information we can out of the window.
   MOZ_ASSERT(aOuterWindow);
   MOZ_ASSERT(mTriggeringPrincipal);
-  MOZ_ASSERT(mPrincipalToInherit);
 
   // if the load is sandboxed, we can not also inherit the principal
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
     mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
     mForceInheritPrincipalDropped = true;
   }
 
   // NB: Ignore the current inner window since we're navigating away from it.
@@ -351,17 +349,16 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mForcePreflight(aForcePreflight)
   , mIsPreflight(aIsPreflight)
   , mForceHSTSPriming (aForceHSTSPriming)
   , mMixedContentWouldBlock(aMixedContentWouldBlock)
 {
   // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
   MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT);
   MOZ_ASSERT(mTriggeringPrincipal);
-  MOZ_ASSERT(mPrincipalToInherit);
 
   mRedirectChainIncludingInternalRedirects.SwapElements(
     aRedirectChainIncludingInternalRedirects);
 
   mRedirectChain.SwapElements(aRedirectChain);
 }
 
 LoadInfo::~LoadInfo()
@@ -439,17 +436,17 @@ nsIPrincipal*
 LoadInfo::TriggeringPrincipal()
 {
   return mTriggeringPrincipal;
 }
 
 NS_IMETHODIMP
 LoadInfo::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit)
 {
-  NS_ADDREF(*aPrincipalToInherit = mPrincipalToInherit);
+  NS_IF_ADDREF(*aPrincipalToInherit = mPrincipalToInherit);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LoadInfo::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit)
 {
   MOZ_ASSERT(aPrincipalToInherit, "must be a valid principal to inherit");
   mPrincipalToInherit = aPrincipalToInherit;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -269,19 +269,22 @@ interface nsILoadInfo : nsISupports
 
   /**
    * A C++-friendly version of triggeringPrincipal.
    */
   [noscript, notxpcom, nostdcall, binaryname(TriggeringPrincipal)]
   nsIPrincipal binaryTriggeringPrincipal();
 
   /**
-   * The principalToInherit is the principal that is used when the inherit flag
-   * is set. For loads that are not TYPE_DOCUMENT or TYPE_SUBDOCUMENT that
-   * principal is always identical to the triggeringPrincipal.
+   * For non-document loads the principalToInherit is always null. For
+   * loads of type TYPE_DOCUMENT or TYPE_SUBDOCUMENT the principalToInherit
+   * might be null. If it's non null, then this is the principal that is
+   * inherited if a principal needs to be inherited. If the principalToInherit
+   * is null but the inherit flag is set, then the triggeringPrincipal is
+   * the principal that is inherited.
    */
   attribute nsIPrincipal principalToInherit;
 
   /**
    * A C++-friendly version of principalToInherit.
    */
   [noscript, notxpcom, nostdcall, binaryname(PrincipalToInherit)]
   nsIPrincipal binaryPrincipalToInherit();
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -27,17 +27,17 @@ namespace net {
 //-----------------------------------------------------------------------------
 // LoadInfo IPDL structs
 //-----------------------------------------------------------------------------
 
 struct LoadInfoArgs
 {
   OptionalPrincipalInfo requestingPrincipalInfo;
   PrincipalInfo         triggeringPrincipalInfo;
-  PrincipalInfo         principalToInheritInfo;
+  OptionalPrincipalInfo principalToInheritInfo;
   uint32_t              securityFlags;
   uint32_t              contentPolicyType;
   uint32_t              tainting;
   bool                  upgradeInsecureRequests;
   bool                  verifySignedContent;
   bool                  enforceSRI;
   bool                  forceInheritPrincipalDropped;
   uint64_t              innerWindowID;
--- a/toolkit/mozapps/extensions/amContentHandler.js
+++ b/toolkit/mozapps/extensions/amContentHandler.js
@@ -41,23 +41,28 @@ amContentHandler.prototype = {
     let callbacks = aRequest.notificationCallbacks ?
                     aRequest.notificationCallbacks :
                     aRequest.loadGroup.notificationCallbacks;
     if (callbacks)
       window = callbacks.getInterface(Ci.nsIDOMWindow);
 
     aRequest.cancel(Cr.NS_BINDING_ABORTED);
 
+    let principalToInherit = aRequest.loadInfo.principalToInherit;
+    if (!principalToInherit) {
+      principalToInherit = aRequest.loadInfo.triggeringPrincipal;
+    }
+
     let installs = {
       uris: [uri.spec],
       hashes: [null],
       names: [null],
       icons: [null],
       mimetype: XPI_CONTENT_TYPE,
-      principalToInherit: aRequest.loadInfo.principalToInherit,
+      principalToInherit: principalToInherit,
       callbackID: -1
     };
 
     if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
       // When running in the main process this might be a frame inside an
       // in-content UI page, walk up to find the first frame element in a chrome
       // privileged document
       let element = window.frameElement;