Bug 1407056: Part 2 - Override page CSP for loads by expanded principals. r=bz,krizsa
authorKris Maglione <maglione.k@gmail.com>
Sat, 07 Oct 2017 14:53:30 -0700
changeset 386035 41e5a4b54c93e40e92e1e697efa936e90a4c5a41
parent 386034 197ce71943518bfb260f2b2cb3f91b55e58f9341
child 386036 d480c295d4eb093b1890056cc724e12bda7ac3ca
push id32673
push userarchaeopteryx@coole-files.de
push dateFri, 13 Oct 2017 09:13:17 +0000
treeherdermozilla-central@196dadb2fe50 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, krizsa
bugs1407056
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 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
caps/BasePrincipal.h
dom/security/nsCSPService.cpp
--- 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);