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
--- 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);