tor-browser

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

nsContentSecurityManager.cpp (68908B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 #include "nsContentSecurityManager.h"
      8 
      9 #include "js/RegExp.h"
     10 #include "jsapi.h"
     11 #include "mozilla/BasePrincipal.h"
     12 #include "mozilla/ClearOnShutdown.h"
     13 #include "mozilla/CmdLineAndEnvUtils.h"
     14 #include "mozilla/Components.h"
     15 #include "mozilla/ExtensionPolicyService.h"
     16 #include "mozilla/Logging.h"
     17 #include "mozilla/Maybe.h"
     18 #include "mozilla/Preferences.h"
     19 #include "mozilla/StaticPrefs_content.h"
     20 #include "mozilla/StaticPrefs_dom.h"
     21 #include "mozilla/StaticPrefs_security.h"
     22 #include "mozilla/dom/BrowserChild.h"
     23 #include "mozilla/dom/ContentChild.h"
     24 #include "mozilla/dom/ContentParent.h"
     25 #include "mozilla/dom/Document.h"
     26 #include "mozilla/dom/Element.h"
     27 #include "mozilla/dom/PolicyContainer.h"
     28 #include "mozilla/dom/nsMixedContentBlocker.h"
     29 #include "mozilla/extensions/WebExtensionPolicy.h"
     30 #include "mozilla/glean/DomSecurityMetrics.h"
     31 #include "nsAboutProtocolUtils.h"
     32 #include "nsArray.h"
     33 #include "nsCORSListenerProxy.h"
     34 #include "nsContentPolicyUtils.h"
     35 #include "nsContentSecurityUtils.h"
     36 #include "nsContentUtils.h"
     37 #include "nsDataHandler.h"
     38 #include "nsEscape.h"
     39 #include "nsIChannel.h"
     40 #include "nsIContentPolicy.h"
     41 #include "nsIHttpChannelInternal.h"
     42 #include "nsILoadInfo.h"
     43 #include "nsIMIMEService.h"
     44 #include "nsINode.h"
     45 #include "nsIOService.h"
     46 #include "nsIParentChannel.h"
     47 #include "nsIRedirectHistoryEntry.h"
     48 #include "nsIStreamListener.h"
     49 #include "nsIXPConnect.h"
     50 #include "nsIXULRuntime.h"
     51 #include "nsMimeTypes.h"
     52 #include "nsNetUtil.h"
     53 #include "nsReadableUtils.h"
     54 #include "nsSandboxFlags.h"
     55 #include "nsScriptSecurityManager.h"
     56 #include "xpcpublic.h"
     57 
     58 using namespace mozilla;
     59 using namespace mozilla::dom;
     60 
     61 NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager,
     62                  nsIChannelEventSink)
     63 
     64 mozilla::LazyLogModule sCSMLog("CSMLog");
     65 mozilla::LazyLogModule sUELLog("UnexpectedLoad");
     66 
     67 // These first two are used for off-the-main-thread checks of
     68 // general.config.filename
     69 //   (which can't be checked off-main-thread).
     70 Atomic<bool, mozilla::Relaxed> sJSHacksChecked(false);
     71 Atomic<bool, mozilla::Relaxed> sJSHacksPresent(false);
     72 Atomic<bool, mozilla::Relaxed> sCSSHacksChecked(false);
     73 Atomic<bool, mozilla::Relaxed> sCSSHacksPresent(false);
     74 
     75 /* static */
     76 bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
     77    nsIChannel* aChannel) {
     78  // Let's block all toplevel document navigations to a data: URI.
     79  // In all cases where the toplevel document is navigated to a
     80  // data: URI the triggeringPrincipal is a contentPrincipal, or
     81  // a NullPrincipal. In other cases, e.g. typing a data: URL into
     82  // the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
     83  // we don't want to block those loads. Only exception, loads coming
     84  // from an external applicaton (e.g. Thunderbird) don't load
     85  // using a contentPrincipal, but we want to block those loads.
     86  if (!StaticPrefs::security_data_uri_block_toplevel_data_uri_navigations()) {
     87    return true;
     88  }
     89  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
     90  if (loadInfo->GetExternalContentPolicyType() !=
     91      ExtContentPolicy::TYPE_DOCUMENT) {
     92    return true;
     93  }
     94  if (loadInfo->GetForceAllowDataURI()) {
     95    // if the loadinfo explicitly allows the data URI navigation, let's allow it
     96    // now
     97    return true;
     98  }
     99  nsCOMPtr<nsIURI> uri;
    100  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    101  NS_ENSURE_SUCCESS(rv, true);
    102  if (!uri->SchemeIs("data")) {
    103    return true;
    104  }
    105 
    106  nsAutoCString spec;
    107  rv = uri->GetSpec(spec);
    108  NS_ENSURE_SUCCESS(rv, true);
    109  nsAutoCString contentType;
    110  bool base64;
    111  rv = nsDataHandler::ParseURI(spec, contentType, nullptr, base64, nullptr);
    112  NS_ENSURE_SUCCESS(rv, true);
    113 
    114  // Allow data: images as long as they are not SVGs
    115  if (StringBeginsWith(contentType, "image/"_ns) &&
    116      !contentType.EqualsLiteral(IMAGE_SVG_XML)) {
    117    return true;
    118  }
    119  // Allow all data: PDFs. or JSON documents
    120  if (contentType.EqualsLiteral(APPLICATION_JSON) ||
    121      contentType.EqualsLiteral(TEXT_JSON) ||
    122      contentType.EqualsLiteral(APPLICATION_PDF)) {
    123    return true;
    124  }
    125  // Redirecting to a toplevel data: URI is not allowed, hence we make
    126  // sure the RedirectChain is empty.
    127  if (!loadInfo->GetLoadTriggeredFromExternal() &&
    128      loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
    129      loadInfo->RedirectChain().IsEmpty()) {
    130    return true;
    131  }
    132 
    133  ReportBlockedDataURI(uri, loadInfo);
    134 
    135  return false;
    136 }
    137 
    138 void nsContentSecurityManager::ReportBlockedDataURI(nsIURI* aURI,
    139                                                    nsILoadInfo* aLoadInfo,
    140                                                    bool aIsRedirect) {
    141  // We're going to block the request, construct the localized error message to
    142  // report to the console.
    143  nsAutoCString dataSpec;
    144  aURI->GetSpec(dataSpec);
    145  if (dataSpec.Length() > 50) {
    146    dataSpec.Truncate(50);
    147    dataSpec.AppendLiteral("...");
    148  }
    149  AutoTArray<nsString, 1> params;
    150  CopyUTF8toUTF16(NS_UnescapeURL(dataSpec), *params.AppendElement());
    151  nsAutoString errorText;
    152  const char* stringID =
    153      aIsRedirect ? "BlockRedirectToDataURI" : "BlockTopLevelDataURINavigation";
    154  nsresult rv = nsContentUtils::FormatLocalizedString(
    155      nsContentUtils::eSECURITY_PROPERTIES, stringID, params, errorText);
    156  if (NS_FAILED(rv)) {
    157    return;
    158  }
    159 
    160  // Report the localized error message to the console for the loading
    161  // BrowsingContext's current inner window.
    162  RefPtr<BrowsingContext> target = aLoadInfo->GetBrowsingContext();
    163  nsContentUtils::ReportToConsoleByWindowID(
    164      errorText, nsIScriptError::warningFlag, "DATA_URI_BLOCKED"_ns,
    165      target ? target->GetCurrentInnerWindowId() : 0);
    166 }
    167 
    168 /* static */
    169 bool nsContentSecurityManager::AllowInsecureRedirectToDataURI(
    170    nsIChannel* aNewChannel) {
    171  nsCOMPtr<nsILoadInfo> loadInfo = aNewChannel->LoadInfo();
    172  if (loadInfo->GetExternalContentPolicyType() !=
    173      ExtContentPolicy::TYPE_SCRIPT) {
    174    return true;
    175  }
    176  nsCOMPtr<nsIURI> newURI;
    177  nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
    178  if (NS_FAILED(rv) || !newURI || !newURI->SchemeIs("data")) {
    179    return true;
    180  }
    181 
    182  // Web Extensions are exempt from that restriction and are allowed to redirect
    183  // a channel to a data: URI. When a web extension redirects a channel, we set
    184  // a flag on the loadInfo which allows us to identify such redirects here.
    185  if (loadInfo->GetAllowInsecureRedirectToDataURI()) {
    186    return true;
    187  }
    188 
    189  ReportBlockedDataURI(newURI, loadInfo, true);
    190 
    191  return false;
    192 }
    193 
    194 static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) {
    195  nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode();
    196 
    197  // We should never perform a security check on a loadInfo that uses the flag
    198  // SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, because that is only used for
    199  // temporary loadInfos used for explicit nsIContentPolicy checks, but never be
    200  // set as a security flag on an actual channel.
    201  if (securityMode !=
    202          nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT &&
    203      securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED &&
    204      securityMode !=
    205          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT &&
    206      securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
    207      securityMode != nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
    208    MOZ_ASSERT(
    209        false,
    210        "need one securityflag from nsILoadInfo to perform security checks");
    211    return NS_ERROR_FAILURE;
    212  }
    213 
    214  // all good, found the right security flags
    215  return NS_OK;
    216 }
    217 
    218 static already_AddRefed<nsIPrincipal> GetExtensionSandboxPrincipal(
    219    nsILoadInfo* aLoadInfo) {
    220  // An extension is allowed to load resources from itself when its pages are
    221  // loaded into a sandboxed frame.  Extension resources in a sandbox have
    222  // a null principal and no access to extension APIs.  See "sandbox" in
    223  // MDN extension docs for more information.
    224  if (!aLoadInfo->TriggeringPrincipal()->GetIsNullPrincipal()) {
    225    return nullptr;
    226  }
    227  RefPtr<Document> doc;
    228  aLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
    229  if (!doc || !(doc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
    230    return nullptr;
    231  }
    232 
    233  // node principal is also a null principal here, so we need to
    234  // create a principal using documentURI, which is the moz-extension
    235  // uri for the page if this is an extension sandboxed page.
    236  nsCOMPtr<nsIPrincipal> docPrincipal = BasePrincipal::CreateContentPrincipal(
    237      doc->GetDocumentURI(), doc->NodePrincipal()->OriginAttributesRef());
    238 
    239  if (!BasePrincipal::Cast(docPrincipal)->AddonPolicy()) {
    240    return nullptr;
    241  }
    242  return docPrincipal.forget();
    243 }
    244 
    245 static bool IsImageLoadInEditorAppType(nsILoadInfo* aLoadInfo) {
    246  // Editor apps get special treatment here, editors can load images
    247  // from anywhere.  This allows editor to insert images from file://
    248  // into documents that are being edited.
    249  nsContentPolicyType type = aLoadInfo->InternalContentPolicyType();
    250  if (type != nsIContentPolicy::TYPE_INTERNAL_IMAGE &&
    251      type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD &&
    252      type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON &&
    253      type != nsIContentPolicy::TYPE_IMAGESET) {
    254    return false;
    255  }
    256 
    257  auto appType = nsIDocShell::APP_TYPE_UNKNOWN;
    258  nsINode* node = aLoadInfo->LoadingNode();
    259  if (!node) {
    260    return false;
    261  }
    262  Document* doc = node->OwnerDoc();
    263  if (!doc) {
    264    return false;
    265  }
    266 
    267  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
    268  if (!docShellTreeItem) {
    269    return false;
    270  }
    271 
    272  nsCOMPtr<nsIDocShellTreeItem> root;
    273  docShellTreeItem->GetInProcessRootTreeItem(getter_AddRefs(root));
    274  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
    275  if (docShell) {
    276    appType = docShell->GetAppType();
    277  }
    278 
    279  return appType == nsIDocShell::APP_TYPE_EDITOR;
    280 }
    281 
    282 static nsresult DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
    283  // In practice, these DTDs are just used for localization, so applying the
    284  // same principal check as Fluent.
    285  if (aLoadInfo->InternalContentPolicyType() ==
    286      nsIContentPolicy::TYPE_INTERNAL_DTD) {
    287    RefPtr<Document> doc;
    288    aLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
    289    bool allowed = false;
    290    aLoadInfo->TriggeringPrincipal()->IsL10nAllowed(
    291        doc ? doc->GetDocumentURI() : nullptr, &allowed);
    292 
    293    return allowed ? NS_OK : NS_ERROR_DOM_BAD_URI;
    294  }
    295 
    296  // This is used in order to allow a privileged DOMParser to parse documents
    297  // that need to access localization DTDs. We just allow through
    298  // TYPE_INTERNAL_FORCE_ALLOWED_DTD no matter what the triggering principal is.
    299  if (aLoadInfo->InternalContentPolicyType() ==
    300      nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD) {
    301    return NS_OK;
    302  }
    303 
    304  if (IsImageLoadInEditorAppType(aLoadInfo)) {
    305    return NS_OK;
    306  }
    307 
    308  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
    309  nsCOMPtr<nsIPrincipal> addonPrincipal =
    310      GetExtensionSandboxPrincipal(aLoadInfo);
    311  if (addonPrincipal) {
    312    // call CheckLoadURIWithPrincipal() as below to continue other checks, but
    313    // with the addon principal.
    314    triggeringPrincipal = addonPrincipal;
    315  }
    316 
    317  // Only call CheckLoadURIWithPrincipal() using the TriggeringPrincipal and not
    318  // the LoadingPrincipal when SEC_ALLOW_CROSS_ORIGIN_* security flags are set,
    319  // to allow, e.g. user stylesheets to load chrome:// URIs.
    320  return nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
    321      triggeringPrincipal, aURI, aLoadInfo->CheckLoadURIFlags(),
    322      aLoadInfo->GetInnerWindowID());
    323 }
    324 
    325 static bool URIHasFlags(nsIURI* aURI, uint32_t aURIFlags) {
    326  bool hasFlags;
    327  nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags);
    328  NS_ENSURE_SUCCESS(rv, false);
    329 
    330  return hasFlags;
    331 }
    332 
    333 static nsresult DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo,
    334                            nsIChannel* aChannel) {
    335  if (aLoadInfo->GetAllowChrome() &&
    336      (URIHasFlags(aURI, nsIProtocolHandler::URI_IS_UI_RESOURCE) ||
    337       nsContentUtils::SchemeIs(aURI, "moz-safe-about"))) {
    338    // UI resources are allowed.
    339    return DoCheckLoadURIChecks(aURI, aLoadInfo);
    340  }
    341 
    342  if (NS_HasBeenCrossOrigin(aChannel, true)) {
    343    NS_SetRequestBlockingReason(aLoadInfo,
    344                                nsILoadInfo::BLOCKING_REASON_NOT_SAME_ORIGIN);
    345    return NS_ERROR_DOM_BAD_URI;
    346  }
    347 
    348  return NS_OK;
    349 }
    350 
    351 // Determine which principal to use in DoCORSChecks.  Normally, we do CORS
    352 // checks using the LoadingPrincipal (whose Origin comes from the host
    353 // document).  But under certain configurations/situations, we instead use
    354 // the TriggeringPrincipal() (whose Origin comes from the specific resource
    355 // that initiated the request).
    356 static nsIPrincipal* DeterminePrincipalForCORSChecks(nsILoadInfo* aLoadInfo) {
    357  nsIPrincipal* const triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
    358 
    359  if (StaticPrefs::content_cors_use_triggering_principal()) {
    360    // This pref forces us to use the TriggeringPrincipal.
    361    // TODO(dholbert): Remove this special-case, perhaps right after we
    362    // fix bug 1982916 which requires it for a test.
    363    return triggeringPrincipal;
    364  }
    365 
    366  if (!StaticPrefs::extensions_content_web_accessible_enabled() &&
    367      triggeringPrincipal->GetIsAddonOrExpandedAddonPrincipal()) {
    368    // If we get here, then we know:
    369    // * we want to allow MV2 WebExtensions to access their own resources
    370    // regardless of whether those are listed in 'web_accessible_resources' in
    371    // their manifest (this is nonstandard but it's a legacy thing we allow).
    372    // * this load was initiated by a WebExtension (possibly running in a
    373    // content script in the context of a web page).
    374    //
    375    // Hence: in this case, we use the TriggeringPrincipal for our CORS checks
    376    // (so that a WebExtension requesting its own resources will be treated as
    377    // same-origin, rather than being rejected as a cross-origin request from
    378    // the page's origin).
    379    //
    380    // NOTE: Technically we should also check whether the extension uses MV2
    381    // here, since this pref is specific to MV2. But that's not strictly
    382    // necessary because we already unconditionally block MV3-WebExtension
    383    // content-loads of this type at a different level (in
    384    // nsScriptSecurityManager::CheckLoadURIWithPrincipal).
    385    return triggeringPrincipal;
    386  }
    387 
    388  // Otherwise we use the LoadingPrincipal.
    389  return aLoadInfo->GetLoadingPrincipal();
    390 }
    391 
    392 static nsresult DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo,
    393                             nsCOMPtr<nsIStreamListener>& aInAndOutListener) {
    394  MOZ_RELEASE_ASSERT(aInAndOutListener,
    395                     "can not perform CORS checks without a listener");
    396 
    397  // No need to set up CORS if TriggeringPrincipal is the SystemPrincipal.
    398  if (aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
    399    return NS_OK;
    400  }
    401 
    402  nsIPrincipal* principalForCORSCheck =
    403      DeterminePrincipalForCORSChecks(aLoadInfo);
    404 
    405  RefPtr<nsCORSListenerProxy> corsListener = new nsCORSListenerProxy(
    406      aInAndOutListener, principalForCORSCheck,
    407      aLoadInfo->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE);
    408  // XXX: @arg: DataURIHandling::Allow
    409  // lets use  DataURIHandling::Allow for now and then decide on callsite basis.
    410  // see also:
    411  // http://mxr.mozilla.org/mozilla-central/source/dom/security/nsCORSListenerProxy.h#33
    412  nsresult rv = corsListener->Init(aChannel, DataURIHandling::Allow);
    413  NS_ENSURE_SUCCESS(rv, rv);
    414  aInAndOutListener = corsListener;
    415  return NS_OK;
    416 }
    417 
    418 static nsresult DoContentSecurityChecks(nsIChannel* aChannel,
    419                                        nsILoadInfo* aLoadInfo) {
    420  ExtContentPolicyType contentPolicyType =
    421      aLoadInfo->GetExternalContentPolicyType();
    422 
    423  nsCOMPtr<nsIURI> uri;
    424  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    425  NS_ENSURE_SUCCESS(rv, rv);
    426 
    427  switch (contentPolicyType) {
    428    case ExtContentPolicy::TYPE_XMLHTTPREQUEST: {
    429 #ifdef DEBUG
    430      {
    431        nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
    432        MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
    433                   "type_xml requires requestingContext of type Document");
    434      }
    435 #endif
    436      break;
    437    }
    438 
    439    case ExtContentPolicy::TYPE_DTD: {
    440 #ifdef DEBUG
    441      {
    442        nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
    443        MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
    444                   "type_dtd requires requestingContext of type Document");
    445      }
    446 #endif
    447      break;
    448    }
    449 
    450    case ExtContentPolicy::TYPE_MEDIA: {
    451 #ifdef DEBUG
    452      {
    453        nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
    454        MOZ_ASSERT(!node || node->NodeType() == nsINode::ELEMENT_NODE,
    455                   "type_media requires requestingContext of type Element");
    456      }
    457 #endif
    458      break;
    459    }
    460 
    461    case ExtContentPolicy::TYPE_WEBSOCKET: {
    462      // Websockets have to use the proxied URI:
    463      // ws:// instead of http:// for CSP checks
    464      nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
    465          do_QueryInterface(aChannel);
    466      MOZ_ASSERT(httpChannelInternal);
    467      if (httpChannelInternal) {
    468        rv = httpChannelInternal->GetProxyURI(getter_AddRefs(uri));
    469        MOZ_ASSERT(NS_SUCCEEDED(rv));
    470      }
    471      break;
    472    }
    473 
    474    case ExtContentPolicy::TYPE_XSLT: {
    475 #ifdef DEBUG
    476      {
    477        nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
    478        MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
    479                   "type_xslt requires requestingContext of type Document");
    480      }
    481 #endif
    482      break;
    483    }
    484 
    485    case ExtContentPolicy::TYPE_BEACON: {
    486 #ifdef DEBUG
    487      {
    488        nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
    489        MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
    490                   "type_beacon requires requestingContext of type Document");
    491      }
    492 #endif
    493      break;
    494    }
    495 
    496    case ExtContentPolicy::TYPE_OTHER:
    497    case ExtContentPolicy::TYPE_SCRIPT:
    498    case ExtContentPolicy::TYPE_IMAGE:
    499    case ExtContentPolicy::TYPE_STYLESHEET:
    500    case ExtContentPolicy::TYPE_OBJECT:
    501    case ExtContentPolicy::TYPE_DOCUMENT:
    502    case ExtContentPolicy::TYPE_SUBDOCUMENT:
    503    case ExtContentPolicy::TYPE_PING:
    504    case ExtContentPolicy::TYPE_FONT:
    505    case ExtContentPolicy::TYPE_UA_FONT:
    506    case ExtContentPolicy::TYPE_CSP_REPORT:
    507    case ExtContentPolicy::TYPE_WEB_MANIFEST:
    508    case ExtContentPolicy::TYPE_FETCH:
    509    case ExtContentPolicy::TYPE_IMAGESET:
    510    case ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD:
    511    case ExtContentPolicy::TYPE_SPECULATIVE:
    512    case ExtContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA:
    513    case ExtContentPolicy::TYPE_WEB_TRANSPORT:
    514    case ExtContentPolicy::TYPE_WEB_IDENTITY:
    515    case ExtContentPolicy::TYPE_JSON:
    516      break;
    517 
    518    case ExtContentPolicy::TYPE_INVALID:
    519      MOZ_ASSERT(false,
    520                 "can not perform security check without a valid contentType");
    521      // Do not add default: so that compilers can catch the missing case.
    522  }
    523 
    524  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
    525  rv = NS_CheckContentLoadPolicy(uri, aLoadInfo, &shouldLoad,
    526                                 nsContentUtils::GetContentPolicy());
    527 
    528  if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
    529    NS_SetRequestBlockingReasonIfNull(
    530        aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_GENERAL);
    531 
    532    if (NS_SUCCEEDED(rv) &&
    533        (contentPolicyType == ExtContentPolicy::TYPE_DOCUMENT ||
    534         contentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT)) {
    535      if (shouldLoad == nsIContentPolicy::REJECT_TYPE) {
    536        // for docshell loads we might have to return SHOW_ALT.
    537        return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
    538      }
    539      if (shouldLoad == nsIContentPolicy::REJECT_POLICY) {
    540        return NS_ERROR_BLOCKED_BY_POLICY;
    541      }
    542    }
    543    return NS_ERROR_CONTENT_BLOCKED;
    544  }
    545 
    546  return NS_OK;
    547 }
    548 
    549 static void LogHTTPSOnlyInfo(nsILoadInfo* aLoadInfo) {
    550  MOZ_LOG(sCSMLog, LogLevel::Verbose, ("  httpsOnlyFirstStatus:"));
    551  uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
    552 
    553  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) {
    554    MOZ_LOG(sCSMLog, LogLevel::Verbose, ("    - HTTPS_ONLY_UNINITIALIZED"));
    555  }
    556  if (httpsOnlyStatus &
    557      nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED) {
    558    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    559            ("    - HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED"));
    560  }
    561  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED) {
    562    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    563            ("    - HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED"));
    564  }
    565  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
    566    MOZ_LOG(sCSMLog, LogLevel::Verbose, ("    - HTTPS_ONLY_EXEMPT"));
    567  }
    568  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS) {
    569    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    570            ("    - HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS"));
    571  }
    572  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DOWNLOAD_IN_PROGRESS) {
    573    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    574            ("    - HTTPS_ONLY_DOWNLOAD_IN_PROGRESS"));
    575  }
    576  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE) {
    577    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    578            ("    - HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE"));
    579  }
    580  if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST) {
    581    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    582            ("    - HTTPS_ONLY_UPGRADED_HTTPS_FIRST"));
    583  }
    584 }
    585 
    586 static void LogPrincipal(nsIPrincipal* aPrincipal,
    587                         const nsAString& aPrincipalName,
    588                         const uint8_t& aNestingLevel) {
    589  nsPrintfCString aIndentationString("%*s", aNestingLevel * 2, "");
    590 
    591  if (aPrincipal && aPrincipal->IsSystemPrincipal()) {
    592    MOZ_LOG(sCSMLog, LogLevel::Debug,
    593            ("%s%s: SystemPrincipal\n", aIndentationString.get(),
    594             NS_ConvertUTF16toUTF8(aPrincipalName).get()));
    595    return;
    596  }
    597  if (aPrincipal) {
    598    if (aPrincipal->GetIsNullPrincipal()) {
    599      MOZ_LOG(sCSMLog, LogLevel::Debug,
    600              ("%s%s: NullPrincipal\n", aIndentationString.get(),
    601               NS_ConvertUTF16toUTF8(aPrincipalName).get()));
    602      return;
    603    }
    604    if (aPrincipal->GetIsExpandedPrincipal()) {
    605      nsCOMPtr<nsIExpandedPrincipal> expanded(do_QueryInterface(aPrincipal));
    606      nsAutoCString origin;
    607      origin.AssignLiteral("[Expanded Principal [");
    608 
    609      StringJoinAppend(origin, ", "_ns, expanded->AllowList(),
    610                       [](nsACString& dest, nsIPrincipal* principal) {
    611                         nsAutoCString subOrigin;
    612                         DebugOnly<nsresult> rv =
    613                             principal->GetOrigin(subOrigin);
    614                         MOZ_ASSERT(NS_SUCCEEDED(rv));
    615                         dest.Append(subOrigin);
    616                       });
    617 
    618      origin.AppendLiteral("]]");
    619 
    620      MOZ_LOG(sCSMLog, LogLevel::Debug,
    621              ("%s%s: %s\n", aIndentationString.get(),
    622               NS_ConvertUTF16toUTF8(aPrincipalName).get(), origin.get()));
    623      return;
    624    }
    625    nsAutoCString principalSpec;
    626    aPrincipal->GetAsciiSpec(principalSpec);
    627    if (aPrincipalName.IsEmpty()) {
    628      MOZ_LOG(sCSMLog, LogLevel::Debug,
    629              ("%s - \"%s\"\n", aIndentationString.get(), principalSpec.get()));
    630    } else {
    631      MOZ_LOG(
    632          sCSMLog, LogLevel::Debug,
    633          ("%s%s: \"%s\"\n", aIndentationString.get(),
    634           NS_ConvertUTF16toUTF8(aPrincipalName).get(), principalSpec.get()));
    635    }
    636    return;
    637  }
    638  MOZ_LOG(sCSMLog, LogLevel::Debug,
    639          ("%s%s: nullptr\n", aIndentationString.get(),
    640           NS_ConvertUTF16toUTF8(aPrincipalName).get()));
    641 }
    642 
    643 static void LogSecurityFlags(nsSecurityFlags securityFlags) {
    644  struct DebugSecFlagType {
    645    unsigned long secFlag;
    646    char secTypeStr[128];
    647  };
    648  static const DebugSecFlagType secTypes[] = {
    649      {nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
    650       "SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK"},
    651      {nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
    652       "SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT"},
    653      {nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
    654       "SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED"},
    655      {nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
    656       "SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT"},
    657      {nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    658       "SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL"},
    659      {nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT,
    660       "SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"},
    661      {nsILoadInfo::SEC_COOKIES_DEFAULT, "SEC_COOKIES_DEFAULT"},
    662      {nsILoadInfo::SEC_COOKIES_INCLUDE, "SEC_COOKIES_INCLUDE"},
    663      {nsILoadInfo::SEC_COOKIES_SAME_ORIGIN, "SEC_COOKIES_SAME_ORIGIN"},
    664      {nsILoadInfo::SEC_COOKIES_OMIT, "SEC_COOKIES_OMIT"},
    665      {nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, "SEC_FORCE_INHERIT_PRINCIPAL"},
    666      {nsILoadInfo::SEC_ABOUT_BLANK_INHERITS, "SEC_ABOUT_BLANK_INHERITS"},
    667      {nsILoadInfo::SEC_ALLOW_CHROME, "SEC_ALLOW_CHROME"},
    668      {nsILoadInfo::SEC_DISALLOW_SCRIPT, "SEC_DISALLOW_SCRIPT"},
    669      {nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS, "SEC_DONT_FOLLOW_REDIRECTS"},
    670      {nsILoadInfo::SEC_LOAD_ERROR_PAGE, "SEC_LOAD_ERROR_PAGE"},
    671      {nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER,
    672       "SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER"}};
    673 
    674  for (const DebugSecFlagType& flag : secTypes) {
    675    if (securityFlags & flag.secFlag) {
    676      // the logging level should be in sync with the logging level in
    677      // DebugDoContentSecurityCheck()
    678      MOZ_LOG(sCSMLog, LogLevel::Verbose, ("    - %s\n", flag.secTypeStr));
    679    }
    680  }
    681 }
    682 static void DebugDoContentSecurityCheck(nsIChannel* aChannel,
    683                                        nsILoadInfo* aLoadInfo) {
    684  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
    685 
    686  MOZ_LOG(sCSMLog, LogLevel::Debug, ("\n#DebugDoContentSecurityCheck Begin\n"));
    687 
    688  // we only log http channels, unless loglevel is 5.
    689  if (httpChannel || MOZ_LOG_TEST(sCSMLog, LogLevel::Verbose)) {
    690    MOZ_LOG(sCSMLog, LogLevel::Verbose, ("doContentSecurityCheck:\n"));
    691 
    692    nsAutoCString remoteType;
    693    if (XRE_IsParentProcess()) {
    694      nsCOMPtr<nsIParentChannel> parentChannel;
    695      NS_QueryNotificationCallbacks(aChannel, parentChannel);
    696      if (parentChannel) {
    697        parentChannel->GetRemoteType(remoteType);
    698      }
    699    } else {
    700      remoteType.Assign(
    701          mozilla::dom::ContentChild::GetSingleton()->GetRemoteType());
    702    }
    703    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    704            ("  processType: \"%s\"\n", remoteType.get()));
    705 
    706    nsCOMPtr<nsIURI> channelURI;
    707    nsAutoCString channelSpec;
    708    nsAutoCString channelMethod;
    709    NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
    710    if (channelURI) {
    711      channelURI->GetSpec(channelSpec);
    712    }
    713    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    714            ("  channelURI: \"%s\"\n", channelSpec.get()));
    715 
    716    // Log HTTP-specific things
    717    if (httpChannel) {
    718      nsresult rv;
    719      rv = httpChannel->GetRequestMethod(channelMethod);
    720      if (!NS_FAILED(rv)) {
    721        MOZ_LOG(sCSMLog, LogLevel::Verbose,
    722                ("  httpMethod: %s\n", channelMethod.get()));
    723      }
    724    }
    725 
    726    // Log Principals
    727    nsCOMPtr<nsIPrincipal> requestPrincipal = aLoadInfo->TriggeringPrincipal();
    728    LogPrincipal(aLoadInfo->GetLoadingPrincipal(), u"loadingPrincipal"_ns, 1);
    729    LogPrincipal(requestPrincipal, u"triggeringPrincipal"_ns, 1);
    730    LogPrincipal(aLoadInfo->PrincipalToInherit(), u"principalToInherit"_ns, 1);
    731 
    732    // Log Redirect Chain
    733    MOZ_LOG(sCSMLog, LogLevel::Verbose, ("  redirectChain:\n"));
    734    for (nsIRedirectHistoryEntry* redirectHistoryEntry :
    735         aLoadInfo->RedirectChain()) {
    736      nsCOMPtr<nsIPrincipal> principal;
    737      redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
    738      LogPrincipal(principal, u""_ns, 2);
    739    }
    740 
    741    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    742            ("  internalContentPolicyType: %s\n",
    743             NS_CP_ContentTypeName(aLoadInfo->InternalContentPolicyType())));
    744    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    745            ("  externalContentPolicyType: %s\n",
    746             NS_CP_ContentTypeName(aLoadInfo->GetExternalContentPolicyType())));
    747    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    748            ("  upgradeInsecureRequests: %s\n",
    749             aLoadInfo->GetUpgradeInsecureRequests() ? "true" : "false"));
    750    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    751            ("  initialSecurityChecksDone: %s\n",
    752             aLoadInfo->GetInitialSecurityCheckDone() ? "true" : "false"));
    753    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    754            ("  allowDeprecatedSystemRequests: %s\n",
    755             aLoadInfo->GetAllowDeprecatedSystemRequests() ? "true" : "false"));
    756    MOZ_LOG(sCSMLog, LogLevel::Verbose,
    757            ("  schemelessInput: %d\n", aLoadInfo->GetSchemelessInput()));
    758 
    759    // Log CSPrequestPrincipal
    760    nsCOMPtr<nsIPolicyContainer> policyContainer =
    761        aLoadInfo->GetPolicyContainer();
    762    nsCOMPtr<nsIContentSecurityPolicy> csp =
    763        PolicyContainer::GetCSP(policyContainer);
    764    MOZ_LOG(sCSMLog, LogLevel::Debug, ("  CSP:"));
    765    if (csp) {
    766      nsAutoString parsedPolicyStr;
    767      uint32_t count = 0;
    768      csp->GetPolicyCount(&count);
    769      for (uint32_t i = 0; i < count; ++i) {
    770        csp->GetPolicyString(i, parsedPolicyStr);
    771        // we need to add quotation marks, as otherwise yaml parsers may fail
    772        // with CSP directives
    773        // no need to escape quote marks in the parsed policy string, as URLs in
    774        // there are already encoded
    775        MOZ_LOG(sCSMLog, LogLevel::Debug,
    776                ("  - \"%s\"\n", NS_ConvertUTF16toUTF8(parsedPolicyStr).get()));
    777      }
    778    }
    779 
    780    // Security Flags
    781    MOZ_LOG(sCSMLog, LogLevel::Verbose, ("  securityFlags:"));
    782    LogSecurityFlags(aLoadInfo->GetSecurityFlags());
    783    // HTTPS-Only
    784    LogHTTPSOnlyInfo(aLoadInfo);
    785 
    786    MOZ_LOG(sCSMLog, LogLevel::Debug, ("\n#DebugDoContentSecurityCheck End\n"));
    787  }
    788 }
    789 
    790 /* static */
    791 void nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads(
    792    nsILoadInfo* aLoadInfo, nsIURI* aFinalURI, const nsACString& aRemoteType) {
    793  if (!StaticPrefs::dom_security_unexpected_system_load_telemetry_enabled()) {
    794    return;
    795  }
    796  nsContentSecurityUtils::DetectJsHacks();
    797  nsContentSecurityUtils::DetectCssHacks();
    798  // The detection only work on the main-thread.
    799  // To avoid races and early reports, we need to ensure the checks actually
    800  // happened.
    801  if (MOZ_UNLIKELY(sJSHacksPresent || !sJSHacksChecked || sCSSHacksPresent ||
    802                   !sCSSHacksChecked)) {
    803    return;
    804  }
    805 
    806  ExtContentPolicyType contentPolicyType =
    807      aLoadInfo->GetExternalContentPolicyType();
    808  // restricting reported types to script, styles and documents
    809  // to be continued in follow-ups of bug 1697163.
    810  if (contentPolicyType != ExtContentPolicyType::TYPE_SCRIPT &&
    811      contentPolicyType != ExtContentPolicyType::TYPE_STYLESHEET &&
    812      contentPolicyType != ExtContentPolicyType::TYPE_DOCUMENT) {
    813    return;
    814  }
    815 
    816  // Gather redirected schemes in string
    817  nsAutoCString loggedRedirects;
    818  const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>& redirects =
    819      aLoadInfo->RedirectChain();
    820  if (!redirects.IsEmpty()) {
    821    nsCOMPtr<nsIRedirectHistoryEntry> end = redirects.LastElement();
    822    for (nsIRedirectHistoryEntry* entry : redirects) {
    823      nsCOMPtr<nsIPrincipal> principal;
    824      entry->GetPrincipal(getter_AddRefs(principal));
    825      if (principal) {
    826        nsAutoCString scheme;
    827        principal->GetScheme(scheme);
    828        loggedRedirects.Append(scheme);
    829        if (entry != end) {
    830          loggedRedirects.AppendLiteral(", ");
    831        }
    832      }
    833    }
    834  }
    835 
    836  nsAutoCString uriString;
    837  if (aFinalURI) {
    838    aFinalURI->GetAsciiSpec(uriString);
    839  }
    840  FilenameTypeAndDetails fileNameTypeAndDetails =
    841      nsContentSecurityUtils::FilenameToFilenameType(uriString, true);
    842 
    843  nsCString loggedFileDetails = "unknown"_ns;
    844  if (fileNameTypeAndDetails.second.isSome()) {
    845    loggedFileDetails.Assign(fileNameTypeAndDetails.second.value());
    846  }
    847  // sanitize remoteType because it may contain sensitive
    848  // info, like URLs. e.g. `webIsolated=https://example.com`
    849  nsAutoCString loggedRemoteType(dom::RemoteTypePrefix(aRemoteType));
    850  nsAutoCString loggedContentType(NS_CP_ContentTypeName(contentPolicyType));
    851 
    852  MOZ_LOG(sUELLog, LogLevel::Debug, ("UnexpectedPrivilegedLoadTelemetry:\n"));
    853  MOZ_LOG(sUELLog, LogLevel::Debug,
    854          ("- contentType: %s\n", loggedContentType.get()));
    855  MOZ_LOG(sUELLog, LogLevel::Debug,
    856          ("- URL (not to be reported): %s\n", uriString.get()));
    857  MOZ_LOG(sUELLog, LogLevel::Debug,
    858          ("- remoteType: %s\n", loggedRemoteType.get()));
    859  MOZ_LOG(sUELLog, LogLevel::Debug,
    860          ("- fileInfo: %s\n", fileNameTypeAndDetails.first.get()));
    861  MOZ_LOG(sUELLog, LogLevel::Debug,
    862          ("- fileDetails: %s\n", loggedFileDetails.get()));
    863  MOZ_LOG(sUELLog, LogLevel::Debug,
    864          ("- redirects: %s\n\n", loggedRedirects.get()));
    865 
    866  glean::security::UnexpectedLoadExtra extra = {
    867      .contenttype = Some(loggedContentType),
    868      .filedetails = Some(loggedFileDetails),
    869      .redirects = Some(loggedRedirects),
    870      .remotetype = Some(loggedRemoteType),
    871      .value = Some(fileNameTypeAndDetails.first),
    872  };
    873  glean::security::unexpected_load.Record(Some(extra));
    874 }
    875 
    876 /* static */
    877 nsSecurityFlags nsContentSecurityManager::ComputeSecurityFlags(
    878    mozilla::CORSMode aCORSMode, CORSSecurityMapping aCORSSecurityMapping) {
    879  if (aCORSSecurityMapping == CORSSecurityMapping::DISABLE_CORS_CHECKS) {
    880    return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
    881  }
    882 
    883  switch (aCORSMode) {
    884    case CORS_NONE:
    885      if (aCORSSecurityMapping == CORSSecurityMapping::REQUIRE_CORS_CHECKS) {
    886        // CORS_NONE gets treated like CORS_ANONYMOUS in this mode
    887        return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
    888               nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
    889      } else if (aCORSSecurityMapping ==
    890                 CORSSecurityMapping::CORS_NONE_MAPS_TO_INHERITED_CONTEXT) {
    891        // CORS_NONE inherits
    892        return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
    893      } else {
    894        // CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS, the only remaining enum
    895        // variant. CORSSecurityMapping::DISABLE_CORS_CHECKS returned early.
    896        MOZ_ASSERT(aCORSSecurityMapping ==
    897                   CORSSecurityMapping::CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS);
    898        return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
    899      }
    900    case CORS_ANONYMOUS:
    901      return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
    902             nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
    903    case CORS_USE_CREDENTIALS:
    904      return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
    905             nsILoadInfo::SEC_COOKIES_INCLUDE;
    906      break;
    907    default:
    908      MOZ_ASSERT_UNREACHABLE("Invalid aCORSMode enum value");
    909      return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
    910             nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
    911  }
    912 }
    913 
    914 /* static */
    915 nsSecurityFlags nsContentSecurityManager::ComputeSecurityMode(
    916    nsSecurityFlags aSecurityFlags) {
    917  return aSecurityFlags &
    918         (nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT |
    919          nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED |
    920          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT |
    921          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL |
    922          nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT);
    923 }
    924 
    925 /* static */
    926 mozilla::dom::RequestMode nsContentSecurityManager::SecurityModeToRequestMode(
    927    uint32_t aSecurityMode) {
    928  if (aSecurityMode ==
    929          nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT ||
    930      aSecurityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED) {
    931    return mozilla::dom::RequestMode::Same_origin;
    932  }
    933 
    934  if (aSecurityMode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
    935    return mozilla::dom::RequestMode::Cors;
    936  }
    937 
    938  // If it's not one of the security modes above, then we ensure it's
    939  // at least one of the others defined in nsILoadInfo
    940  MOZ_ASSERT(aSecurityMode ==
    941                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT ||
    942                 aSecurityMode ==
    943                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    944             "unhandled security mode");
    945 
    946  return mozilla::dom::RequestMode::No_cors;
    947 }
    948 
    949 /* static */
    950 nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
    951    nsIChannel* aChannel) {
    952  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    953  nsCOMPtr<nsIPrincipal> inspectedPrincipal = loadInfo->GetLoadingPrincipal();
    954  if (!inspectedPrincipal) {
    955    return NS_OK;
    956  }
    957  // Check if we are actually dealing with a privileged request
    958  if (!inspectedPrincipal->IsSystemPrincipal()) {
    959    return NS_OK;
    960  }
    961  // loads with the allow flag are waived through
    962  // until refactored (e.g., Shavar, OCSP)
    963  if (loadInfo->GetAllowDeprecatedSystemRequests()) {
    964    return NS_OK;
    965  }
    966  ExtContentPolicyType contentPolicyType =
    967      loadInfo->GetExternalContentPolicyType();
    968  // For now, let's not inspect top-level document loads
    969  if (contentPolicyType == ExtContentPolicy::TYPE_DOCUMENT) {
    970    return NS_OK;
    971  }
    972 
    973  // allowing some fetches due to their lowered risk
    974  // i.e., data & downloads fetches do limited parsing, no rendering
    975  // remote images are too widely used (favicons, about:addons etc.)
    976  if ((contentPolicyType == ExtContentPolicy::TYPE_FETCH) ||
    977      (contentPolicyType == ExtContentPolicy::TYPE_XMLHTTPREQUEST) ||
    978      (contentPolicyType == ExtContentPolicy::TYPE_WEBSOCKET) ||
    979      (contentPolicyType == ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD) ||
    980      (contentPolicyType == ExtContentPolicy::TYPE_IMAGE)) {
    981    return NS_OK;
    982  }
    983 
    984  // Allow the user interface (e.g., schemes like chrome, resource)
    985  nsCOMPtr<nsIURI> finalURI;
    986  NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
    987  bool isUiResource = false;
    988  if (NS_SUCCEEDED(NS_URIChainHasFlags(
    989          finalURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isUiResource)) &&
    990      isUiResource) {
    991    return NS_OK;
    992  }
    993  // For about: and extension-based URIs, which don't get
    994  // URI_IS_UI_RESOURCE, first remove layers of view-source:, if present.
    995  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(finalURI);
    996 
    997  nsAutoCString remoteType;
    998  if (XRE_IsParentProcess()) {
    999    nsCOMPtr<nsIParentChannel> parentChannel;
   1000    NS_QueryNotificationCallbacks(aChannel, parentChannel);
   1001    if (parentChannel) {
   1002      parentChannel->GetRemoteType(remoteType);
   1003    }
   1004  } else {
   1005    remoteType.Assign(
   1006        mozilla::dom::ContentChild::GetSingleton()->GetRemoteType());
   1007  }
   1008 
   1009  // GetInnerURI can return null for malformed nested URIs like moz-icon:trash
   1010  if (!innerURI) {
   1011    MeasureUnexpectedPrivilegedLoads(loadInfo, innerURI, remoteType);
   1012    aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1013    return NS_ERROR_CONTENT_BLOCKED;
   1014  }
   1015  // loads of userContent.css during startup and tests that show up as file:
   1016  if (innerURI->SchemeIs("file")) {
   1017    if ((contentPolicyType == ExtContentPolicy::TYPE_STYLESHEET) ||
   1018        (contentPolicyType == ExtContentPolicy::TYPE_OTHER)) {
   1019      return NS_OK;
   1020    }
   1021  }
   1022  // (1) loads from within omni.ja and system add-ons use jar:
   1023  // this is safe to allow, because we do not support remote jar.
   1024  // (2) about: resources are always allowed: they are part of the build.
   1025  // (3) extensions are signed or the user has made bad decisions.
   1026  if (innerURI->SchemeIs("jar") || innerURI->SchemeIs("about") ||
   1027      innerURI->SchemeIs("moz-extension") ||
   1028      innerURI->SchemeIs("moz-safe-about")) {
   1029    return NS_OK;
   1030  }
   1031 
   1032  nsAutoCString requestedURL;
   1033  innerURI->GetAsciiSpec(requestedURL);
   1034  MOZ_LOG(sUELLog, LogLevel::Warning,
   1035          ("SystemPrincipal should not load remote resources. URL: %s, type %d",
   1036           requestedURL.get(), int(contentPolicyType)));
   1037 
   1038  // The load types that we want to disallow, will extend over time and
   1039  // prioritized by risk. The most risky/dangerous are load-types are documents,
   1040  // subdocuments, scripts and styles in that order. The most dangerous URL
   1041  // schemes to cover are HTTP, HTTPS, data, blob in that order. Meta bug
   1042  // 1725112 will track upcoming restrictions
   1043 
   1044  // Telemetry for unexpected privileged loads.
   1045  // pref check & data sanitization happens in the called function
   1046  MeasureUnexpectedPrivilegedLoads(loadInfo, innerURI, remoteType);
   1047 
   1048  // Relaxing restrictions for our test suites:
   1049  // (1) AreNonLocalConnectionsDisabled() disables network, so
   1050  // http://mochitest is actually local and allowed. (2) The marionette test
   1051  // framework uses injections and data URLs to execute scripts, checking for
   1052  // the environment variable breaks the attack but not the tests.
   1053  if (xpc::AreNonLocalConnectionsDisabled() ||
   1054      mozilla::EnvHasValue("MOZ_MARIONETTE")) {
   1055    bool disallowSystemPrincipalRemoteDocuments = Preferences::GetBool(
   1056        "security.disallow_non_local_systemprincipal_in_tests");
   1057    if (disallowSystemPrincipalRemoteDocuments) {
   1058      // our own mochitest needs NS_ASSERTION instead of MOZ_ASSERT
   1059      NS_ASSERTION(false, "SystemPrincipal must not load remote documents.");
   1060      aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1061      return NS_ERROR_CONTENT_BLOCKED;
   1062    }
   1063    // but other mochitest are exempt from this
   1064    return NS_OK;
   1065  }
   1066 
   1067  if (contentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
   1068    if (net::SchemeIsHttpOrHttps(innerURI)) {
   1069      MOZ_ASSERT(
   1070          false,
   1071          "Disallowing SystemPrincipal load of subdocuments on HTTP(S).");
   1072      aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1073      return NS_ERROR_CONTENT_BLOCKED;
   1074    }
   1075    if (innerURI->SchemeIs("data")) {
   1076      MOZ_ASSERT(
   1077          false,
   1078          "Disallowing SystemPrincipal load of subdocuments on data URL.");
   1079      aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1080      return NS_ERROR_CONTENT_BLOCKED;
   1081    }
   1082  }
   1083  if (contentPolicyType == ExtContentPolicy::TYPE_SCRIPT) {
   1084    if (net::SchemeIsHttpOrHttps(innerURI)) {
   1085      MOZ_ASSERT(false,
   1086                 "Disallowing SystemPrincipal load of scripts on HTTP(S).");
   1087      aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1088      return NS_ERROR_CONTENT_BLOCKED;
   1089    }
   1090  }
   1091  if (contentPolicyType == ExtContentPolicy::TYPE_STYLESHEET) {
   1092    if (net::SchemeIsHttpOrHttps(innerURI)) {
   1093      MOZ_ASSERT(false,
   1094                 "Disallowing SystemPrincipal load of stylesheets on HTTP(S).");
   1095      aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1096      return NS_ERROR_CONTENT_BLOCKED;
   1097    }
   1098  }
   1099  return NS_OK;
   1100 }
   1101 
   1102 /*
   1103 * Disallow about pages in the privilegedaboutcontext (e.g., password manager,
   1104 * newtab etc.) to load remote scripts. Regardless of whether this is coming
   1105 * from the contentprincipal or the systemprincipal.
   1106 */
   1107 /* static */
   1108 nsresult nsContentSecurityManager::CheckAllowLoadInPrivilegedAboutContext(
   1109    nsIChannel* aChannel) {
   1110  // If remote scripts aren't disallowed, then bail out.
   1111  if (!StaticPrefs::security_disallow_privilegedabout_remote_script_loads()) {
   1112    return NS_OK;
   1113  }
   1114 
   1115  nsAutoCString remoteType;
   1116  if (XRE_IsParentProcess()) {
   1117    nsCOMPtr<nsIParentChannel> parentChannel;
   1118    NS_QueryNotificationCallbacks(aChannel, parentChannel);
   1119    if (parentChannel) {
   1120      parentChannel->GetRemoteType(remoteType);
   1121    }
   1122  } else {
   1123    remoteType.Assign(
   1124        mozilla::dom::ContentChild::GetSingleton()->GetRemoteType());
   1125  }
   1126 
   1127  // only perform check for privileged about process
   1128  if (!remoteType.Equals(PRIVILEGEDABOUT_REMOTE_TYPE)) {
   1129    return NS_OK;
   1130  }
   1131 
   1132  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1133  ExtContentPolicyType contentPolicyType =
   1134      loadInfo->GetExternalContentPolicyType();
   1135  // only check for script loads
   1136  if (contentPolicyType != ExtContentPolicy::TYPE_SCRIPT) {
   1137    return NS_OK;
   1138  }
   1139 
   1140  nsCOMPtr<nsIURI> finalURI;
   1141  NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
   1142  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(finalURI);
   1143 
   1144  bool isLocal;
   1145  NS_URIChainHasFlags(innerURI, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
   1146                      &isLocal);
   1147  // We allow URLs that are URI_IS_LOCAL (but that includes `data`
   1148  // and `blob` which are also undesirable.
   1149  if (isLocal && !innerURI->SchemeIs("data") && !innerURI->SchemeIs("blob")) {
   1150    return NS_OK;
   1151  }
   1152  MOZ_ASSERT(
   1153      false,
   1154      "Disallowing privileged about process to load scripts on HTTP(S).");
   1155  aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1156  return NS_ERROR_CONTENT_BLOCKED;
   1157 }
   1158 
   1159 /*
   1160 * Every protocol handler must set one of the six security flags
   1161 * defined in nsIProtocolHandler - if not - deny the load.
   1162 */
   1163 nsresult nsContentSecurityManager::CheckChannelHasProtocolSecurityFlag(
   1164    nsIChannel* aChannel) {
   1165  nsCOMPtr<nsIURI> uri;
   1166  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   1167  NS_ENSURE_SUCCESS(rv, rv);
   1168 
   1169  nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
   1170  NS_ENSURE_SUCCESS(rv, rv);
   1171 
   1172  uint32_t flags;
   1173  rv = ios->GetDynamicProtocolFlags(uri, &flags);
   1174  NS_ENSURE_SUCCESS(rv, rv);
   1175 
   1176  uint32_t securityFlagsSet = 0;
   1177  if (flags & nsIProtocolHandler::URI_IS_WEBEXTENSION_RESOURCE) {
   1178    securityFlagsSet += 1;
   1179  }
   1180  if (flags & nsIProtocolHandler::URI_LOADABLE_BY_ANYONE) {
   1181    securityFlagsSet += 1;
   1182  }
   1183  if (flags & nsIProtocolHandler::URI_DANGEROUS_TO_LOAD) {
   1184    securityFlagsSet += 1;
   1185  }
   1186  if (flags & nsIProtocolHandler::URI_IS_UI_RESOURCE) {
   1187    securityFlagsSet += 1;
   1188  }
   1189  if (flags & nsIProtocolHandler::URI_IS_LOCAL_FILE) {
   1190    securityFlagsSet += 1;
   1191  }
   1192  if (flags & nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS) {
   1193    securityFlagsSet += 1;
   1194  }
   1195 
   1196  // Ensure that only "1" valid security flags is set.
   1197  if (securityFlagsSet == 1) {
   1198    return NS_OK;
   1199  }
   1200 
   1201  MOZ_ASSERT(false, "protocol must use one valid security flag");
   1202  return NS_ERROR_CONTENT_BLOCKED;
   1203 }
   1204 
   1205 // We should not allow loading non-JavaScript files as scripts using
   1206 // a file:// URL.
   1207 static nsresult CheckAllowFileProtocolScriptLoad(nsIChannel* aChannel) {
   1208  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1209  ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType();
   1210 
   1211  // Only check script loads.
   1212  if (type != ExtContentPolicy::TYPE_SCRIPT) {
   1213    return NS_OK;
   1214  }
   1215 
   1216  if (!StaticPrefs::security_block_fileuri_script_with_wrong_mime()) {
   1217    return NS_OK;
   1218  }
   1219 
   1220  nsCOMPtr<nsIURI> uri;
   1221  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   1222  NS_ENSURE_SUCCESS(rv, rv);
   1223  if (!uri || !uri->SchemeIs("file")) {
   1224    return NS_OK;
   1225  }
   1226 
   1227  nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
   1228  NS_ENSURE_SUCCESS(rv, rv);
   1229 
   1230  // GetTypeFromURI fails for missing or unknown file-extensions.
   1231  nsAutoCString contentType;
   1232  rv = mime->GetTypeFromURI(uri, contentType);
   1233  if (NS_FAILED(rv) || !nsContentUtils::IsJavascriptMIMEType(
   1234                           NS_ConvertUTF8toUTF16(contentType))) {
   1235    nsCOMPtr<Document> doc;
   1236    if (nsINode* node = loadInfo->LoadingNode()) {
   1237      doc = node->OwnerDoc();
   1238    }
   1239 
   1240    nsAutoCString spec;
   1241    uri->GetSpec(spec);
   1242 
   1243    AutoTArray<nsString, 1> params;
   1244    CopyUTF8toUTF16(NS_UnescapeURL(spec), *params.AppendElement());
   1245    CopyUTF8toUTF16(NS_UnescapeURL(contentType), *params.AppendElement());
   1246 
   1247    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   1248                                    "FILE_SCRIPT_BLOCKED"_ns, doc,
   1249                                    nsContentUtils::eSECURITY_PROPERTIES,
   1250                                    "BlockFileScriptWithWrongMimeType", params);
   1251 
   1252    return NS_ERROR_CONTENT_BLOCKED;
   1253  }
   1254 
   1255  return NS_OK;
   1256 }
   1257 
   1258 // We should not allow loading non-JavaScript files as scripts using
   1259 // a moz-extension:// URL.
   1260 static nsresult CheckAllowExtensionProtocolScriptLoad(nsIChannel* aChannel) {
   1261  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1262  ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType();
   1263 
   1264  // Only check script loads.
   1265  if (type != ExtContentPolicy::TYPE_SCRIPT) {
   1266    return NS_OK;
   1267  }
   1268 
   1269  nsCOMPtr<nsIURI> uri;
   1270  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   1271  NS_ENSURE_SUCCESS(rv, rv);
   1272  if (!uri || !uri->SchemeIs("moz-extension")) {
   1273    return NS_OK;
   1274  }
   1275 
   1276  // We expect this code to never be hit off-the-main-thread (even worker
   1277  // scripts are currently hitting only on the main thread, see
   1278  // WorkerScriptLoader::DispatchLoadScript calling NS_DispatchToMainThread
   1279  // internally), this diagnostic assertion is meant to let us notice if that
   1280  // isn't the case anymore.
   1281  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
   1282                        "Unexpected off-the-main-thread call to "
   1283                        "CheckAllowFileProtocolScriptLoad");
   1284 
   1285  nsAutoCString host;
   1286  rv = uri->GetHost(host);
   1287  NS_ENSURE_SUCCESS(rv, rv);
   1288 
   1289  RefPtr<extensions::WebExtensionPolicyCore> targetPolicy =
   1290      ExtensionPolicyService::GetCoreByHost(host);
   1291 
   1292  if (NS_WARN_IF(!targetPolicy) || targetPolicy->ManifestVersion() < 3) {
   1293    return NS_OK;
   1294  }
   1295 
   1296  nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
   1297  NS_ENSURE_SUCCESS(rv, rv);
   1298 
   1299  // GetDefaultTypeFromExtension fails for missing or unknown file-extensions.
   1300  nsAutoCString contentType;
   1301  rv = mime->GetDefaultTypeFromURI(uri, contentType);
   1302  if (NS_FAILED(rv) || !nsContentUtils::IsJavascriptMIMEType(
   1303                           NS_ConvertUTF8toUTF16(contentType))) {
   1304    nsCOMPtr<Document> doc;
   1305    if (nsINode* node = loadInfo->LoadingNode()) {
   1306      doc = node->OwnerDoc();
   1307    }
   1308 
   1309    nsAutoCString spec;
   1310    uri->GetSpec(spec);
   1311 
   1312    AutoTArray<nsString, 1> params;
   1313    CopyUTF8toUTF16(NS_UnescapeURL(spec), *params.AppendElement());
   1314 
   1315    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   1316                                    "EXTENSION_SCRIPT_BLOCKED"_ns, doc,
   1317                                    nsContentUtils::eSECURITY_PROPERTIES,
   1318                                    "BlockExtensionScriptWithWrongExt", params);
   1319 
   1320    return NS_ERROR_CONTENT_BLOCKED;
   1321  }
   1322 
   1323  return NS_OK;
   1324 }
   1325 
   1326 // Validate that a load should be allowed based on its remote type. This
   1327 // intentionally prevents some loads from occuring even using the system
   1328 // principal, if they were started in a content process.
   1329 static nsresult CheckAllowLoadByTriggeringRemoteType(nsIChannel* aChannel) {
   1330  MOZ_ASSERT(aChannel);
   1331 
   1332  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1333 
   1334  // For now, only restrict loads for documents. We currently have no
   1335  // interesting subresource checks for protocols which are are not fully
   1336  // handled within the content process.
   1337  ExtContentPolicy contentPolicyType = loadInfo->GetExternalContentPolicyType();
   1338  if (contentPolicyType != ExtContentPolicy::TYPE_DOCUMENT &&
   1339      contentPolicyType != ExtContentPolicy::TYPE_SUBDOCUMENT &&
   1340      contentPolicyType != ExtContentPolicy::TYPE_OBJECT) {
   1341    return NS_OK;
   1342  }
   1343 
   1344  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
   1345                        "Unexpected off-the-main-thread call to "
   1346                        "CheckAllowLoadByTriggeringRemoteType");
   1347 
   1348  // Due to the way that session history is handled without SHIP, we cannot run
   1349  // these checks when SHIP is disabled.
   1350  if (!mozilla::SessionHistoryInParent()) {
   1351    return NS_OK;
   1352  }
   1353 
   1354  nsAutoCString triggeringRemoteType;
   1355  nsresult rv = loadInfo->GetTriggeringRemoteType(triggeringRemoteType);
   1356  NS_ENSURE_SUCCESS(rv, rv);
   1357 
   1358  // For now, only restrict loads coming from web remote types. In the future we
   1359  // may want to expand this a bit.
   1360  if (!StringBeginsWith(triggeringRemoteType, WEB_REMOTE_TYPE)) {
   1361    return NS_OK;
   1362  }
   1363 
   1364  nsCOMPtr<nsIURI> finalURI;
   1365  rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
   1366  NS_ENSURE_SUCCESS(rv, rv);
   1367 
   1368  // Don't allow web content processes to load non-remote about pages.
   1369  // NOTE: URIs with a `moz-safe-about:` inner scheme are safe to link to, so
   1370  // it's OK we miss them here.
   1371  nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(finalURI);
   1372  if (innermostURI->SchemeIs("about")) {
   1373    nsCOMPtr<nsIAboutModule> aboutModule;
   1374    rv = NS_GetAboutModule(innermostURI, getter_AddRefs(aboutModule));
   1375    NS_ENSURE_SUCCESS(rv, rv);
   1376 
   1377    uint32_t aboutModuleFlags = 0;
   1378    rv = aboutModule->GetURIFlags(innermostURI, &aboutModuleFlags);
   1379    NS_ENSURE_SUCCESS(rv, rv);
   1380 
   1381    if (!(aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) &&
   1382        !(aboutModuleFlags & nsIAboutModule::URI_CAN_LOAD_IN_CHILD) &&
   1383        !(aboutModuleFlags & nsIAboutModule::URI_MUST_LOAD_IN_CHILD)) {
   1384      NS_WARNING(nsPrintfCString("Blocking load of about URI (%s) which cannot "
   1385                                 "be linked to in web content process",
   1386                                 finalURI->GetSpecOrDefault().get())
   1387                     .get());
   1388 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   1389      if (NS_SUCCEEDED(
   1390              loadInfo->TriggeringPrincipal()->CheckMayLoad(finalURI, true))) {
   1391        nsAutoCString aboutModuleName;
   1392        MOZ_ALWAYS_SUCCEEDS(
   1393            NS_GetAboutModuleName(innermostURI, aboutModuleName));
   1394        MOZ_CRASH_UNSAFE_PRINTF(
   1395            "Blocking load of about uri by content process which may have "
   1396            "otherwise succeeded [aboutModule=%s, isSystemPrincipal=%d]",
   1397            aboutModuleName.get(),
   1398            loadInfo->TriggeringPrincipal()->IsSystemPrincipal());
   1399      }
   1400 #endif
   1401      return NS_ERROR_CONTENT_BLOCKED;
   1402    }
   1403    return NS_OK;
   1404  }
   1405 
   1406  // Don't allow web content processes to load file documents. Loads of file
   1407  // URIs as subresources will be handled by the sandbox, and may be allowed in
   1408  // some cases.
   1409  bool localFile = false;
   1410  rv = NS_URIChainHasFlags(finalURI, nsIProtocolHandler::URI_IS_LOCAL_FILE,
   1411                           &localFile);
   1412  NS_ENSURE_SUCCESS(rv, rv);
   1413  if (localFile) {
   1414    NS_WARNING(
   1415        nsPrintfCString(
   1416            "Blocking document load of file URI (%s) from web content process",
   1417            innermostURI->GetSpecOrDefault().get())
   1418            .get());
   1419 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   1420    if (NS_SUCCEEDED(
   1421            loadInfo->TriggeringPrincipal()->CheckMayLoad(finalURI, true))) {
   1422      MOZ_CRASH_UNSAFE_PRINTF(
   1423          "Blocking document load of file URI by content process which may "
   1424          "have otherwise succeeded [isSystemPrincipal=%d]",
   1425          loadInfo->TriggeringPrincipal()->IsSystemPrincipal());
   1426    }
   1427 #endif
   1428    return NS_ERROR_CONTENT_BLOCKED;
   1429  }
   1430 
   1431  return NS_OK;
   1432 }
   1433 
   1434 /*
   1435 * Based on the security flags provided in the loadInfo of the channel,
   1436 * doContentSecurityCheck() performs the following content security checks
   1437 * before opening the channel:
   1438 *
   1439 * (1) Same Origin Policy Check (if applicable)
   1440 * (2) Allow Cross Origin but perform sanity checks whether a principal
   1441 *     is allowed to access the following URL.
   1442 * (3) Perform CORS check (if applicable)
   1443 * (4) ContentPolicy checks (Content-Security-Policy, Mixed Content, ...)
   1444 *
   1445 * @param aChannel
   1446 *    The channel to perform the security checks on.
   1447 * @param aInAndOutListener
   1448 *    The streamListener that is passed to channel->AsyncOpen() that is now
   1449 * potentially wrappend within nsCORSListenerProxy() and becomes the
   1450 * corsListener that now needs to be set as new streamListener on the channel.
   1451 */
   1452 nsresult nsContentSecurityManager::doContentSecurityCheck(
   1453    nsIChannel* aChannel, nsCOMPtr<nsIStreamListener>& aInAndOutListener) {
   1454  NS_ENSURE_ARG(aChannel);
   1455  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1456  if (MOZ_UNLIKELY(MOZ_LOG_TEST(sCSMLog, LogLevel::Verbose))) {
   1457    DebugDoContentSecurityCheck(aChannel, loadInfo);
   1458  }
   1459 
   1460  nsresult rv = CheckAllowLoadInSystemPrivilegedContext(aChannel);
   1461  NS_ENSURE_SUCCESS(rv, rv);
   1462 
   1463  rv = CheckAllowLoadInPrivilegedAboutContext(aChannel);
   1464  NS_ENSURE_SUCCESS(rv, rv);
   1465 
   1466  // We want to also check redirected requests to ensure
   1467  // the target maintains the proper javascript file extensions.
   1468  rv = CheckAllowExtensionProtocolScriptLoad(aChannel);
   1469  NS_ENSURE_SUCCESS(rv, rv);
   1470 
   1471  rv = CheckChannelHasProtocolSecurityFlag(aChannel);
   1472  NS_ENSURE_SUCCESS(rv, rv);
   1473 
   1474  rv = CheckAllowLoadByTriggeringRemoteType(aChannel);
   1475  NS_ENSURE_SUCCESS(rv, rv);
   1476 
   1477  rv = CheckForIncoherentResultPrincipal(aChannel);
   1478  NS_ENSURE_SUCCESS(rv, rv);
   1479 
   1480  // if dealing with a redirected channel then we have already installed
   1481  // streamlistener and redirect proxies and so we are done.
   1482  if (loadInfo->GetInitialSecurityCheckDone()) {
   1483    return NS_OK;
   1484  }
   1485 
   1486  // make sure that only one of the five security flags is set in the loadinfo
   1487  // e.g. do not require same origin and allow cross origin at the same time
   1488  rv = ValidateSecurityFlags(loadInfo);
   1489  NS_ENSURE_SUCCESS(rv, rv);
   1490 
   1491  if (loadInfo->GetSecurityMode() ==
   1492      nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
   1493    rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener);
   1494    NS_ENSURE_SUCCESS(rv, rv);
   1495  }
   1496 
   1497  rv = CheckChannel(aChannel);
   1498  NS_ENSURE_SUCCESS(rv, rv);
   1499 
   1500  // Perform all ContentPolicy checks (MixedContent, CSP, ...)
   1501  rv = DoContentSecurityChecks(aChannel, loadInfo);
   1502  NS_ENSURE_SUCCESS(rv, rv);
   1503 
   1504  rv = CheckAllowFileProtocolScriptLoad(aChannel);
   1505  NS_ENSURE_SUCCESS(rv, rv);
   1506 
   1507  // now lets set the initialSecurityFlag for subsequent calls
   1508  loadInfo->SetInitialSecurityCheckDone(true);
   1509 
   1510  // all security checks passed - lets allow the load
   1511  return NS_OK;
   1512 }
   1513 
   1514 NS_IMETHODIMP
   1515 nsContentSecurityManager::AsyncOnChannelRedirect(
   1516    nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirFlags,
   1517    nsIAsyncVerifyRedirectCallback* aCb) {
   1518  // Since we compare the principal from the loadInfo to the URI's
   1519  // princicpal, it's possible that the checks fail when doing an internal
   1520  // redirect. We can just return early instead, since we should never
   1521  // need to block an internal redirect.
   1522  if (aRedirFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
   1523    aCb->OnRedirectVerifyCallback(NS_OK);
   1524    return NS_OK;
   1525  }
   1526 
   1527  nsCOMPtr<nsILoadInfo> loadInfo = aOldChannel->LoadInfo();
   1528  nsresult rv = CheckChannel(aNewChannel);
   1529  if (NS_FAILED(rv)) {
   1530    aOldChannel->Cancel(rv);
   1531    return rv;
   1532  }
   1533 
   1534  // Also verify that the redirecting server is allowed to redirect to the
   1535  // given URI
   1536  nsCOMPtr<nsIPrincipal> oldPrincipal;
   1537  nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
   1538      aOldChannel, getter_AddRefs(oldPrincipal));
   1539 
   1540  nsCOMPtr<nsIURI> newURI;
   1541  (void)NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
   1542  NS_ENSURE_STATE(oldPrincipal && newURI);
   1543 
   1544  // Do not allow insecure redirects to data: URIs
   1545  if (!AllowInsecureRedirectToDataURI(aNewChannel)) {
   1546    // cancel the old channel and return an error
   1547    aOldChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
   1548    return NS_ERROR_CONTENT_BLOCKED;
   1549  }
   1550 
   1551  const uint32_t flags =
   1552      nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
   1553      nsIScriptSecurityManager::DISALLOW_SCRIPT;
   1554  rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
   1555      oldPrincipal, newURI, flags, loadInfo->GetInnerWindowID());
   1556  NS_ENSURE_SUCCESS(rv, rv);
   1557 
   1558  aCb->OnRedirectVerifyCallback(NS_OK);
   1559  return NS_OK;
   1560 }
   1561 
   1562 static void AddLoadFlags(nsIRequest* aRequest, nsLoadFlags aNewFlags) {
   1563  nsLoadFlags flags;
   1564  aRequest->GetLoadFlags(&flags);
   1565  flags |= aNewFlags;
   1566  aRequest->SetLoadFlags(flags);
   1567 }
   1568 
   1569 /*
   1570 * Check that this channel passes all security checks. Returns an error code
   1571 * if this requesst should not be permitted.
   1572 */
   1573 nsresult nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) {
   1574  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1575  nsCOMPtr<nsIURI> uri;
   1576  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   1577  NS_ENSURE_SUCCESS(rv, rv);
   1578 
   1579  // Handle cookie policies
   1580  uint32_t cookiePolicy = loadInfo->GetCookiePolicy();
   1581  if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
   1582    // We shouldn't have the SEC_COOKIES_SAME_ORIGIN flag for top level loads
   1583    MOZ_ASSERT(loadInfo->GetExternalContentPolicyType() !=
   1584               ExtContentPolicy::TYPE_DOCUMENT);
   1585    nsIPrincipal* loadingPrincipal = loadInfo->GetLoadingPrincipal();
   1586 
   1587    // It doesn't matter what we pass for the second, data-inherits, argument.
   1588    // Any protocol which inherits won't pay attention to cookies anyway.
   1589    rv = loadingPrincipal->CheckMayLoad(uri, false);
   1590    if (NS_FAILED(rv)) {
   1591      AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
   1592    }
   1593  } else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_OMIT) {
   1594    AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
   1595  }
   1596 
   1597  if (!CrossOriginEmbedderPolicyAllowsCredentials(aChannel)) {
   1598    AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
   1599  }
   1600 
   1601  nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
   1602 
   1603  // CORS mode is handled by nsCORSListenerProxy
   1604  if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
   1605    if (NS_HasBeenCrossOrigin(aChannel)) {
   1606      loadInfo->MaybeIncreaseTainting(LoadTainting::CORS);
   1607    }
   1608    return NS_OK;
   1609  }
   1610 
   1611  // Allow subresource loads if TriggeringPrincipal is the SystemPrincipal.
   1612  if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
   1613      loadInfo->GetExternalContentPolicyType() !=
   1614          ExtContentPolicy::TYPE_DOCUMENT &&
   1615      loadInfo->GetExternalContentPolicyType() !=
   1616          ExtContentPolicy::TYPE_SUBDOCUMENT) {
   1617    return NS_OK;
   1618  }
   1619 
   1620  // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
   1621  if ((securityMode ==
   1622       nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT) ||
   1623      (securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) {
   1624    rv = DoSOPChecks(uri, loadInfo, aChannel);
   1625    NS_ENSURE_SUCCESS(rv, rv);
   1626  }
   1627 
   1628  if ((securityMode ==
   1629       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT) ||
   1630      (securityMode ==
   1631       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL)) {
   1632    if (NS_HasBeenCrossOrigin(aChannel)) {
   1633      NS_ENSURE_FALSE(loadInfo->GetDontFollowRedirects(), NS_ERROR_DOM_BAD_URI);
   1634      loadInfo->MaybeIncreaseTainting(LoadTainting::Opaque);
   1635    }
   1636    // Please note that DoCheckLoadURIChecks should only be enforced for
   1637    // cross origin requests. If the flag SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
   1638    // is set within the loadInfo, then CheckLoadURIWithPrincipal is performed
   1639    // within nsCorsListenerProxy
   1640    rv = DoCheckLoadURIChecks(uri, loadInfo);
   1641    NS_ENSURE_SUCCESS(rv, rv);
   1642    // TODO: Bug 1371237
   1643    // consider calling SetBlockedRequest in
   1644    // nsContentSecurityManager::CheckChannel
   1645  }
   1646 
   1647  return NS_OK;
   1648 }
   1649 
   1650 // https://fetch.spec.whatwg.org/#ref-for-cross-origin-embedder-policy-allows-credentials
   1651 bool nsContentSecurityManager::CrossOriginEmbedderPolicyAllowsCredentials(
   1652    nsIChannel* aChannel) {
   1653  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1654 
   1655  // 1. If request’s mode is not "no-cors", then return true.
   1656  //
   1657  // `no-cors` check applies to document navigation such that if it is
   1658  // an document navigation, this check should return true to allow
   1659  // credentials.
   1660  if (loadInfo->GetExternalContentPolicyType() ==
   1661          ExtContentPolicy::TYPE_DOCUMENT ||
   1662      loadInfo->GetExternalContentPolicyType() ==
   1663          ExtContentPolicy::TYPE_SUBDOCUMENT ||
   1664      loadInfo->GetExternalContentPolicyType() ==
   1665          ExtContentPolicy::TYPE_WEBSOCKET) {
   1666    return true;
   1667  }
   1668 
   1669  if (loadInfo->GetSecurityMode() !=
   1670          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
   1671      loadInfo->GetSecurityMode() !=
   1672          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT) {
   1673    return true;
   1674  }
   1675 
   1676  // If request’s client’s policy container’s embedder policy’s value is not
   1677  // "credentialless", then return true.
   1678  if (loadInfo->GetLoadingEmbedderPolicy() !=
   1679      nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS) {
   1680    return true;
   1681  }
   1682 
   1683  // If request’s origin is same origin with request’s current URL’s origin and
   1684  // request does not have a redirect-tainted origin, then return true.
   1685  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   1686  nsCOMPtr<nsIPrincipal> resourcePrincipal;
   1687  ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(resourcePrincipal));
   1688 
   1689  bool sameOrigin = resourcePrincipal->Equals(loadInfo->TriggeringPrincipal());
   1690  nsAutoCString serializedOrigin;
   1691  GetSerializedOrigin(loadInfo->TriggeringPrincipal(), resourcePrincipal,
   1692                      serializedOrigin, loadInfo);
   1693  if (sameOrigin && !serializedOrigin.IsEmpty()) {
   1694    return true;
   1695  }
   1696 
   1697  return false;
   1698 }
   1699 
   1700 // https://fetch.spec.whatwg.org/#serializing-a-request-origin
   1701 void nsContentSecurityManager::GetSerializedOrigin(
   1702    nsIPrincipal* aOrigin, nsIPrincipal* aResourceOrigin,
   1703    nsACString& aSerializedOrigin, nsILoadInfo* aLoadInfo) {
   1704  // The following for loop performs the
   1705  // https://fetch.spec.whatwg.org/#ref-for-concept-request-tainted-origin
   1706  nsCOMPtr<nsIPrincipal> lastOrigin;
   1707  for (nsIRedirectHistoryEntry* entry : aLoadInfo->RedirectChain()) {
   1708    if (!lastOrigin) {
   1709      entry->GetPrincipal(getter_AddRefs(lastOrigin));
   1710      continue;
   1711    }
   1712 
   1713    nsCOMPtr<nsIPrincipal> currentOrigin;
   1714    entry->GetPrincipal(getter_AddRefs(currentOrigin));
   1715 
   1716    if (!currentOrigin->Equals(lastOrigin) && !lastOrigin->Equals(aOrigin)) {
   1717      aSerializedOrigin.AssignLiteral("null");
   1718      return;
   1719    }
   1720    lastOrigin = currentOrigin;
   1721  }
   1722 
   1723  // When the redirectChain is empty, it means this is the first redirect.
   1724  // So according to the #serializing-a-request-origin spec, we don't
   1725  // have a redirect-tainted origin, so we return the origin of the request
   1726  // here.
   1727  if (!lastOrigin) {
   1728    aOrigin->GetWebExposedOriginSerialization(aSerializedOrigin);
   1729    return;
   1730  }
   1731 
   1732  // Same as above, redirectChain doesn't contain the current redirect,
   1733  // so we have to do the check one last time here.
   1734  if (!lastOrigin->Equals(aResourceOrigin) && !lastOrigin->Equals(aOrigin)) {
   1735    aSerializedOrigin.AssignLiteral("null");
   1736    return;
   1737  }
   1738 
   1739  aOrigin->GetWebExposedOriginSerialization(aSerializedOrigin);
   1740 }
   1741 
   1742 // https://html.spec.whatwg.org/multipage/browsers.html#compatible-with-cross-origin-isolation
   1743 bool nsContentSecurityManager::IsCompatibleWithCrossOriginIsolation(
   1744    nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) {
   1745  return aPolicy == nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS ||
   1746         aPolicy == nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP;
   1747 }
   1748 
   1749 // ==== nsIContentSecurityManager implementation =====
   1750 
   1751 NS_IMETHODIMP
   1752 nsContentSecurityManager::PerformSecurityCheck(
   1753    nsIChannel* aChannel, nsIStreamListener* aStreamListener,
   1754    nsIStreamListener** outStreamListener) {
   1755  nsCOMPtr<nsIStreamListener> inAndOutListener = aStreamListener;
   1756  nsresult rv = doContentSecurityCheck(aChannel, inAndOutListener);
   1757  NS_ENSURE_SUCCESS(rv, rv);
   1758 
   1759  inAndOutListener.forget(outStreamListener);
   1760  return NS_OK;
   1761 }
   1762 
   1763 nsresult nsContentSecurityManager::CheckForIncoherentResultPrincipal(
   1764    nsIChannel* aChannel) {
   1765  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1766  ExtContentPolicyType contentPolicyType =
   1767      loadInfo->GetExternalContentPolicyType();
   1768  if (contentPolicyType != ExtContentPolicyType::TYPE_DOCUMENT &&
   1769      contentPolicyType != ExtContentPolicyType::TYPE_SUBDOCUMENT &&
   1770      contentPolicyType != ExtContentPolicyType::TYPE_OBJECT) {
   1771    return NS_OK;
   1772  }
   1773 
   1774  nsCOMPtr<nsIPrincipal> resultOrPrecursor;
   1775  nsresult rv = nsScriptSecurityManager::GetScriptSecurityManager()
   1776                    ->GetChannelResultPrincipalIfNotSandboxed(
   1777                        aChannel, getter_AddRefs(resultOrPrecursor));
   1778  NS_ENSURE_SUCCESS(rv, rv);
   1779  NS_ENSURE_STATE(resultOrPrecursor);
   1780 
   1781  if (nsCOMPtr<nsIPrincipal> precursor =
   1782          resultOrPrecursor->GetPrecursorPrincipal()) {
   1783    resultOrPrecursor = precursor;
   1784  }
   1785 
   1786  if (!resultOrPrecursor->GetIsContentPrincipal()) {
   1787    return NS_OK;
   1788  }
   1789 
   1790  nsAutoCString resultSiteOriginNoSuffix;
   1791  rv = resultOrPrecursor->GetSiteOriginNoSuffix(resultSiteOriginNoSuffix);
   1792  NS_ENSURE_SUCCESS(rv, rv);
   1793 
   1794  nsCOMPtr<nsIURI> resultSiteOriginURI;
   1795  NS_NewURI(getter_AddRefs(resultSiteOriginURI), resultSiteOriginNoSuffix);
   1796  NS_ENSURE_STATE(resultSiteOriginURI);
   1797 
   1798  nsCOMPtr<nsIURI> channelURI;
   1799  aChannel->GetURI(getter_AddRefs(channelURI));
   1800  NS_ENSURE_STATE(channelURI);
   1801 
   1802  nsCOMPtr<nsIPrincipal> channelUriPrincipal =
   1803      BasePrincipal::CreateContentPrincipal(channelURI, {});
   1804  NS_ENSURE_STATE(channelUriPrincipal);
   1805 
   1806  nsAutoCString channelUriSiteOrigin;
   1807  rv = channelUriPrincipal->GetSiteOriginNoSuffix(channelUriSiteOrigin);
   1808  NS_ENSURE_SUCCESS(rv, rv);
   1809 
   1810  nsCOMPtr<nsIURI> channelSiteOriginURI;
   1811  NS_NewURI(getter_AddRefs(channelSiteOriginURI), channelUriSiteOrigin);
   1812  NS_ENSURE_STATE(channelSiteOriginURI);
   1813 
   1814  if (nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(
   1815          resultSiteOriginURI, channelSiteOriginURI) ||
   1816      (!net::SchemeIsHttpOrHttps(resultSiteOriginURI) &&
   1817       net::SchemeIsHttpOrHttps(channelSiteOriginURI))) {
   1818    return NS_ERROR_CONTENT_BLOCKED;
   1819  }
   1820 
   1821  return NS_OK;
   1822 }