Bug 1407056: Part 2 - Override page CSP for loads by expanded principals. r?bz,krizsa
Per the CSP specification, content injected by extensions is meant to be
exempt from page CSP. This patch takes care of the most common case of content
injected by extension content scripts, which always have expanded principals
which inherit from the page principal.
In a follow-up, we'll probably need to extend the exemption to stylesheet
content loaded by extension codebase principals.
MozReview-Commit-ID: GlY887QAb5V
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -120,16 +120,26 @@ public:
// Call these to avoid the cost of virtual dispatch.
inline bool FastEquals(nsIPrincipal* aOther);
inline bool FastEqualsConsideringDomain(nsIPrincipal* aOther);
inline bool FastSubsumes(nsIPrincipal* aOther);
inline bool FastSubsumesConsideringDomain(nsIPrincipal* aOther);
inline bool FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther);
+ /**
+ * Returns true if this principal's CSP should override a document's CSP for
+ * loads that it triggers. Currently true only for expanded principals which
+ * subsume the document principal.
+ */
+ bool OverridesCSP(nsIPrincipal* aDocumentPrincipal)
+ {
+ return mKind == eExpandedPrincipal && FastSubsumes(aDocumentPrincipal);
+ }
+
protected:
virtual ~BasePrincipal();
// Note that this does not check OriginAttributes. Callers that depend on
// those must call Subsumes instead.
virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;
// Internal, side-effect-free check to determine whether the concrete
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -127,22 +127,28 @@ CSPService::ShouldLoad(uint32_t aContent
// or type is *not* subject to CSP.
// Please note, the correct way to opt-out of CSP using a custom
// protocolHandler is to set one of the nsIProtocolHandler flags
// that are whitelistet in subjectToCSP()
if (!sCSPEnabled || !subjectToCSP(aContentLocation, aContentType)) {
return NS_OK;
}
- // query the principal of the document; if no document is passed, then
- // fall back to using the requestPrincipal (e.g. service workers do not
- // pass a document).
+ // Find a principal to retrieve the CSP from. If we don't have a context node
+ // (because, for instance, the load originates in a service worker), or the
+ // requesting principal's CSP overrides our document CSP, use the request
+ // principal. Otherwise, use the document principal.
nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
- nsCOMPtr<nsIPrincipal> principal = node ? node->NodePrincipal()
- : aRequestPrincipal;
+ nsCOMPtr<nsIPrincipal> principal;
+ if (!node || (aRequestPrincipal &&
+ BasePrincipal::Cast(aRequestPrincipal)->OverridesCSP(node->NodePrincipal()))) {
+ principal = aRequestPrincipal;
+ } else {
+ principal = node->NodePrincipal();
+ }
if (!principal) {
// if we can't query a principal, then there is nothing to do.
return NS_OK;
}
nsresult rv = NS_OK;
// 1) Apply speculate CSP for preloads
bool isPreload = nsContentUtils::IsPreloadType(aContentType);