Bug 1406278: Part 8b - Use subject principal as triggering principal in style <link> "href" attribute. r=bz
authorKris Maglione <maglione.k@gmail.com>
Thu, 05 Oct 2017 19:40:48 -0700
changeset 385234 ec0c2767cf57ed606e9bed54a15d6bdadae12579
parent 385233 e4308fbed9c584d58ef67693ba4797680e6d6669
child 385235 e9fdabc86073de7f425b0a42ad8899c298bca5d3
push id95948
push usermaglione.k@gmail.com
push dateTue, 10 Oct 2017 03:38:28 +0000
treeherdermozilla-inbound@ec0c2767cf57 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1406278
milestone58.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 1406278: Part 8b - Use subject principal as triggering principal in style <link> "href" attribute. r=bz MozReview-Commit-ID: LWMkBcB4WIg
dom/base/nsContentSink.cpp
dom/base/nsStyleLinkElement.cpp
dom/base/nsStyleLinkElement.h
dom/html/HTMLLinkElement.cpp
dom/html/HTMLLinkElement.h
dom/html/HTMLStyleElement.cpp
dom/html/HTMLStyleElement.h
dom/svg/SVGStyleElement.cpp
dom/svg/SVGStyleElement.h
dom/webidl/HTMLLinkElement.webidl
dom/xml/XMLStylesheetProcessingInstruction.cpp
dom/xml/XMLStylesheetProcessingInstruction.h
layout/style/Loader.cpp
layout/style/Loader.h
toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -805,17 +805,17 @@ nsContentSink::ProcessStyleLink(nsIConte
   mozilla::net::ReferrerPolicy referrerPolicy =
     mozilla::net::AttributeReferrerPolicyFromString(aReferrerPolicy);
   if (referrerPolicy == net::RP_Unset) {
     referrerPolicy = mDocument->GetReferrerPolicy();
   }
   // If this is a fragment parser, we don't want to observe.
   // We don't support CORS for processing instructions
   bool isAlternate;
-  rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
+  rv = mCSSLoader->LoadStyleLink(aElement, url, nullptr, aTitle, aMedia, aAlternate,
                                  CORS_NONE, referrerPolicy,
                                  integrity, mRunsToCompletion ? nullptr : this,
                                  &isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!isAlternate && !mRunsToCompletion) {
     ++mPendingSheetCount;
     mScriptLoader->AddParserBlockingScriptExecutionBlocker();
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -466,17 +466,18 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
 
   nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
     thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
   if (!doc || !doc->CSSLoader()->GetEnabled()) {
     return NS_OK;
   }
 
   bool isInline;
-  nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline);
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+  nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline, getter_AddRefs(triggeringPrincipal));
 
   if (!aForceUpdate && mStyleSheet && !isInline && uri) {
     nsIURI* oldURI = mStyleSheet->GetSheetURI();
     if (oldURI) {
       bool equal;
       nsresult rv = oldURI->Equals(uri, &equal);
       if (NS_SUCCEEDED(rv) && equal) {
         return NS_OK; // We already loaded this stylesheet
@@ -558,18 +559,18 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
                NS_ConvertUTF16toUTF8(integrity).get()));
     }
 
     // XXXbz clone the URI here to work around content policies modifying URIs.
     nsCOMPtr<nsIURI> clonedURI;
     uri->Clone(getter_AddRefs(clonedURI));
     NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
     rv = doc->CSSLoader()->
-      LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
-                    GetCORSMode(), referrerPolicy, integrity,
+      LoadStyleLink(thisContent, clonedURI, triggeringPrincipal, title, media,
+                    isAlternate, GetCORSMode(), referrerPolicy, integrity,
                     aObserver, &isAlternate);
     if (NS_FAILED(rv)) {
       // Don't propagate LoadStyleLink() errors further than this, since some
       // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
       // things like a stylesheet load being blocked by the security system.
       doneLoading = true;
       isAlternate = false;
       rv = NS_OK;
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -88,17 +88,17 @@ protected:
    *                     changed but the URI may not have changed.
    */
   nsresult UpdateStyleSheetInternal(nsIDocument *aOldDocument,
                                     mozilla::dom::ShadowRoot *aOldShadowRoot,
                                     bool aForceUpdate = false);
 
   void UpdateStyleSheetScopedness(bool aIsNowScoped);
 
-  virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) = 0;
+  virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) = 0;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsScoped,
                                  bool* aIsAlternate) = 0;
 
   virtual mozilla::CORSMode GetCORSMode() const
   {
@@ -132,15 +132,16 @@ private:
                               mozilla::dom::ShadowRoot* aOldShadowRoot,
                               nsICSSLoaderObserver* aObserver,
                               bool* aWillNotify,
                               bool* aIsAlternate,
                               bool aForceUpdate);
 
   RefPtr<mozilla::StyleSheet> mStyleSheet;
 protected:
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mDontLoadStyle;
   bool mUpdatesEnabled;
   uint32_t mLineNumber;
 };
 
 #endif /* nsStyleLinkElement_h___ */
 
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -279,16 +279,22 @@ HTMLLinkElement::AfterSetAttr(int32_t aN
   if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
     bool hasHref = aValue;
     Link::ResetLinkState(!!aNotify, hasHref);
     if (IsInUncomposedDoc()) {
       CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
     }
   }
 
+  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href) {
+    mTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
+        this, aValue ? aValue->GetStringValue() : EmptyString(),
+        aSubjectPrincipal);
+  }
+
   if (aValue) {
     if (aNameSpaceID == kNameSpaceID_None &&
         (aName == nsGkAtoms::href ||
          aName == nsGkAtoms::rel ||
          aName == nsGkAtoms::title ||
          aName == nsGkAtoms::media ||
          aName == nsGkAtoms::type ||
          aName == nsGkAtoms::as ||
@@ -396,24 +402,30 @@ HTMLLinkElement::RelList()
 
 already_AddRefed<nsIURI>
 HTMLLinkElement::GetHrefURI() const
 {
   return GetHrefURIForAnchors();
 }
 
 already_AddRefed<nsIURI>
-HTMLLinkElement::GetStyleSheetURL(bool* aIsInline)
+HTMLLinkElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = false;
+  *aTriggeringPrincipal = nullptr;
+
   nsAutoString href;
   GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
   if (href.IsEmpty()) {
     return nullptr;
   }
+
+  nsCOMPtr<nsIPrincipal> prin = mTriggeringPrincipal;
+  prin.forget(aTriggeringPrincipal);
+
   nsCOMPtr<nsIURI> uri = Link::GetURI();
   return uri.forget();
 }
 
 void
 HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
                                    nsAString& aType,
                                    nsAString& aMedia,
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -82,19 +82,23 @@ public:
   // WebIDL
   bool Disabled();
   void SetDisabled(bool aDisabled);
 
   void GetHref(nsAString& aValue)
   {
     GetURIAttr(nsGkAtoms::href, nullptr, aValue);
   }
-  void SetHref(const nsAString& aHref, ErrorResult& aRv)
+  void GetHref(nsString& aValue, nsIPrincipal&)
   {
-    SetHTMLAttr(nsGkAtoms::href, aHref, aRv);
+    GetHref(aValue);
+  }
+  void SetHref(const nsAString& aHref, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::href, aHref, aTriggeringPrincipal, aRv);
   }
   void GetCrossOrigin(nsAString& aResult)
   {
     // Null for both missing and invalid defaults is ok, since we
     // always parse to an enum value, so we don't need an invalid
     // default, and we _want_ the missing default to be null.
     GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
   }
@@ -199,17 +203,17 @@ public:
     ClearHasPendingLinkUpdate();
     nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
   }
 
 protected:
   virtual ~HTMLLinkElement();
 
   // nsStyleLinkElement
-  virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
+  virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) override;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsScoped,
                                  bool* aIsAlternate) override;
 protected:
   RefPtr<nsDOMTokenList> mRelList;
 };
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -181,19 +181,20 @@ HTMLStyleElement::SetInnerHTML(const nsA
   aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
 
   SetEnableUpdates(true);
 
   UpdateStyleSheetInternal(nullptr, nullptr);
 }
 
 already_AddRefed<nsIURI>
-HTMLStyleElement::GetStyleSheetURL(bool* aIsInline)
+HTMLStyleElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = true;
+  *aTriggeringPrincipal = nullptr;
   return nullptr;
 }
 
 void
 HTMLStyleElement::GetStyleSheetInfo(nsAString& aTitle,
                                     nsAString& aType,
                                     nsAString& aMedia,
                                     bool* aIsScoped,
--- a/dom/html/HTMLStyleElement.h
+++ b/dom/html/HTMLStyleElement.h
@@ -83,17 +83,17 @@ public:
     SetHTMLBoolAttr(nsGkAtoms::scoped, aScoped, aError);
   }
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 protected:
   virtual ~HTMLStyleElement();
 
-  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
+  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) override;
   void GetStyleSheetInfo(nsAString& aTitle,
                          nsAString& aType,
                          nsAString& aMedia,
                          bool* aIsScoped,
                          bool* aIsAlternate) override;
   /**
    * Common method to call from the various mutation observer methods.
    * aContent is a content node that's either the one that changed or its
--- a/dom/svg/SVGStyleElement.cpp
+++ b/dom/svg/SVGStyleElement.cpp
@@ -252,19 +252,20 @@ SVGStyleElement::SetTitle(const nsAStrin
 {
   rv = SetAttr(kNameSpaceID_None, nsGkAtoms::title, aTitle, true);
 }
 
 //----------------------------------------------------------------------
 // nsStyleLinkElement methods
 
 already_AddRefed<nsIURI>
-SVGStyleElement::GetStyleSheetURL(bool* aIsInline)
+SVGStyleElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = true;
+  *aTriggeringPrincipal = nullptr;
   return nullptr;
 }
 
 void
 SVGStyleElement::GetStyleSheetInfo(nsAString& aTitle,
                                    nsAString& aType,
                                    nsAString& aMedia,
                                    bool* aIsScoped,
--- a/dom/svg/SVGStyleElement.h
+++ b/dom/svg/SVGStyleElement.h
@@ -82,17 +82,17 @@ protected:
   // NS_IMPL_ELEMENT_CLONE_WITH_INIT usable with this class. This should be
   // completely optimized away.
   inline nsresult Init()
   {
     return NS_OK;
   }
 
   // nsStyleLinkElement overrides
-  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
+  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) override;
 
   void GetStyleSheetInfo(nsAString& aTitle,
                          nsAString& aType,
                          nsAString& aMedia,
                          bool* aIsScoped,
                          bool* aIsAlternate) override;
   virtual CORSMode GetCORSMode() const override;
 
--- a/dom/webidl/HTMLLinkElement.webidl
+++ b/dom/webidl/HTMLLinkElement.webidl
@@ -11,17 +11,17 @@
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-link-element
 [HTMLConstructor]
 interface HTMLLinkElement : HTMLElement {
   [Pure]
            attribute boolean disabled;
-  [CEReactions, SetterThrows, Pure]
+  [CEReactions, NeedsSubjectPrincipal, SetterThrows, Pure]
            attribute DOMString href;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString? crossOrigin;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString rel;
   [PutForwards=value]
   readonly attribute DOMTokenList relList;
   [CEReactions, SetterThrows, Pure]
--- a/dom/xml/XMLStylesheetProcessingInstruction.cpp
+++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp
@@ -95,19 +95,20 @@ XMLStylesheetProcessingInstruction::GetC
 
 /* virtual */ void
 XMLStylesheetProcessingInstruction::OverrideBaseURI(nsIURI* aNewBaseURI)
 {
   mOverriddenBaseURI = aNewBaseURI;
 }
 
 already_AddRefed<nsIURI>
-XMLStylesheetProcessingInstruction::GetStyleSheetURL(bool* aIsInline)
+XMLStylesheetProcessingInstruction::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = false;
+  *aTriggeringPrincipal = nullptr;
 
   nsAutoString href;
   if (!GetAttrValue(nsGkAtoms::href, href)) {
     return nullptr;
   }
 
   nsIURI *baseURL;
   nsIDocument *document = OwnerDoc();
--- a/dom/xml/XMLStylesheetProcessingInstruction.h
+++ b/dom/xml/XMLStylesheetProcessingInstruction.h
@@ -72,17 +72,17 @@ public:
   }
   using ProcessingInstruction::SetData; // Prevent hiding overloaded virtual function.
 
 protected:
   virtual ~XMLStylesheetProcessingInstruction();
 
   nsCOMPtr<nsIURI> mOverriddenBaseURI;
 
-  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
+  already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) override;
   void GetStyleSheetInfo(nsAString& aTitle,
                          nsAString& aType,
                          nsAString& aMedia,
                          bool* aIsScoped,
                          bool* aIsAlternate) override;
   virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
                                               bool aCloneText) const override;
 };
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1917,16 +1917,17 @@ Loader::LoadInlineStyle(nsIContent* aEle
     data->mMustNotify = true;
   }
   return rv;
 }
 
 nsresult
 Loader::LoadStyleLink(nsIContent* aElement,
                       nsIURI* aURL,
+                      nsIPrincipal* aTriggeringPrincipal,
                       const nsAString& aTitle,
                       const nsAString& aMedia,
                       bool aHasAlternateRel,
                       CORSMode aCORSMode,
                       ReferrerPolicy aReferrerPolicy,
                       const nsAString& aIntegrity,
                       nsICSSLoaderObserver* aObserver,
                       bool* aIsAlternate)
@@ -1942,18 +1943,21 @@ Loader::LoadStyleLink(nsIContent* aEleme
 
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
 
-  nsIPrincipal* principal =
-    aElement ? aElement->NodePrincipal() : mDocument->NodePrincipal();
+  nsIPrincipal* principal = aTriggeringPrincipal;
+  if (!principal) {
+    principal = aElement ? aElement->NodePrincipal()
+                         : mDocument->NodePrincipal();
+  }
 
   nsISupports* context = aElement;
   if (!context) {
     context = mDocument;
   }
 
   nsresult rv = CheckContentPolicy(principal, aURL, context, false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -251,29 +251,33 @@ public:
    * Load a linked (document) stylesheet.  If a successful result is returned,
    * aObserver is guaranteed to be notified asynchronously once the sheet is
    * loaded and marked complete.  If an error is returned, aObserver will not
    * be notified.  In addition to loading the sheet, this method will insert it
    * into the stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the the stylesheet.  May be null.
    * @param aURL the URL of the sheet.
+   * @param aTriggeringPrincipal the triggering principal for the load. May be
+   *        null, in which case the NodePrincipal() of the element (or
+   *        document if aElement is null) should be used.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
    * @param aHasAlternateRel whether the rel for this link included
    *        "alternate".
    * @param aCORSMode the CORS mode for this load.
    * @param aObserver the observer to notify when the load completes.
    *                  May be null.
    * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
    *        an alternate sheet.  Note that this need not match
    *        aHasAlternateRel.
    */
   nsresult LoadStyleLink(nsIContent* aElement,
                          nsIURI* aURL,
+                         nsIPrincipal* aTriggeringPrincipal,
                          const nsAString& aTitle,
                          const nsAString& aMedia,
                          bool aHasAlternateRel,
                          CORSMode aCORSMode,
                          ReferrerPolicy aReferrerPolicy,
                          const nsAString& aIntegrity,
                          nsICSSLoaderObserver* aObserver,
                          bool* aIsAlternate);
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
@@ -39,17 +39,17 @@ function registerStaticPage(path, conten
 }
 
 const BASE_URL = `http://localhost:${server.identity.primaryPort}`;
 
 /**
  * A set of tags which are automatically closed in HTML documents, and
  * do not require an explicit closing tag.
  */
-const AUTOCLOSE_TAGS = new Set(["img", "input", "source"]);
+const AUTOCLOSE_TAGS = new Set(["img", "input", "link", "source"]);
 
 /**
  * An object describing the elements to create for a specific test.
  *
  * @typedef {object} ElementTestCase
  * @property {Array} element
  *        A recursive array, describing the element to create, in the
  *        following format:
@@ -455,16 +455,21 @@ add_task(async function test_contentscri
       src: "imgset.png",
       srcAttr: "srcset",
     },
     {
       element: ["input", {type: "image"}],
       src: "input.png",
     },
     {
+      element: ["link", {rel: "stylesheet"}],
+      src: "link.css",
+      srcAttr: "href",
+    },
+    {
       element: ["picture", {}, ["source", {}], ["img", {}]],
       src: "picture.png",
       srcAttr: "srcset",
     },
     {
       element: ["script", {}],
       src: "script.js",
       liveSrc: false,