tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsContentPolicyUtils.h (13095B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 * Utility routines for checking content load/process policy settings,
      8 * and routines helpful for content policy implementors.
      9 *
     10 * XXXbz it would be nice if some of this stuff could be out-of-lined in
     11 * nsContentUtils.  That would work for almost all the callers...
     12 */
     13 
     14 #ifndef __nsContentPolicyUtils_h__
     15 #define __nsContentPolicyUtils_h__
     16 
     17 #include "mozilla/BasePrincipal.h"
     18 #include "mozilla/dom/nsCSPService.h"
     19 #include "nsContentUtils.h"
     20 #include "nsIContent.h"
     21 #include "nsIContentPolicy.h"
     22 #include "nsIURI.h"
     23 #include "nsServiceManagerUtils.h"
     24 #include "nsStringFwd.h"
     25 
     26 // XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget
     27 #include "mozilla/dom/Document.h"
     28 #include "nsPIDOMWindow.h"
     29 
     30 #define NS_CONTENTPOLICY_CONTRACTID "@mozilla.org/layout/content-policy;1"
     31 #define NS_CONTENTPOLICY_CATEGORY "content-policy"
     32 #define NS_CONTENTPOLICY_CID \
     33  {0x0e3afd3d, 0xeb60, 0x4c2b, {0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24}}
     34 
     35 /**
     36 * Evaluates to true if val is ACCEPT.
     37 *
     38 * @param val the status returned from shouldProcess/shouldLoad
     39 */
     40 #define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT)
     41 
     42 /**
     43 * Evaluates to true if val is a REJECT_* status
     44 *
     45 * @param val the status returned from shouldProcess/shouldLoad
     46 */
     47 #define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT)
     48 
     49 // Offer convenient translations of constants -> const char*
     50 
     51 // convenience macro to reduce some repetative typing...
     52 // name is the name of a constant from this interface
     53 #define CASE_RETURN(name)      \
     54  case nsIContentPolicy::name: \
     55    return #name
     56 
     57 /**
     58 * Returns a string corresponding to the name of the response constant, or
     59 * "<Unknown Response>" if an unknown response value is given.
     60 *
     61 * The return value is static and must not be freed.
     62 *
     63 * @param response the response code
     64 * @return the name of the given response code
     65 */
     66 inline const char* NS_CP_ResponseName(int16_t response) {
     67  switch (response) {
     68    CASE_RETURN(REJECT_REQUEST);
     69    CASE_RETURN(REJECT_TYPE);
     70    CASE_RETURN(REJECT_SERVER);
     71    CASE_RETURN(REJECT_OTHER);
     72    CASE_RETURN(ACCEPT);
     73    default:
     74      return "<Unknown Response>";
     75  }
     76 }
     77 
     78 /**
     79 * Returns a string corresponding to the name of the content type constant, or
     80 * "<Unknown Type>" if an unknown content type value is given.
     81 *
     82 * The return value is static and must not be freed.
     83 *
     84 * @param contentType the content type code
     85 * @return the name of the given content type code
     86 */
     87 inline const char* NS_CP_ContentTypeName(nsContentPolicyType contentType) {
     88  switch (contentType) {
     89    CASE_RETURN(TYPE_OTHER);
     90    CASE_RETURN(TYPE_SCRIPT);
     91    CASE_RETURN(TYPE_IMAGE);
     92    CASE_RETURN(TYPE_STYLESHEET);
     93    CASE_RETURN(TYPE_OBJECT);
     94    CASE_RETURN(TYPE_DOCUMENT);
     95    CASE_RETURN(TYPE_SUBDOCUMENT);
     96    CASE_RETURN(TYPE_PING);
     97    CASE_RETURN(TYPE_XMLHTTPREQUEST);
     98    CASE_RETURN(TYPE_DTD);
     99    CASE_RETURN(TYPE_FONT);
    100    CASE_RETURN(TYPE_MEDIA);
    101    CASE_RETURN(TYPE_WEBSOCKET);
    102    CASE_RETURN(TYPE_CSP_REPORT);
    103    CASE_RETURN(TYPE_XSLT);
    104    CASE_RETURN(TYPE_BEACON);
    105    CASE_RETURN(TYPE_FETCH);
    106    CASE_RETURN(TYPE_IMAGESET);
    107    CASE_RETURN(TYPE_WEB_MANIFEST);
    108    CASE_RETURN(TYPE_INTERNAL_SCRIPT);
    109    CASE_RETURN(TYPE_INTERNAL_WORKER);
    110    CASE_RETURN(TYPE_INTERNAL_SHARED_WORKER);
    111    CASE_RETURN(TYPE_INTERNAL_EMBED);
    112    CASE_RETURN(TYPE_INTERNAL_OBJECT);
    113    CASE_RETURN(TYPE_INTERNAL_FRAME);
    114    CASE_RETURN(TYPE_INTERNAL_IFRAME);
    115    CASE_RETURN(TYPE_INTERNAL_AUDIO);
    116    CASE_RETURN(TYPE_INTERNAL_VIDEO);
    117    CASE_RETURN(TYPE_INTERNAL_TRACK);
    118    CASE_RETURN(TYPE_INTERNAL_XMLHTTPREQUEST_ASYNC);
    119    CASE_RETURN(TYPE_INTERNAL_EVENTSOURCE);
    120    CASE_RETURN(TYPE_INTERNAL_SERVICE_WORKER);
    121    CASE_RETURN(TYPE_INTERNAL_SCRIPT_PRELOAD);
    122    CASE_RETURN(TYPE_INTERNAL_IMAGE);
    123    CASE_RETURN(TYPE_INTERNAL_IMAGE_PRELOAD);
    124    CASE_RETURN(TYPE_INTERNAL_IMAGE_FAVICON);
    125    CASE_RETURN(TYPE_INTERNAL_STYLESHEET);
    126    CASE_RETURN(TYPE_INTERNAL_STYLESHEET_PRELOAD);
    127    CASE_RETURN(TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS);
    128    CASE_RETURN(TYPE_SAVEAS_DOWNLOAD);
    129    CASE_RETURN(TYPE_SPECULATIVE);
    130    CASE_RETURN(TYPE_INTERNAL_MODULE);
    131    CASE_RETURN(TYPE_INTERNAL_MODULE_PRELOAD);
    132    CASE_RETURN(TYPE_INTERNAL_DTD);
    133    CASE_RETURN(TYPE_INTERNAL_FORCE_ALLOWED_DTD);
    134    CASE_RETURN(TYPE_INTERNAL_AUDIOWORKLET);
    135    CASE_RETURN(TYPE_INTERNAL_PAINTWORKLET);
    136    CASE_RETURN(TYPE_INTERNAL_FONT_PRELOAD);
    137    CASE_RETURN(TYPE_INTERNAL_CHROMEUTILS_COMPILED_SCRIPT);
    138    CASE_RETURN(TYPE_INTERNAL_FRAME_MESSAGEMANAGER_SCRIPT);
    139    CASE_RETURN(TYPE_INTERNAL_FETCH_PRELOAD);
    140    CASE_RETURN(TYPE_UA_FONT);
    141    CASE_RETURN(TYPE_INTERNAL_WORKER_STATIC_MODULE);
    142    CASE_RETURN(TYPE_PROXIED_WEBRTC_MEDIA);
    143    CASE_RETURN(TYPE_WEB_IDENTITY);
    144    CASE_RETURN(TYPE_WEB_TRANSPORT);
    145    CASE_RETURN(TYPE_INTERNAL_XMLHTTPREQUEST_SYNC);
    146    CASE_RETURN(TYPE_INTERNAL_EXTERNAL_RESOURCE);
    147    CASE_RETURN(TYPE_JSON);
    148    CASE_RETURN(TYPE_INTERNAL_JSON_PRELOAD);
    149    CASE_RETURN(TYPE_END);
    150    case nsIContentPolicy::TYPE_INVALID:
    151      break;
    152      // Do not add default: so that compilers can catch the missing case.
    153  }
    154  return "<Unknown Type>";
    155 }
    156 
    157 #undef CASE_RETURN
    158 
    159 inline const char* NS_CP_ContentTypeName(ExtContentPolicyType contentType) {
    160  return NS_CP_ContentTypeName(static_cast<nsContentPolicyType>(contentType));
    161 }
    162 
    163 /* Passes on parameters from its "caller"'s context. */
    164 #define CHECK_CONTENT_POLICY(action)                          \
    165  PR_BEGIN_MACRO                                              \
    166  nsCOMPtr<nsIContentPolicy> policy =                         \
    167      do_GetService(NS_CONTENTPOLICY_CONTRACTID);             \
    168  if (!policy) return NS_ERROR_FAILURE;                       \
    169                                                              \
    170  return policy->action(contentLocation, loadInfo, decision); \
    171  PR_END_MACRO
    172 
    173 /* Passes on parameters from its "caller"'s context. */
    174 #define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy)     \
    175  PR_BEGIN_MACRO                                               \
    176  return _policy->action(contentLocation, loadInfo, decision); \
    177  PR_END_MACRO
    178 
    179 /**
    180 * Check whether we can short-circuit this check and bail out.  If not, get the
    181 * origin URI to use.
    182 *
    183 * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on
    184 * purpose */
    185 #define CHECK_PRINCIPAL_CSP_AND_DATA(action)                                  \
    186  PR_BEGIN_MACRO                                                              \
    187  if (loadingPrincipal && loadingPrincipal->IsSystemPrincipal()) {            \
    188    /* We exempt most loads into any document with the system principal       \
    189     * from content policy (except CSP) checks, mostly as an optimization.    \
    190     * Which means that we need to apply this check to the loading principal, \
    191     * not the principal that triggered the load. */                          \
    192    /* Check CSP for System Privileged pages */                               \
    193    CSPService::ConsultCSP(contentLocation, loadInfo, decision);              \
    194    if (NS_CP_REJECTED(*decision)) {                                          \
    195      return NS_OK;                                                           \
    196    }                                                                         \
    197    if (contentType != nsIContentPolicy::TYPE_DOCUMENT &&                     \
    198        contentType != nsIContentPolicy::TYPE_UA_FONT) {                      \
    199      *decision = nsIContentPolicy::ACCEPT;                                   \
    200      nsCOMPtr<nsINode> n = do_QueryInterface(context);                       \
    201      if (!n) {                                                               \
    202        nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(context);        \
    203        n = win ? win->GetExtantDoc() : nullptr;                              \
    204      }                                                                       \
    205      if (n) {                                                                \
    206        mozilla::dom::Document* d = n->OwnerDoc();                            \
    207        if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() ||                 \
    208            d->IsResourceDoc()) {                                             \
    209          nsCOMPtr<nsIContentPolicy> dataPolicy =                             \
    210              do_GetService("@mozilla.org/data-document-content-policy;1");   \
    211          if (dataPolicy) {                                                   \
    212            dataPolicy->action(contentLocation, loadInfo, decision);          \
    213          }                                                                   \
    214        }                                                                     \
    215      }                                                                       \
    216    }                                                                         \
    217    return NS_OK;                                                             \
    218  }                                                                           \
    219  PR_END_MACRO
    220 
    221 /**
    222 * Alias for calling ShouldLoad on the content policy service.  Parameters are
    223 * the same as nsIContentPolicy::shouldLoad, except for the loadingPrincipal
    224 * and triggeringPrincipal parameters (which should be non-null if possible,
    225 * and have the same semantics as in nsLoadInfo), and the last parameter,
    226 * which can be used to pass in a pointer to a useful service if the caller
    227 * already has it.  The origin URI to pass to shouldLoad will be the URI of
    228 * loadingPrincipal, unless loadingPrincipal is null (in which case a null
    229 * origin URI will be passed).
    230 */
    231 inline nsresult NS_CheckContentLoadPolicy(
    232    nsIURI* contentLocation, nsILoadInfo* loadInfo, int16_t* decision,
    233    nsIContentPolicy* policyService = nullptr) {
    234  nsIPrincipal* loadingPrincipal = loadInfo->GetLoadingPrincipal();
    235  nsCOMPtr<nsISupports> context = loadInfo->GetLoadingContext();
    236  nsContentPolicyType contentType = loadInfo->InternalContentPolicyType();
    237  CHECK_PRINCIPAL_CSP_AND_DATA(ShouldLoad);
    238  if (policyService) {
    239    CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService);
    240  }
    241  CHECK_CONTENT_POLICY(ShouldLoad);
    242 }
    243 
    244 /**
    245 * Alias for calling ShouldProcess on the content policy service.
    246 */
    247 inline nsresult NS_CheckContentProcessPolicy(
    248    nsIURI* contentLocation, nsILoadInfo* loadInfo, int16_t* decision,
    249    nsIContentPolicy* policyService = nullptr) {
    250  nsIPrincipal* loadingPrincipal = loadInfo->GetLoadingPrincipal();
    251  nsCOMPtr<nsISupports> context = loadInfo->GetLoadingContext();
    252  nsContentPolicyType contentType = loadInfo->InternalContentPolicyType();
    253  CHECK_PRINCIPAL_CSP_AND_DATA(ShouldProcess);
    254  if (policyService) {
    255    CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService);
    256  }
    257  CHECK_CONTENT_POLICY(ShouldProcess);
    258 }
    259 
    260 #undef CHECK_CONTENT_POLICY
    261 #undef CHECK_CONTENT_POLICY_WITH_SERVICE
    262 
    263 /**
    264 * Helper function to get an nsIDocShell given a context.
    265 * If the context is a document or window, the corresponding docshell will be
    266 * returned.
    267 * If the context is a non-document DOM node, the docshell of its ownerDocument
    268 * will be returned.
    269 *
    270 * @param aContext the context to find a docshell for (can be null)
    271 *
    272 * @return a WEAK pointer to the docshell, or nullptr if it could
    273 *     not be obtained
    274 *
    275 * @note  As of this writing, calls to nsIContentPolicy::Should{Load,Process}
    276 * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either
    277 * points to the frameElement of the window the load is happening in
    278 * (in which case NS_CP_GetDocShellFromContext will return the parent of the
    279 * docshell the load is happening in), or points to the window the load is
    280 * happening in (in which case NS_CP_GetDocShellFromContext will return
    281 * the docshell the load is happening in).  It's up to callers to QI aContext
    282 * and handle things accordingly if they want the docshell the load is
    283 * happening in.  These are somewhat odd semantics, and bug 466687 has been
    284 * filed to consider improving them.
    285 */
    286 inline nsIDocShell* NS_CP_GetDocShellFromContext(nsISupports* aContext) {
    287  if (!aContext) {
    288    return nullptr;
    289  }
    290 
    291  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aContext);
    292 
    293  if (!window) {
    294    // Our context might be a document.
    295    nsCOMPtr<mozilla::dom::Document> doc = do_QueryInterface(aContext);
    296    if (!doc) {
    297      // we were not a document after all, get our ownerDocument,
    298      // hopefully
    299      nsCOMPtr<nsIContent> content = do_QueryInterface(aContext);
    300      if (content) {
    301        doc = content->OwnerDoc();
    302      }
    303    }
    304 
    305    if (doc) {
    306      if (doc->GetDisplayDocument()) {
    307        doc = doc->GetDisplayDocument();
    308      }
    309 
    310      window = doc->GetWindow();
    311    }
    312  }
    313 
    314  if (!window) {
    315    return nullptr;
    316  }
    317 
    318  return window->GetDocShell();
    319 }
    320 
    321 #endif /* __nsContentPolicyUtils_h__ */