LCOV - code coverage report
Current view: top level - dom/base - nsContentPolicy.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 64 87 73.6 %
Date: 2017-07-14 16:53:18 Functions: 7 10 70.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : // vim: ft=cpp tw=78 sw=4 et ts=8
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * Implementation of the "@mozilla.org/layout/content-policy;1" contract.
       9             :  */
      10             : 
      11             : #include "mozilla/Logging.h"
      12             : 
      13             : #include "nsISupports.h"
      14             : #include "nsXPCOM.h"
      15             : #include "nsContentPolicyUtils.h"
      16             : #include "mozilla/dom/nsCSPService.h"
      17             : #include "nsContentPolicy.h"
      18             : #include "nsIURI.h"
      19             : #include "nsIDocShell.h"
      20             : #include "nsIDOMElement.h"
      21             : #include "nsIDOMNode.h"
      22             : #include "nsIDOMWindow.h"
      23             : #include "nsIContent.h"
      24             : #include "nsIImageLoadingContent.h"
      25             : #include "nsILoadContext.h"
      26             : #include "nsCOMArray.h"
      27             : #include "nsContentUtils.h"
      28             : #include "mozilla/dom/nsMixedContentBlocker.h"
      29             : #include "nsIContentSecurityPolicy.h"
      30             : #include "mozilla/dom/TabGroup.h"
      31             : #include "mozilla/TaskCategory.h"
      32             : 
      33             : using mozilla::LogLevel;
      34             : 
      35          39 : NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
      36             : 
      37             : static mozilla::LazyLogModule gConPolLog("nsContentPolicy");
      38             : 
      39             : nsresult
      40           3 : NS_NewContentPolicy(nsIContentPolicy **aResult)
      41             : {
      42           3 :   *aResult = new nsContentPolicy;
      43           3 :   NS_ADDREF(*aResult);
      44           3 :   return NS_OK;
      45             : }
      46             : 
      47           3 : nsContentPolicy::nsContentPolicy()
      48             :     : mPolicies(NS_CONTENTPOLICY_CATEGORY)
      49             :     , mSimplePolicies(NS_SIMPLECONTENTPOLICY_CATEGORY)
      50             :     , mMixedContentBlocker(do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID))
      51           3 :     , mCSPService(do_GetService(CSPSERVICE_CONTRACTID))
      52             : {
      53           3 : }
      54             : 
      55           0 : nsContentPolicy::~nsContentPolicy()
      56             : {
      57           0 : }
      58             : 
      59             : #ifdef DEBUG
      60             : #define WARN_IF_URI_UNINITIALIZED(uri,name)                         \
      61             :   PR_BEGIN_MACRO                                                    \
      62             :     if ((uri)) {                                                    \
      63             :         nsAutoCString spec;                                         \
      64             :         (uri)->GetAsciiSpec(spec);                                  \
      65             :         if (spec.IsEmpty()) {                                       \
      66             :             NS_WARNING(name " is uninitialized, fix caller");       \
      67             :         }                                                           \
      68             :     }                                                               \
      69             :   PR_END_MACRO
      70             : 
      71             : #else  // ! defined(DEBUG)
      72             : 
      73             : #define WARN_IF_URI_UNINITIALIZED(uri,name)
      74             : 
      75             : #endif // defined(DEBUG)
      76             : 
      77             : inline nsresult
      78          23 : nsContentPolicy::CheckPolicy(CPMethod          policyMethod,
      79             :                              SCPMethod         simplePolicyMethod,
      80             :                              nsContentPolicyType contentType,
      81             :                              nsIURI           *contentLocation,
      82             :                              nsIURI           *requestingLocation,
      83             :                              nsISupports      *requestingContext,
      84             :                              const nsACString &mimeType,
      85             :                              nsISupports      *extra,
      86             :                              nsIPrincipal     *requestPrincipal,
      87             :                              int16_t           *decision)
      88             : {
      89             :     //sanity-check passed-through parameters
      90          23 :     NS_PRECONDITION(decision, "Null out pointer");
      91          23 :     WARN_IF_URI_UNINITIALIZED(contentLocation, "Request URI");
      92          23 :     WARN_IF_URI_UNINITIALIZED(requestingLocation, "Requesting URI");
      93             : 
      94             : #ifdef DEBUG
      95             :     {
      96          46 :         nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext));
      97          46 :         nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext));
      98          23 :         NS_ASSERTION(!requestingContext || node || window,
      99             :                      "Context should be a DOM node or a DOM window!");
     100             :     }
     101             : #endif
     102             : 
     103             :     /*
     104             :      * There might not be a requestinglocation. This can happen for
     105             :      * iframes with an image as src. Get the uri from the dom node.
     106             :      * See bug 254510
     107             :      */
     108          23 :     if (!requestingLocation) {
     109          20 :         nsCOMPtr<nsIDocument> doc;
     110          20 :         nsCOMPtr<nsIContent> node = do_QueryInterface(requestingContext);
     111          10 :         if (node) {
     112           1 :             doc = node->OwnerDoc();
     113             :         }
     114          10 :         if (!doc) {
     115           9 :             doc = do_QueryInterface(requestingContext);
     116             :         }
     117          10 :         if (doc) {
     118           1 :             requestingLocation = doc->GetDocumentURI();
     119             :         }
     120             :     }
     121             : 
     122             :     nsContentPolicyType externalType =
     123          23 :         nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
     124             : 
     125             :     /*
     126             :      * Enumerate mPolicies and ask each of them, taking the logical AND of
     127             :      * their permissions.
     128             :      */
     129             :     nsresult rv;
     130          23 :     const nsCOMArray<nsIContentPolicy>& entries = mPolicies.GetCachedEntries();
     131             : 
     132          46 :     nsCOMPtr<nsPIDOMWindowOuter> window;
     133          46 :     if (nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext)) {
     134          13 :         window = node->OwnerDoc()->GetWindow();
     135             :     } else {
     136          10 :         window = do_QueryInterface(requestingContext);
     137             :     }
     138             : 
     139          23 :     if (requestPrincipal) {
     140          46 :         nsCOMPtr<nsIContentSecurityPolicy> csp;
     141          23 :         requestPrincipal->GetCsp(getter_AddRefs(csp));
     142          23 :         if (csp && window) {
     143           0 :             csp->EnsureEventTarget(window->EventTargetFor(mozilla::TaskCategory::Other));
     144             :         }
     145             :     }
     146             : 
     147          23 :     int32_t count = entries.Count();
     148         184 :     for (int32_t i = 0; i < count; i++) {
     149             :         /* check the appropriate policy */
     150             :         // Send internal content policy type to CSP and mixed content blocker
     151         161 :         nsContentPolicyType type = externalType;
     152         161 :         if (mMixedContentBlocker == entries[i] || mCSPService == entries[i]) {
     153          46 :           type = contentType;
     154             :         }
     155         322 :         rv = (entries[i]->*policyMethod)(type, contentLocation,
     156             :                                          requestingLocation, requestingContext,
     157             :                                          mimeType, extra, requestPrincipal,
     158         322 :                                          decision);
     159             : 
     160         161 :         if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
     161             :             // If we are blocking an image, we have to let the
     162             :             // ImageLoadingContent know that we blocked the load.
     163           0 :             if (externalType == nsIContentPolicy::TYPE_IMAGE ||
     164             :                 externalType == nsIContentPolicy::TYPE_IMAGESET) {
     165             :               nsCOMPtr<nsIImageLoadingContent> img =
     166           0 :                 do_QueryInterface(requestingContext);
     167           0 :               if (img) {
     168           0 :                 img->SetBlockedRequest(*decision);
     169             :               }
     170             :             }
     171             :             /* policy says no, no point continuing to check */
     172           0 :             return NS_OK;
     173             :         }
     174             :     }
     175             : 
     176          46 :     nsCOMPtr<nsIDOMElement> topFrameElement;
     177          23 :     bool isTopLevel = true;
     178             : 
     179          23 :     if (window) {
     180          30 :         nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
     181          30 :         nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
     182          15 :         if (loadContext) {
     183          15 :           loadContext->GetTopFrameElement(getter_AddRefs(topFrameElement));
     184             :         }
     185             : 
     186          15 :         MOZ_ASSERT(window->IsOuterWindow());
     187             : 
     188          15 :         if (topFrameElement) {
     189           0 :             nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetScriptableTop();
     190           0 :             isTopLevel = topWindow == window;
     191             :         } else {
     192             :             // If we don't have a top frame element, then requestingContext is
     193             :             // part of the top-level XUL document. Presumably it's the <browser>
     194             :             // element that content is being loaded into, so we call it the
     195             :             // topFrameElement.
     196          15 :             topFrameElement = do_QueryInterface(requestingContext);
     197          15 :             isTopLevel = true;
     198             :         }
     199             :     }
     200             : 
     201             :     const nsCOMArray<nsISimpleContentPolicy>& simpleEntries =
     202          23 :         mSimplePolicies.GetCachedEntries();
     203          23 :     count = simpleEntries.Count();
     204          23 :     for (int32_t i = 0; i < count; i++) {
     205             :         /* check the appropriate policy */
     206           0 :         rv = (simpleEntries[i]->*simplePolicyMethod)(externalType, contentLocation,
     207             :                                                      requestingLocation,
     208             :                                                      topFrameElement, isTopLevel,
     209             :                                                      mimeType, extra, requestPrincipal,
     210           0 :                                                      decision);
     211             : 
     212           0 :         if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
     213             :             // If we are blocking an image, we have to let the
     214             :             // ImageLoadingContent know that we blocked the load.
     215           0 :             if (externalType == nsIContentPolicy::TYPE_IMAGE ||
     216             :                 externalType == nsIContentPolicy::TYPE_IMAGESET) {
     217             :               nsCOMPtr<nsIImageLoadingContent> img =
     218           0 :                 do_QueryInterface(requestingContext);
     219           0 :               if (img) {
     220           0 :                 img->SetBlockedRequest(*decision);
     221             :               }
     222             :             }
     223             :             /* policy says no, no point continuing to check */
     224           0 :             return NS_OK;
     225             :         }
     226             :     }
     227             : 
     228             :     // everyone returned failure, or no policies: sanitize result
     229          23 :     *decision = nsIContentPolicy::ACCEPT;
     230          23 :     return NS_OK;
     231             : }
     232             : 
     233             : //uses the parameters from ShouldXYZ to produce and log a message
     234             : //logType must be a literal string constant
     235             : #define LOG_CHECK(logType)                                                     \
     236             :   PR_BEGIN_MACRO                                                               \
     237             :     /* skip all this nonsense if the call failed or logging is disabled */     \
     238             :     if (NS_SUCCEEDED(rv) && MOZ_LOG_TEST(gConPolLog, LogLevel::Debug)) {       \
     239             :       const char *resultName;                                                  \
     240             :       if (decision) {                                                          \
     241             :         resultName = NS_CP_ResponseName(*decision);                            \
     242             :       } else {                                                                 \
     243             :         resultName = "(null ptr)";                                             \
     244             :       }                                                                        \
     245             :       MOZ_LOG(gConPolLog, LogLevel::Debug,                                     \
     246             :              ("Content Policy: " logType ": <%s> <Ref:%s> result=%s",          \
     247             :               contentLocation ? contentLocation->GetSpecOrDefault().get()      \
     248             :                               : "None",                                        \
     249             :               requestingLocation ? requestingLocation->GetSpecOrDefault().get()\
     250             :                                  : "None",                                     \
     251             :               resultName)                                                      \
     252             :              );                                                                \
     253             :     }                                                                          \
     254             :   PR_END_MACRO
     255             : 
     256             : NS_IMETHODIMP
     257          23 : nsContentPolicy::ShouldLoad(uint32_t          contentType,
     258             :                             nsIURI           *contentLocation,
     259             :                             nsIURI           *requestingLocation,
     260             :                             nsISupports      *requestingContext,
     261             :                             const nsACString &mimeType,
     262             :                             nsISupports      *extra,
     263             :                             nsIPrincipal     *requestPrincipal,
     264             :                             int16_t          *decision)
     265             : {
     266             :     // ShouldProcess does not need a content location, but we do
     267          23 :     NS_PRECONDITION(contentLocation, "Must provide request location");
     268          23 :     nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldLoad,
     269             :                               &nsISimpleContentPolicy::ShouldLoad,
     270             :                               contentType,
     271             :                               contentLocation, requestingLocation,
     272             :                               requestingContext, mimeType, extra,
     273          23 :                               requestPrincipal, decision);
     274          23 :     LOG_CHECK("ShouldLoad");
     275             : 
     276          23 :     return rv;
     277             : }
     278             : 
     279             : NS_IMETHODIMP
     280           0 : nsContentPolicy::ShouldProcess(uint32_t          contentType,
     281             :                                nsIURI           *contentLocation,
     282             :                                nsIURI           *requestingLocation,
     283             :                                nsISupports      *requestingContext,
     284             :                                const nsACString &mimeType,
     285             :                                nsISupports      *extra,
     286             :                                nsIPrincipal     *requestPrincipal,
     287             :                                int16_t          *decision)
     288             : {
     289           0 :     nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldProcess,
     290             :                               &nsISimpleContentPolicy::ShouldProcess,
     291             :                               contentType,
     292             :                               contentLocation, requestingLocation,
     293             :                               requestingContext, mimeType, extra,
     294           0 :                               requestPrincipal, decision);
     295           0 :     LOG_CHECK("ShouldProcess");
     296             : 
     297           0 :     return rv;
     298             : }

Generated by: LCOV version 1.13