Bug 1407056: Part 2 - Override page CSP for loads by expanded principals. r?bz,krizsa draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 07 Oct 2017 14:53:30 -0700
changeset 678075 c7fff19733cce0b609487cf0fbe44be11307ba1a
parent 678074 e88e951c7905b4df2cffa27ae86e2d42dc8da409
child 678076 ddf53adb94bb18f245fba0f3b055813dd5560118
push id83827
push usermaglione.k@gmail.com
push dateTue, 10 Oct 2017 20:40:33 +0000
reviewersbz, krizsa
bugs1407056
milestone58.0a1
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);