Bug 1407258: Dowgrade document loads with expanded principals to their last sub-principal. r?bz draft
authorKris Maglione <maglione.k@gmail.com>
Tue, 10 Oct 2017 14:08:47 -0700
changeset 678172 6a5ca7444ff921d82293b63db9c29e3b76afcd73
parent 678076 ddf53adb94bb18f245fba0f3b055813dd5560118
child 735247 5a5a09b829d11fa79ed23a4de3cc6f6e565b6224
push id83837
push usermaglione.k@gmail.com
push dateTue, 10 Oct 2017 21:09:23 +0000
reviewersbz
bugs1407258
milestone58.0a1
Bug 1407258: Dowgrade document loads with expanded principals to their last sub-principal. r?bz There are currently some corner cases where channels that are eventually loaded into documents (mainly <img src="data:image/svg+xml,") can inherit expanded principals from a caller. Since documents aren't allowed to have expanded principals, this causes crashes. This patch is a short term workaround for the issue, until we have a longer term solution that prevents the channels from inheriting the expanded principals to begin with. MozReview-Commit-ID: JwqqtVynLjj
dom/base/nsDocument.cpp
toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -106,16 +106,17 @@
 #include "nsNetUtil.h"     // for NS_NewURI
 #include "nsIInputStreamChannel.h"
 #include "nsIAuthPrompt.h"
 #include "nsIAuthPrompt2.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
+#include "ExpandedPrincipal.h"
 #include "NullPrincipal.h"
 
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMElement.h"
 #include "nsFocusManager.h"
 
 // for radio group stuff
@@ -2481,16 +2482,30 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
 
 already_AddRefed<nsIPrincipal>
 nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
 {
   if (!aPrincipal) {
     return nullptr;
   }
 
+  // We can't load a document with an expanded principal. If we're given one,
+  // automatically downgrade it to the last principal it subsumes (which is the
+  // extension principal, in the case of extension content scripts).
+  auto* basePrin = BasePrincipal::Cast(aPrincipal);
+  if (basePrin->Is<ExpandedPrincipal>()) {
+    auto* expanded = basePrin->As<ExpandedPrincipal>();
+
+    nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist;
+    MOZ_ALWAYS_SUCCEEDS(expanded->GetWhiteList(&whitelist));
+    MOZ_ASSERT(whitelist->Length() > 0);
+
+    return do_AddRef(whitelist->LastElement().get());
+  }
+
   if (!sChromeInContentPrefCached) {
     sChromeInContentPrefCached = true;
     Preferences::AddBoolVarCache(&sChromeInContentAllowed,
                                  kChromeInContentPref, false);
   }
   if (!sChromeInContentAllowed &&
       nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     // We basically want the parent document here, but because this is very
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
@@ -253,16 +253,22 @@ function toHTML(test, opts) {
  *        A list of test objects, as understood by {@see getElementData}.
  * @param {ElementTestOptions} baseOpts
  *        A base options object, as understood by {@see getElementData},
  *        which represents the default values for injections under this
  *        context.
  */
 function injectElements(tests, baseOpts) {
   window.addEventListener("load", () => {
+    // Basic smoke test to check that SVG images do not try to create a document
+    // with an expanded principal, which would cause a crash.
+    let img = document.createElement("img");
+    img.src = "data:image/svg+xml,%3Csvg%2F%3E";
+    document.body.appendChild(img);
+
     let overrideOpts = opts => Object.assign({}, baseOpts, opts);
     let opts = baseOpts;
 
     // Build the full element with setAttr, then inject.
     for (let test of tests) {
       let {elem, srcElem, src} = createElement(test, opts);
       srcElem.setAttribute(test.srcAttr, src);
       document.body.appendChild(elem);