Bug 1112782 - Update Redirect handling for CSP (r=sstamm)
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Wed, 17 Dec 2014 14:19:25 -0800
changeset 220291 1f46d4d9d1dc01c42a8d82fc19b0a29953289400
parent 220290 190df6248c74a717c02470421a85cce7b80bb1cc
child 220292 752e55372986a4782a2e15e65f66baf551165670
push id27983
push usercbook@mozilla.com
push dateThu, 18 Dec 2014 12:51:14 +0000
treeherdermozilla-central@9bb8b0b4daae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstamm
bugs1112782
milestone37.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 1112782 - Update Redirect handling for CSP (r=sstamm)
dom/security/nsCSPService.cpp
dom/security/nsCSPUtils.cpp
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -266,54 +266,54 @@ CSPService::ShouldProcess(uint32_t      
 NS_IMETHODIMP
 CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
                                    nsIChannel *newChannel,
                                    uint32_t flags,
                                    nsIAsyncVerifyRedirectCallback *callback)
 {
   nsAsyncRedirectAutoCallback autoCallback(callback);
 
+  nsCOMPtr<nsIURI> newUri;
+  nsresult rv = newChannel->GetURI(getter_AddRefs(newUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // No need to continue processing if CSP is disabled or if the protocol
+  // 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(newUri)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsILoadInfo> loadInfo;
-  nsresult rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+  rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
 
   // if no loadInfo on the channel, nothing for us to do
   if (!loadInfo) {
     return NS_OK;
   }
 
-  // The loadInfo must not necessarily contain a Node, hence we try to query
-  // the CSP in the following order:
-  //   a) Get the Node, the Principal of that Node, and the CSP of that Principal
-  //   b) Get the Principal and the CSP of that Principal
-
-  nsCOMPtr<nsINode> loadingNode = loadInfo->LoadingNode();
-  nsCOMPtr<nsIPrincipal> principal = loadingNode ?
-                                     loadingNode->NodePrincipal() :
-                                     loadInfo->LoadingPrincipal();
-  NS_ASSERTION(principal, "Can not evaluate CSP without a principal");
+  // Get the LoadingPrincipal and CSP from the loadInfo
   nsCOMPtr<nsIContentSecurityPolicy> csp;
-  rv = principal->GetCsp(getter_AddRefs(csp));
+  rv = loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // if there is no CSP, nothing for us to do
   if (!csp) {
     return NS_OK;
   }
 
   /* Since redirecting channels don't call into nsIContentPolicy, we call our
    * Content Policy implementation directly when redirects occur using the
    * information set in the LoadInfo when channels are created.
    *
    * We check if the CSP permits this host for this type of load, if not,
    * we cancel the load now.
    */
-
-  nsCOMPtr<nsIURI> newUri;
-  rv = newChannel->GetURI(getter_AddRefs(newUri));
-  NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIURI> originalUri;
   rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
   NS_ENSURE_SUCCESS(rv, rv);
   nsContentPolicyType policyType = loadInfo->GetContentPolicyType();
 
   int16_t aDecision = nsIContentPolicy::ACCEPT;
   csp->ShouldLoad(policyType,     // load type per nsIContentPolicy (uint32_t)
                   newUri,         // nsIURI
@@ -326,22 +326,24 @@ CSPService::AsyncOnChannelRedirect(nsICh
 #ifdef PR_LOGGING
   if (newUri) {
     nsAutoCString newUriSpec("None");
     newUri->GetSpec(newUriSpec);
     PR_LOG(gCspPRLog, PR_LOG_DEBUG,
            ("CSPService::AsyncOnChannelRedirect called for %s",
             newUriSpec.get()));
   }
-  if (aDecision == 1)
+  if (aDecision == true) {
     PR_LOG(gCspPRLog, PR_LOG_DEBUG,
            ("CSPService::AsyncOnChannelRedirect ALLOWING request."));
-  else
+  }
+  else {
     PR_LOG(gCspPRLog, PR_LOG_DEBUG,
            ("CSPService::AsyncOnChannelRedirect CANCELLING request."));
+  }
 #endif
 
   // if ShouldLoad doesn't accept the load, cancel the request
   if (!NS_CP_ACCEPTED(aDecision)) {
     autoCallback.DontCallback();
     return NS_BINDING_FAILED;
   }
   return NS_OK;
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -144,20 +144,16 @@ CSP_ContentTypeToDirective(nsContentPoli
       return nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_FONT:
       return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_MEDIA:
       return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
 
-    // TYPE_DOCUMENT shouldn't be used since it's specifically whitelisted by
-    // the CSPService, but in case we do want to know which directive to check,
-    // FRAME_SRC is the best fit.
-    case nsIContentPolicy::TYPE_DOCUMENT:
     case nsIContentPolicy::TYPE_SUBDOCUMENT:
       return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_WEBSOCKET:
     case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
     case nsIContentPolicy::TYPE_BEACON:
     case nsIContentPolicy::TYPE_FETCH:
       return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
@@ -167,18 +163,23 @@ CSP_ContentTypeToDirective(nsContentPoli
       return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_XBL:
     case nsIContentPolicy::TYPE_PING:
     case nsIContentPolicy::TYPE_DTD:
     case nsIContentPolicy::TYPE_OTHER:
       return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
 
-    // CSP can not block csp reports, fall through to error
+    // csp shold not block top level loads, e.g. in case
+    // of a redirect.
+    case nsIContentPolicy::TYPE_DOCUMENT:
+    // CSP can not block csp reports
     case nsIContentPolicy::TYPE_CSP_REPORT:
+      return nsIContentSecurityPolicy::NO_DIRECTIVE;
+
     // Fall through to error for all other directives
     default:
       MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
   }
   return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
 }
 
 nsCSPHostSrc*