Bug 1415352: Part 4c - Use subject principal as the triggering principal for inline <style> nodes. r?bz draft
authorKris Maglione <maglione.k@gmail.com>
Tue, 07 Nov 2017 14:25:45 -0800
changeset 694622 15ab92e6689555a3b1b84bf11104b7f31e904279
parent 694621 e53e03181cd615e939bafde9676c72aca02e46cd
child 694623 793e2157fd27473489b35a92c58bdead7d89e1d5
push id88175
push usermaglione.k@gmail.com
push dateTue, 07 Nov 2017 23:59:46 +0000
reviewersbz
bugs1415352
milestone58.0a1
Bug 1415352: Part 4c - Use subject principal as the triggering principal for inline <style> nodes. r?bz This change captures the subject principal when a scripted caller sets the textContent or innerHTML property of a <style> node, and uses it as the triggering principal for the resulting stylesheet. If the node contents are modified in any way other than through textContent or innerHTML, the triggering principal is forgotten (which is an intentional design feature). MozReview-Commit-ID: GacZFIB5BzS
dom/base/nsStyleLinkElement.cpp
dom/html/HTMLStyleElement.cpp
dom/html/HTMLStyleElement.h
layout/style/Loader.cpp
layout/style/Loader.h
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -535,26 +535,26 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
     if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
                "<link> is not 'inline', and needs different CSP checks");
     if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
                                            thisContent->NodePrincipal(),
-                                           nullptr,
+                                           triggeringPrincipal,
                                            doc->GetDocumentURI(),
                                            mLineNumber, text, &rv))
       return rv;
 
     // Parse the style sheet.
     rv = doc->CSSLoader()->
-      LoadInlineStyle(thisContent, text, mLineNumber, title, media,
-                      referrerPolicy, scopeElement, aObserver, &doneLoading,
-                      &isAlternate);
+      LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber,
+                      title, media, referrerPolicy, scopeElement,
+                      aObserver, &doneLoading, &isAlternate);
   }
   else {
     nsAutoString integrity;
     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
     if (!integrity.IsEmpty()) {
       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
               ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
                NS_ConvertUTF16toUTF8(integrity).get()));
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -95,16 +95,17 @@ HTMLStyleElement::ContentRemoved(nsIDocu
                                  nsIContent* aPreviousSibling)
 {
   ContentChanged(aChild);
 }
 
 void
 HTMLStyleElement::ContentChanged(nsIContent* aContent)
 {
+  mTriggeringPrincipal = nullptr;
   if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
     UpdateStyleSheetInternal(nullptr, nullptr);
   }
 }
 
 nsresult
 HTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                              nsIContent* aBindingParent,
@@ -172,30 +173,40 @@ HTMLStyleElement::GetInnerHTML(nsAString
   return NS_OK;
 }
 
 void
 HTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML,
                                nsIPrincipal& aScriptedPrincipal,
                                ErrorResult& aError)
 {
+  SetTextContentInternal(aInnerHTML, &aScriptedPrincipal, aError);
+}
+
+void
+HTMLStyleElement::SetTextContentInternal(const nsAString& aTextContent,
+                                         nsIPrincipal* aScriptedPrincipal,
+                                         ErrorResult& aError)
+{
   SetEnableUpdates(false);
 
-  aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
+  aError = nsContentUtils::SetNodeTextContent(this, aTextContent, true);
 
   SetEnableUpdates(true);
 
+  mTriggeringPrincipal = aScriptedPrincipal;
+
   UpdateStyleSheetInternal(nullptr, nullptr);
 }
 
 already_AddRefed<nsIURI>
 HTMLStyleElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = true;
-  *aTriggeringPrincipal = nullptr;
+  *aTriggeringPrincipal = do_AddRef(mTriggeringPrincipal).take();
   return nullptr;
 }
 
 void
 HTMLStyleElement::GetStyleSheetInfo(nsAString& aTitle,
                                     nsAString& aType,
                                     nsAString& aMedia,
                                     bool* aIsScoped,
--- a/dom/html/HTMLStyleElement.h
+++ b/dom/html/HTMLStyleElement.h
@@ -31,16 +31,19 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLStyleElement,
                                            nsGenericHTMLElement)
 
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
   using nsGenericHTMLElement::SetInnerHTML;
   virtual void SetInnerHTML(const nsAString& aInnerHTML,
                             nsIPrincipal& aSubjectPrincipal,
                             mozilla::ErrorResult& aError) override;
+  virtual void SetTextContentInternal(const nsAString& aTextContent,
+                                      nsIPrincipal* aSubjectPrincipal,
+                                      mozilla::ErrorResult& aError) override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                 const nsAttrValue* aValue,
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1843,16 +1843,17 @@ Loader::DoSheetComplete(SheetLoadData* a
   }
 
   NS_RELEASE(aLoadData);  // this will release parents and siblings and all that
 }
 
 nsresult
 Loader::LoadInlineStyle(nsIContent* aElement,
                         const nsAString& aBuffer,
+                        nsIPrincipal* aTriggeringPrincipal,
                         uint32_t aLineNumber,
                         const nsAString& aTitle,
                         const nsAString& aMedia,
                         ReferrerPolicy aReferrerPolicy,
                         Element* aScopeElement,
                         nsICSSLoaderObserver* aObserver,
                         bool* aCompleted,
                         bool* aIsAlternate)
@@ -1895,22 +1896,32 @@ Loader::LoadInlineStyle(nsIContent* aEle
     ShadowRoot* containingShadow = aElement->GetContainingShadow();
     MOZ_ASSERT(containingShadow);
     containingShadow->InsertSheet(sheet, aElement);
   } else {
     rv = InsertSheetInDoc(sheet, aElement, mDocument);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  nsIPrincipal* principal = aElement->NodePrincipal();
+  if (aTriggeringPrincipal) {
+    // The triggering principal may be an expanded principal, which is safe to
+    // use for URL security checks, but not as the loader principal for a
+    // stylesheet. So treat this as principal inheritance, and downgrade if
+    // necessary.
+    principal = BasePrincipal::Cast(aTriggeringPrincipal)->PrincipalToInherit();
+  }
+
   SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
                                           owningElement, *aIsAlternate,
-                                          aObserver, nullptr, static_cast<nsINode*>(aElement));
+                                          aObserver, principal,
+                                          static_cast<nsINode*>(aElement));
 
   // We never actually load this, so just set its principal directly
-  sheet->SetPrincipal(aElement->NodePrincipal());
+  sheet->SetPrincipal(principal);
 
   NS_ADDREF(data);
   data->mLineNumber = aLineNumber;
   // Parse completion releases the load data
   rv = ParseSheet(aBuffer, Span<const uint8_t>(), data, *aCompleted);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If aCompleted is true, |data| may well be deleted by now.
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -222,28 +222,32 @@ public:
    * asynchronously once the sheet is marked complete.  If an error is
    * returned, or if *aCompleted is true, aObserver will not be notified.  In
    * addition to parsing the sheet, this method will insert it into the
    * stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the stylesheet.  This must not be
    *                 null and must implement nsIStyleSheetLinkingElement.
    * @param aBuffer the stylesheet data
+   * @param aTriggeringPrincipal The principal of the scripted caller that
+   *                             initiated the load, if available. Otherwise
+   *                             null.
    * @param aLineNumber the line number at which the stylesheet data started.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
    * @param aReferrerPolicy the referrer policy for loading the sheet.
    * @param aObserver the observer to notify when the load completes.
    *        May be null.
    * @param [out] aCompleted whether parsing of the sheet completed.
    * @param [out] aIsAlternate whether the stylesheet ended up being an
    *        alternate sheet.
    */
   nsresult LoadInlineStyle(nsIContent* aElement,
                            const nsAString& aBuffer,
+                           nsIPrincipal* aTriggeringPrincipal,
                            uint32_t aLineNumber,
                            const nsAString& aTitle,
                            const nsAString& aMedia,
                            ReferrerPolicy aReferrerPolicy,
                            mozilla::dom::Element* aScopeElement,
                            nsICSSLoaderObserver* aObserver,
                            bool* aCompleted,
                            bool* aIsAlternate);