tor-browser

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

nsScriptSecurityManager.cpp (67710B)


      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 "nsScriptSecurityManager.h"
      8 
      9 #include "mozilla/SourceLocation.h"
     10 #include "mozilla/StaticPrefs_extensions.h"
     11 #include "mozilla/StaticPrefs_security.h"
     12 #include "mozilla/StoragePrincipalHelper.h"
     13 
     14 #include "xpcpublic.h"
     15 #include "XPCWrapper.h"
     16 #include "nsILoadContext.h"
     17 #include "nsIScriptObjectPrincipal.h"
     18 #include "nsIScriptContext.h"
     19 #include "nsIScriptError.h"
     20 #include "nsINestedURI.h"
     21 #include "nspr.h"
     22 #include "nsJSPrincipals.h"
     23 #include "mozilla/BasePrincipal.h"
     24 #include "mozilla/ContentPrincipal.h"
     25 #include "ExpandedPrincipal.h"
     26 #include "SystemPrincipal.h"
     27 #include "DomainPolicy.h"
     28 #include "nsString.h"
     29 #include "nsCRT.h"
     30 #include "nsCRTGlue.h"
     31 #include "nsContentSecurityUtils.h"
     32 #include "nsDocShell.h"
     33 #include "nsError.h"
     34 #include "nsGlobalWindowInner.h"
     35 #include "nsDOMCID.h"
     36 #include "nsTextFormatter.h"
     37 #include "nsIStringBundle.h"
     38 #include "nsNetUtil.h"
     39 #include "nsIEffectiveTLDService.h"
     40 #include "nsDirectoryServiceDefs.h"
     41 #include "nsIScriptGlobalObject.h"
     42 #include "nsPIDOMWindow.h"
     43 #include "nsIDocShell.h"
     44 #include "nsIConsoleService.h"
     45 #include "nsIOService.h"
     46 #include "nsIContent.h"
     47 #include "nsDOMJSUtils.h"
     48 #include "nsAboutProtocolUtils.h"
     49 #include "nsIClassInfo.h"
     50 #include "nsIURIFixup.h"
     51 #include "nsIURIMutator.h"
     52 #include "nsIChromeRegistry.h"
     53 #include "nsIResProtocolHandler.h"
     54 #include "nsIContentSecurityPolicy.h"
     55 #include "mozilla/Components.h"
     56 #include "mozilla/Preferences.h"
     57 #include "mozilla/dom/BindingUtils.h"
     58 #include "mozilla/NullPrincipal.h"
     59 #include <stdint.h>
     60 #include "mozilla/dom/ContentChild.h"
     61 #include "mozilla/dom/ContentParent.h"
     62 #include "mozilla/dom/Exceptions.h"
     63 #include "mozilla/dom/nsCSPContext.h"
     64 #include "mozilla/dom/PolicyContainer.h"
     65 #include "mozilla/dom/ScriptSettings.h"
     66 #include "mozilla/ClearOnShutdown.h"
     67 #include "mozilla/ExtensionPolicyService.h"
     68 #include "mozilla/StaticPtr.h"
     69 #include "mozilla/dom/TrustedTypeUtils.h"
     70 #include "mozilla/dom/WorkerCommon.h"
     71 #include "mozilla/dom/WorkerPrivate.h"
     72 #include "nsContentUtils.h"
     73 #include "nsJSUtils.h"
     74 #include "nsILoadInfo.h"
     75 #include "js/ColumnNumber.h"  // JS::ColumnNumberOneOrigin
     76 #include "js/GCVector.h"
     77 #include "js/Value.h"
     78 
     79 // This should be probably defined on some other place... but I couldn't find it
     80 #define WEBAPPS_PERM_NAME "webapps-manage"
     81 
     82 using namespace mozilla;
     83 using namespace mozilla::dom;
     84 
     85 StaticRefPtr<nsIIOService> nsScriptSecurityManager::sIOService;
     86 std::atomic<bool> nsScriptSecurityManager::sStrictFileOriginPolicy = true;
     87 
     88 namespace {
     89 
     90 class BundleHelper {
     91 public:
     92  NS_INLINE_DECL_REFCOUNTING(BundleHelper)
     93 
     94  static nsIStringBundle* GetOrCreate() {
     95    MOZ_ASSERT(!sShutdown);
     96 
     97    // Already shutting down. Nothing should require the use of the string
     98    // bundle when shutting down.
     99    if (sShutdown) {
    100      return nullptr;
    101    }
    102 
    103    if (!sSelf) {
    104      sSelf = new BundleHelper();
    105    }
    106 
    107    return sSelf->GetOrCreateInternal();
    108  }
    109 
    110  static void Shutdown() {
    111    sSelf = nullptr;
    112    sShutdown = true;
    113  }
    114 
    115 private:
    116  ~BundleHelper() = default;
    117 
    118  nsIStringBundle* GetOrCreateInternal() {
    119    if (!mBundle) {
    120      nsCOMPtr<nsIStringBundleService> bundleService =
    121          mozilla::components::StringBundle::Service();
    122      if (NS_WARN_IF(!bundleService)) {
    123        return nullptr;
    124      }
    125 
    126      nsresult rv = bundleService->CreateBundle(
    127          "chrome://global/locale/security/caps.properties",
    128          getter_AddRefs(mBundle));
    129      if (NS_WARN_IF(NS_FAILED(rv))) {
    130        return nullptr;
    131      }
    132    }
    133 
    134    return mBundle;
    135  }
    136 
    137  nsCOMPtr<nsIStringBundle> mBundle;
    138 
    139  static StaticRefPtr<BundleHelper> sSelf;
    140  static bool sShutdown;
    141 };
    142 
    143 StaticRefPtr<BundleHelper> BundleHelper::sSelf;
    144 bool BundleHelper::sShutdown = false;
    145 
    146 }  // namespace
    147 
    148 ///////////////////////////
    149 // Convenience Functions //
    150 ///////////////////////////
    151 
    152 class nsAutoInPrincipalDomainOriginSetter {
    153 public:
    154  nsAutoInPrincipalDomainOriginSetter() { ++sInPrincipalDomainOrigin; }
    155  ~nsAutoInPrincipalDomainOriginSetter() { --sInPrincipalDomainOrigin; }
    156  static uint32_t sInPrincipalDomainOrigin;
    157 };
    158 uint32_t nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
    159 
    160 static nsresult GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin) {
    161  if (!aURI) {
    162    return NS_ERROR_NULL_POINTER;
    163  }
    164  if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
    165    // Allow a single recursive call to GetPrincipalDomainOrigin, since that
    166    // might be happening on a different principal from the first call.  But
    167    // after that, cut off the recursion; it just indicates that something
    168    // we're doing in this method causes us to reenter a security check here.
    169    return NS_ERROR_NOT_AVAILABLE;
    170  }
    171 
    172  nsAutoInPrincipalDomainOriginSetter autoSetter;
    173 
    174  nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
    175  NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
    176 
    177  nsAutoCString hostPort;
    178 
    179  nsresult rv = uri->GetHostPort(hostPort);
    180  if (NS_SUCCEEDED(rv)) {
    181    nsAutoCString scheme;
    182    rv = uri->GetScheme(scheme);
    183    NS_ENSURE_SUCCESS(rv, rv);
    184    aOrigin = scheme + "://"_ns + hostPort;
    185  } else {
    186    // Some URIs (e.g., nsSimpleURI) don't support host. Just
    187    // get the full spec.
    188    rv = uri->GetSpec(aOrigin);
    189    NS_ENSURE_SUCCESS(rv, rv);
    190  }
    191 
    192  return NS_OK;
    193 }
    194 
    195 static nsresult GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
    196                                         nsACString& aOrigin) {
    197  aOrigin.Truncate();
    198  nsCOMPtr<nsIURI> uri;
    199  aPrincipal->GetDomain(getter_AddRefs(uri));
    200  nsresult rv = GetOriginFromURI(uri, aOrigin);
    201  if (NS_SUCCEEDED(rv)) {
    202    return rv;
    203  }
    204  // If there is no Domain fallback to the Principals Origin
    205  return aPrincipal->GetOriginNoSuffix(aOrigin);
    206 }
    207 
    208 inline void SetPendingExceptionASCII(JSContext* cx, const char* aMsg) {
    209  JS_ReportErrorASCII(cx, "%s", aMsg);
    210 }
    211 
    212 inline void SetPendingException(JSContext* cx, const char16_t* aMsg) {
    213  NS_ConvertUTF16toUTF8 msg(aMsg);
    214  JS_ReportErrorUTF8(cx, "%s", msg.get());
    215 }
    216 
    217 /* static */
    218 bool nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
    219                                                  nsIURI* aTargetURI) {
    220  return NS_SecurityCompareURIs(aSourceURI, aTargetURI,
    221                                sStrictFileOriginPolicy);
    222 }
    223 
    224 // SecurityHashURI is consistent with SecurityCompareURIs because
    225 // NS_SecurityHashURI is consistent with NS_SecurityCompareURIs.  See
    226 // nsNetUtil.h.
    227 uint32_t nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI) {
    228  return NS_SecurityHashURI(aURI);
    229 }
    230 
    231 bool nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(nsIURI* aUriA,
    232                                                          nsIURI* aUriB) {
    233  if (!aUriA || !net::SchemeIsHttpOrHttps(aUriA) || !aUriB ||
    234      !net::SchemeIsHttpOrHttps(aUriB)) {
    235    return false;
    236  }
    237  if (!SecurityCompareURIs(aUriA, aUriB)) {
    238    return true;
    239  }
    240  return false;
    241 }
    242 
    243 /*
    244 * GetChannelResultPrincipal will return the principal that the resource
    245 * returned by this channel will use.  For example, if the resource is in
    246 * a sandbox, it will return the nullprincipal.  If the resource is forced
    247 * to inherit principal, it will return the principal of its parent.  If
    248 * the load doesn't require sandboxing or inheriting, it will return the same
    249 * principal as GetChannelURIPrincipal. Namely the principal of the URI
    250 * that is being loaded.
    251 */
    252 NS_IMETHODIMP
    253 nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
    254                                                   nsIPrincipal** aPrincipal) {
    255  return GetChannelResultPrincipal(aChannel, aPrincipal,
    256                                   /*aIgnoreSandboxing*/ false);
    257 }
    258 
    259 nsresult nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(
    260    nsIChannel* aChannel, nsIPrincipal** aPrincipal) {
    261  return GetChannelResultPrincipal(aChannel, aPrincipal,
    262                                   /*aIgnoreSandboxing*/ true);
    263 }
    264 
    265 NS_IMETHODIMP
    266 nsScriptSecurityManager::GetChannelResultStoragePrincipal(
    267    nsIChannel* aChannel, nsIPrincipal** aPrincipal) {
    268  nsCOMPtr<nsIPrincipal> principal;
    269  nsresult rv = GetChannelResultPrincipal(aChannel, getter_AddRefs(principal),
    270                                          /*aIgnoreSandboxing*/ false);
    271  if (NS_WARN_IF(NS_FAILED(rv) || !principal)) {
    272    return rv;
    273  }
    274 
    275  if (!(principal->GetIsContentPrincipal())) {
    276    // If for some reason we don't have a content principal here, just reuse our
    277    // principal for the storage principal too, since attempting to create a
    278    // storage principal would fail anyway.
    279    principal.forget(aPrincipal);
    280    return NS_OK;
    281  }
    282 
    283  return StoragePrincipalHelper::Create(
    284      aChannel, principal, /* aForceIsolation */ false, aPrincipal);
    285 }
    286 
    287 NS_IMETHODIMP
    288 nsScriptSecurityManager::GetChannelResultPrincipals(
    289    nsIChannel* aChannel, nsIPrincipal** aPrincipal,
    290    nsIPrincipal** aPartitionedPrincipal) {
    291  nsresult rv = GetChannelResultPrincipal(aChannel, aPrincipal,
    292                                          /*aIgnoreSandboxing*/ false);
    293  if (NS_WARN_IF(NS_FAILED(rv))) {
    294    return rv;
    295  }
    296 
    297  if (!(*aPrincipal)->GetIsContentPrincipal()) {
    298    // If for some reason we don't have a content principal here, just reuse our
    299    // principal for the storage principal too, since attempting to create a
    300    // storage principal would fail anyway.
    301    nsCOMPtr<nsIPrincipal> copy = *aPrincipal;
    302    copy.forget(aPartitionedPrincipal);
    303    return NS_OK;
    304  }
    305 
    306  return StoragePrincipalHelper::Create(
    307      aChannel, *aPrincipal, /* aForceIsolation */ true, aPartitionedPrincipal);
    308 }
    309 
    310 nsresult nsScriptSecurityManager::GetChannelResultPrincipal(
    311    nsIChannel* aChannel, nsIPrincipal** aPrincipal, bool aIgnoreSandboxing) {
    312  MOZ_ASSERT(aChannel, "Must have channel!");
    313 
    314  // Check whether we have an nsILoadInfo that says what we should do.
    315  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    316  if (loadInfo->GetForceInheritPrincipalOverruleOwner()) {
    317    nsCOMPtr<nsIPrincipal> principalToInherit =
    318        loadInfo->FindPrincipalToInherit(aChannel);
    319    principalToInherit.forget(aPrincipal);
    320    return NS_OK;
    321  }
    322 
    323  nsCOMPtr<nsISupports> owner;
    324  aChannel->GetOwner(getter_AddRefs(owner));
    325  if (owner) {
    326    CallQueryInterface(owner, aPrincipal);
    327    if (*aPrincipal) {
    328      return NS_OK;
    329    }
    330  }
    331 
    332  if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
    333    // Determine the unsandboxed result principal to use as this null
    334    // principal's precursor. Ignore errors here, as the precursor isn't
    335    // required.
    336    nsCOMPtr<nsIPrincipal> precursor;
    337    GetChannelResultPrincipal(aChannel, getter_AddRefs(precursor),
    338                              /*aIgnoreSandboxing*/ true);
    339 
    340    // Construct a deterministic null principal URI from the precursor and the
    341    // loadinfo's nullPrincipalID.
    342    nsCOMPtr<nsIURI> nullPrincipalURI = NullPrincipal::CreateURI(
    343        precursor, &loadInfo->GetSandboxedNullPrincipalID());
    344 
    345    // Use the URI to construct the sandboxed result principal.
    346    OriginAttributes attrs;
    347    loadInfo->GetOriginAttributes(&attrs);
    348    nsCOMPtr<nsIPrincipal> sandboxedPrincipal =
    349        NullPrincipal::Create(attrs, nullPrincipalURI);
    350    sandboxedPrincipal.forget(aPrincipal);
    351    return NS_OK;
    352  }
    353 
    354  bool forceInherit = loadInfo->GetForceInheritPrincipal();
    355  if (aIgnoreSandboxing && !forceInherit) {
    356    // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of
    357    // sandboxing:
    358    if (loadInfo->GetLoadingSandboxed() &&
    359        loadInfo->GetForceInheritPrincipalDropped()) {
    360      forceInherit = true;
    361    }
    362  }
    363  if (forceInherit) {
    364    nsCOMPtr<nsIPrincipal> principalToInherit =
    365        loadInfo->FindPrincipalToInherit(aChannel);
    366    principalToInherit.forget(aPrincipal);
    367    return NS_OK;
    368  }
    369 
    370  auto securityMode = loadInfo->GetSecurityMode();
    371  // The data: inheritance flags should only apply to the initial load,
    372  // not to loads that it might have redirected to.
    373  if (loadInfo->RedirectChain().IsEmpty() &&
    374      (securityMode ==
    375           nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT ||
    376       securityMode ==
    377           nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT ||
    378       securityMode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT)) {
    379    nsCOMPtr<nsIURI> uri;
    380    nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    381    NS_ENSURE_SUCCESS(rv, rv);
    382 
    383    nsCOMPtr<nsIPrincipal> principalToInherit =
    384        loadInfo->FindPrincipalToInherit(aChannel);
    385    bool inheritForAboutBlank = loadInfo->GetAboutBlankInherits();
    386 
    387    if (nsContentUtils::ChannelShouldInheritPrincipal(
    388            principalToInherit, uri, inheritForAboutBlank, false)) {
    389      principalToInherit.forget(aPrincipal);
    390      return NS_OK;
    391    }
    392  }
    393  return GetChannelURIPrincipal(aChannel, aPrincipal);
    394 }
    395 
    396 /* The principal of the URI that this channel is loading. This is never
    397 * affected by things like sandboxed loads, or loads where we forcefully
    398 * inherit the principal.  Think of this as the principal of the server
    399 * which this channel is loading from.  Most callers should use
    400 * GetChannelResultPrincipal instead of GetChannelURIPrincipal.  Only
    401 * call GetChannelURIPrincipal if you are sure that you want the
    402 * principal that matches the uri, even in cases when the load is
    403 * sandboxed or when the load could be a blob or data uri (i.e even when
    404 * you encounter loads that may or may not be sandboxed and loads
    405 * that may or may not inherit)."
    406 */
    407 NS_IMETHODIMP
    408 nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
    409                                                nsIPrincipal** aPrincipal) {
    410  MOZ_ASSERT(aChannel, "Must have channel!");
    411 
    412  // Get the principal from the URI.  Make sure this does the same thing
    413  // as Document::Reset and PrototypeDocumentContentSink::Init.
    414  nsCOMPtr<nsIURI> uri;
    415  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    416  NS_ENSURE_SUCCESS(rv, rv);
    417 
    418  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    419 
    420  // Inherit the origin attributes from loadInfo.
    421  // If this is a top-level document load, the origin attributes of the
    422  // loadInfo will be set from nsDocShell::DoURILoad.
    423  // For subresource loading, the origin attributes of the loadInfo is from
    424  // its loadingPrincipal.
    425  OriginAttributes attrs = loadInfo->GetOriginAttributes();
    426 
    427  // If the URI is supposed to inherit the security context of whoever loads it,
    428  // we shouldn't make a content principal for it, so instead return a null
    429  // principal.
    430  bool inheritsPrincipal = false;
    431  rv = NS_URIChainHasFlags(uri,
    432                           nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
    433                           &inheritsPrincipal);
    434  if (NS_FAILED(rv) || inheritsPrincipal) {
    435    // Find a precursor principal to credit for the load. This won't impact
    436    // security checks, but makes tracking the source of related loads easier.
    437    nsCOMPtr<nsIPrincipal> precursorPrincipal =
    438        loadInfo->FindPrincipalToInherit(aChannel);
    439    nsCOMPtr<nsIURI> nullPrincipalURI =
    440        NullPrincipal::CreateURI(precursorPrincipal);
    441    *aPrincipal = NullPrincipal::Create(attrs, nullPrincipalURI).take();
    442    return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    443  }
    444 
    445  nsCOMPtr<nsIPrincipal> prin =
    446      BasePrincipal::CreateContentPrincipal(uri, attrs);
    447  prin.forget(aPrincipal);
    448  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    449 }
    450 
    451 /////////////////////////////
    452 // nsScriptSecurityManager //
    453 /////////////////////////////
    454 
    455 ////////////////////////////////////
    456 // Methods implementing ISupports //
    457 ////////////////////////////////////
    458 NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager)
    459 
    460 ///////////////////////////////////////////////////
    461 // Methods implementing nsIScriptSecurityManager //
    462 ///////////////////////////////////////////////////
    463 
    464 ///////////////// Security Checks /////////////////
    465 
    466 bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
    467    JSContext* cx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
    468    JS::CompilationType aCompilationType,
    469    JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
    470    JS::Handle<JSString*> aBodyString,
    471    JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
    472    JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
    473  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
    474 
    475  nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
    476 
    477  if (aKind == JS::RuntimeCode::JS) {
    478    ErrorResult error;
    479    bool areArgumentsTrusted = TrustedTypeUtils::
    480        AreArgumentsTrustedForEnsureCSPDoesNotBlockStringCompilation(
    481            cx, aCodeString, aCompilationType, aParameterStrings, aBodyString,
    482            aParameterArgs, aBodyArg, subjectPrincipal, error);
    483    if (error.MaybeSetPendingException(cx)) {
    484      return false;
    485    }
    486    if (!areArgumentsTrusted) {
    487      *aOutCanCompileStrings = false;
    488      return true;
    489    }
    490  }
    491 
    492  // Check if Eval is allowed per firefox hardening policy
    493  bool contextForbidsEval =
    494      (subjectPrincipal->IsSystemPrincipal() || XRE_IsE10sParentProcess());
    495  if (contextForbidsEval) {
    496    nsAutoJSString scriptSample;
    497    if (aKind == JS::RuntimeCode::JS &&
    498        NS_WARN_IF(!scriptSample.init(cx, aCodeString))) {
    499      return false;
    500    }
    501 
    502    if (!nsContentSecurityUtils::IsEvalAllowed(
    503            cx, subjectPrincipal->IsSystemPrincipal(), scriptSample)) {
    504      *aOutCanCompileStrings = false;
    505      return true;
    506    }
    507  }
    508 
    509  // Get the window, if any, corresponding to the current global
    510  nsCOMPtr<nsIContentSecurityPolicy> csp;
    511  if (nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(cx)) {
    512    csp = PolicyContainer::GetCSP(win->GetPolicyContainer());
    513  }
    514 
    515  if (!csp) {
    516    // Get the CSP for addon sandboxes.  If the principal is expanded and has a
    517    // csp, we're probably in luck.
    518    auto* basePrin = BasePrincipal::Cast(subjectPrincipal);
    519    // TODO bug 1548468: Move CSP off ExpandedPrincipal.
    520    if (basePrin->Is<ExpandedPrincipal>()) {
    521      basePrin->As<ExpandedPrincipal>()->GetCsp(getter_AddRefs(csp));
    522    }
    523    // don't do anything unless there's a CSP
    524    if (!csp) {
    525      *aOutCanCompileStrings = true;
    526      return true;
    527    }
    528  }
    529 
    530  nsCOMPtr<nsICSPEventListener> cspEventListener;
    531  if (!NS_IsMainThread()) {
    532    WorkerPrivate* workerPrivate =
    533        mozilla::dom::GetWorkerPrivateFromContext(cx);
    534    if (workerPrivate) {
    535      cspEventListener = workerPrivate->CSPEventListener();
    536    }
    537  }
    538 
    539  bool evalOK = true;
    540  bool reportViolation = false;
    541  if (aKind == JS::RuntimeCode::JS) {
    542    nsresult rv = csp->GetAllowsEval(&reportViolation, &evalOK);
    543    if (NS_FAILED(rv)) {
    544      NS_WARNING("CSP: failed to get allowsEval");
    545      *aOutCanCompileStrings = true;  // fail open to not break sites.
    546      return true;
    547    }
    548  } else {
    549    if (NS_FAILED(csp->GetAllowsWasmEval(&reportViolation, &evalOK))) {
    550      return false;
    551    }
    552    if (!evalOK) {
    553      // Historically, CSP did not block WebAssembly in Firefox, and some
    554      // add-ons use wasm and a stricter CSP. To avoid breaking them, ignore
    555      // 'wasm-unsafe-eval' violations for MV2 extensions.
    556      // TODO bug 1770909: remove this exception.
    557      auto* addonPolicy = BasePrincipal::Cast(subjectPrincipal)->AddonPolicy();
    558      if (addonPolicy && addonPolicy->ManifestVersion() == 2) {
    559        reportViolation = true;
    560        evalOK = true;
    561      }
    562    }
    563  }
    564 
    565  if (reportViolation) {
    566    auto caller = JSCallingLocation::Get(cx);
    567    nsAutoJSString scriptSample;
    568    if (aKind == JS::RuntimeCode::JS &&
    569        NS_WARN_IF(!scriptSample.init(cx, aCodeString))) {
    570      return false;
    571    }
    572    uint16_t violationType =
    573        aKind == JS::RuntimeCode::JS
    574            ? nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL
    575            : nsIContentSecurityPolicy::VIOLATION_TYPE_WASM_EVAL;
    576    csp->LogViolationDetails(violationType,
    577                             nullptr,  // triggering element
    578                             cspEventListener, caller.FileName(), scriptSample,
    579                             caller.mLine, caller.mColumn, u""_ns, u""_ns);
    580  }
    581 
    582  *aOutCanCompileStrings = evalOK;
    583  return true;
    584 }
    585 
    586 // static
    587 bool nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals* first,
    588                                                  JSPrincipals* second) {
    589  return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
    590 }
    591 
    592 NS_IMETHODIMP
    593 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
    594                                            nsIURI* aTargetURI,
    595                                            bool reportError,
    596                                            bool aFromPrivateWindow) {
    597  // Please note that aFromPrivateWindow is only 100% accurate if
    598  // reportError is true.
    599  if (!SecurityCompareURIs(aSourceURI, aTargetURI)) {
    600    if (reportError) {
    601      ReportError("CheckSameOriginError", aSourceURI, aTargetURI,
    602                  aFromPrivateWindow);
    603    }
    604    return NS_ERROR_DOM_BAD_URI;
    605  }
    606  return NS_OK;
    607 }
    608 
    609 NS_IMETHODIMP
    610 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext* cx, nsIURI* aURI) {
    611  // Get principal of currently executing script.
    612  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
    613  nsIPrincipal* principal = nsContentUtils::SubjectPrincipal();
    614  nsresult rv = CheckLoadURIWithPrincipal(
    615      // Passing 0 for the window ID here is OK, because we will report a
    616      // script-visible exception anyway.
    617      principal, aURI, nsIScriptSecurityManager::STANDARD, 0);
    618  if (NS_SUCCEEDED(rv)) {
    619    // OK to load
    620    return NS_OK;
    621  }
    622 
    623  // Report error.
    624  nsAutoCString spec;
    625  if (NS_FAILED(aURI->GetAsciiSpec(spec))) return NS_ERROR_FAILURE;
    626  nsAutoCString msg("Access to '");
    627  msg.Append(spec);
    628  msg.AppendLiteral("' from script denied");
    629  SetPendingExceptionASCII(cx, msg.get());
    630  return NS_ERROR_DOM_BAD_URI;
    631 }
    632 
    633 /**
    634 * Helper method to handle cases where a flag passed to
    635 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
    636 * nsIProtocolHandler flags set.
    637 * @return if success, access is allowed. Otherwise, deny access
    638 */
    639 static nsresult DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags) {
    640  MOZ_ASSERT(aURI, "Must have URI!");
    641 
    642  bool uriHasFlags;
    643  nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
    644  NS_ENSURE_SUCCESS(rv, rv);
    645 
    646  if (uriHasFlags) {
    647    return NS_ERROR_DOM_BAD_URI;
    648  }
    649 
    650  return NS_OK;
    651 }
    652 
    653 static bool EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase) {
    654  nsresult rv;
    655  nsCOMPtr<nsIURI> probe = aProbeArg;
    656 
    657  nsCOMPtr<nsIEffectiveTLDService> tldService =
    658      do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
    659  NS_ENSURE_TRUE(tldService, false);
    660  while (true) {
    661    if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
    662      return true;
    663    }
    664 
    665    nsAutoCString host, newHost;
    666    rv = probe->GetHost(host);
    667    NS_ENSURE_SUCCESS(rv, false);
    668 
    669    rv = tldService->GetNextSubDomain(host, newHost);
    670    if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    671      return false;
    672    }
    673    NS_ENSURE_SUCCESS(rv, false);
    674    rv = NS_MutateURI(probe).SetHost(newHost).Finalize(probe);
    675    NS_ENSURE_SUCCESS(rv, false);
    676  }
    677 }
    678 
    679 NS_IMETHODIMP
    680 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
    681                                                   nsIURI* aTargetURI,
    682                                                   uint32_t aFlags,
    683                                                   uint64_t aInnerWindowID) {
    684  MOZ_ASSERT(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
    685 
    686  // If someone passes a flag that we don't understand, we should
    687  // fail, because they may need a security check that we don't
    688  // provide.
    689  NS_ENSURE_FALSE(
    690      aFlags &
    691          ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
    692            nsIScriptSecurityManager::ALLOW_CHROME |
    693            nsIScriptSecurityManager::DISALLOW_SCRIPT |
    694            nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
    695            nsIScriptSecurityManager::DONT_REPORT_ERRORS),
    696      NS_ERROR_UNEXPECTED);
    697  NS_ENSURE_ARG_POINTER(aPrincipal);
    698  NS_ENSURE_ARG_POINTER(aTargetURI);
    699 
    700  // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
    701  // would do such inheriting. That would be URIs that do not have their own
    702  // security context. We do this even for the system principal.
    703  if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
    704    nsresult rv = DenyAccessIfURIHasFlags(
    705        aTargetURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
    706    NS_ENSURE_SUCCESS(rv, rv);
    707  }
    708 
    709  if (aPrincipal == mSystemPrincipal) {
    710    // Allow access
    711    return NS_OK;
    712  }
    713 
    714  nsCOMPtr<nsIURI> sourceURI;
    715  auto* basePrin = BasePrincipal::Cast(aPrincipal);
    716  basePrin->GetURI(getter_AddRefs(sourceURI));
    717  if (!sourceURI) {
    718    if (basePrin->Is<ExpandedPrincipal>()) {
    719      // If the target addon is MV3 or the pref is on we require extension
    720      // resources loaded from content to be listed in web_accessible_resources.
    721      auto* targetPolicy =
    722          ExtensionPolicyService::GetSingleton().GetByURL(aTargetURI);
    723      bool contentAccessRequired =
    724          targetPolicy &&
    725          (targetPolicy->ManifestVersion() > 2 ||
    726           StaticPrefs::extensions_content_web_accessible_enabled());
    727      auto expanded = basePrin->As<ExpandedPrincipal>();
    728      const auto& allowList = expanded->AllowList();
    729      // Only report errors when all principals fail.
    730      // With expanded principals, which are used by extension content scripts,
    731      // we check only against non-extension principals for access to extension
    732      // resource to enforce making those resources explicitly web accessible.
    733      uint32_t flags = aFlags | nsIScriptSecurityManager::DONT_REPORT_ERRORS;
    734      for (size_t i = 0; i < allowList.Length() - 1; i++) {
    735        if (contentAccessRequired &&
    736            BasePrincipal::Cast(allowList[i])->AddonPolicy()) {
    737          continue;
    738        }
    739        nsresult rv = CheckLoadURIWithPrincipal(allowList[i], aTargetURI, flags,
    740                                                aInnerWindowID);
    741        if (NS_SUCCEEDED(rv)) {
    742          // Allow access if it succeeded with one of the allowlisted principals
    743          return NS_OK;
    744        }
    745      }
    746 
    747      if (contentAccessRequired &&
    748          BasePrincipal::Cast(allowList.LastElement())->AddonPolicy()) {
    749        bool reportErrors =
    750            !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS);
    751        if (reportErrors) {
    752          ReportError("CheckLoadURI", sourceURI, aTargetURI,
    753                      allowList.LastElement()
    754                          ->OriginAttributesRef()
    755                          .IsPrivateBrowsing(),
    756                      aInnerWindowID);
    757        }
    758        return NS_ERROR_DOM_BAD_URI;
    759      }
    760      // Report errors (if requested) for the last principal.
    761      return CheckLoadURIWithPrincipal(allowList.LastElement(), aTargetURI,
    762                                       aFlags, aInnerWindowID);
    763    }
    764    NS_ERROR(
    765        "Non-system principals or expanded principal passed to "
    766        "CheckLoadURIWithPrincipal "
    767        "must have a URI!");
    768    return NS_ERROR_UNEXPECTED;
    769  }
    770 
    771  // Automatic loads are not allowed from certain protocols.
    772  if (aFlags &
    773      nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
    774    nsresult rv = DenyAccessIfURIHasFlags(
    775        sourceURI,
    776        nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
    777    NS_ENSURE_SUCCESS(rv, rv);
    778  }
    779 
    780  // If either URI is a nested URI, get the base URI
    781  nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
    782  nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
    783 
    784  //-- get the target scheme
    785  nsAutoCString targetScheme;
    786  nsresult rv = targetBaseURI->GetScheme(targetScheme);
    787  if (NS_FAILED(rv)) return rv;
    788 
    789  //-- Some callers do not allow loading javascript:
    790  if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
    791      targetScheme.EqualsLiteral("javascript")) {
    792    return NS_ERROR_DOM_BAD_URI;
    793  }
    794 
    795  // Check for uris that are only loadable by principals that subsume them
    796  bool targetURIIsLoadableBySubsumers = false;
    797  rv = NS_URIChainHasFlags(targetBaseURI,
    798                           nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
    799                           &targetURIIsLoadableBySubsumers);
    800  NS_ENSURE_SUCCESS(rv, rv);
    801 
    802  if (targetURIIsLoadableBySubsumers) {
    803    // check nothing else in the URI chain has flags that prevent
    804    // access:
    805    rv = CheckLoadURIFlags(
    806        sourceURI, aTargetURI, sourceBaseURI, targetBaseURI, aFlags,
    807        aPrincipal->OriginAttributesRef().IsPrivateBrowsing(), aInnerWindowID);
    808    NS_ENSURE_SUCCESS(rv, rv);
    809    // Check the principal is allowed to load the target.
    810    if (aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS) {
    811      return aPrincipal->CheckMayLoad(targetBaseURI, false);
    812    }
    813    return aPrincipal->CheckMayLoadWithReporting(targetBaseURI, false,
    814                                                 aInnerWindowID);
    815  }
    816 
    817  //-- get the source scheme
    818  nsAutoCString sourceScheme;
    819  rv = sourceBaseURI->GetScheme(sourceScheme);
    820  if (NS_FAILED(rv)) return rv;
    821 
    822  if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
    823    // A null principal can target its own URI.
    824    if (sourceURI == aTargetURI) {
    825      return NS_OK;
    826    }
    827  } else if (sourceScheme.EqualsIgnoreCase("file") &&
    828             targetScheme.EqualsIgnoreCase("moz-icon")) {
    829    // exception for file: linking to moz-icon://.ext?size=...
    830    // Note that because targetScheme is the base (innermost) URI scheme,
    831    // this does NOT allow file -> moz-icon:file:///... links.
    832    // This is intentional.
    833    return NS_OK;
    834  }
    835 
    836  // Check for webextension
    837  bool targetURIIsLoadableByExtensions = false;
    838  rv = NS_URIChainHasFlags(aTargetURI,
    839                           nsIProtocolHandler::URI_LOADABLE_BY_EXTENSIONS,
    840                           &targetURIIsLoadableByExtensions);
    841  NS_ENSURE_SUCCESS(rv, rv);
    842 
    843  if (targetURIIsLoadableByExtensions &&
    844      BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
    845    return NS_OK;
    846  }
    847 
    848  // If we get here, check all the schemes can link to each other, from the top
    849  // down:
    850  nsCOMPtr<nsIURI> currentURI = sourceURI;
    851  nsCOMPtr<nsIURI> currentOtherURI = aTargetURI;
    852 
    853  bool denySameSchemeLinks = false;
    854  rv = NS_URIChainHasFlags(aTargetURI,
    855                           nsIProtocolHandler::URI_SCHEME_NOT_SELF_LINKABLE,
    856                           &denySameSchemeLinks);
    857  if (NS_FAILED(rv)) return rv;
    858 
    859  while (currentURI && currentOtherURI) {
    860    nsAutoCString scheme, otherScheme;
    861    currentURI->GetScheme(scheme);
    862    currentOtherURI->GetScheme(otherScheme);
    863 
    864    bool schemesMatch =
    865        scheme.Equals(otherScheme, nsCaseInsensitiveCStringComparator);
    866    bool isSamePage = false;
    867    bool isExtensionMismatch = false;
    868    // about: URIs are special snowflakes.
    869    if (scheme.EqualsLiteral("about") && schemesMatch) {
    870      nsAutoCString moduleName, otherModuleName;
    871      // about: pages can always link to themselves:
    872      isSamePage =
    873          NS_SUCCEEDED(NS_GetAboutModuleName(currentURI, moduleName)) &&
    874          NS_SUCCEEDED(
    875              NS_GetAboutModuleName(currentOtherURI, otherModuleName)) &&
    876          moduleName.Equals(otherModuleName);
    877      if (!isSamePage) {
    878        // We will have allowed the load earlier if the source page has
    879        // system principal. So we know the source has a content
    880        // principal, and it's trying to link to something else.
    881        // Linkable about: pages are always reachable, even if we hit
    882        // the CheckLoadURIFlags call below.
    883        // We punch only 1 other hole: iff the source is unlinkable,
    884        // we let them link to other pages explicitly marked SAFE
    885        // for content. This avoids world-linkable about: pages linking
    886        // to non-world-linkable about: pages.
    887        nsCOMPtr<nsIAboutModule> module, otherModule;
    888        bool knowBothModules =
    889            NS_SUCCEEDED(
    890                NS_GetAboutModule(currentURI, getter_AddRefs(module))) &&
    891            NS_SUCCEEDED(NS_GetAboutModule(currentOtherURI,
    892                                           getter_AddRefs(otherModule)));
    893        uint32_t aboutModuleFlags = 0;
    894        uint32_t otherAboutModuleFlags = 0;
    895        knowBothModules =
    896            knowBothModules &&
    897            NS_SUCCEEDED(module->GetURIFlags(currentURI, &aboutModuleFlags)) &&
    898            NS_SUCCEEDED(otherModule->GetURIFlags(currentOtherURI,
    899                                                  &otherAboutModuleFlags));
    900        if (knowBothModules) {
    901          isSamePage = !(aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) &&
    902                       (otherAboutModuleFlags &
    903                        nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT);
    904          if (isSamePage &&
    905              otherAboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
    906            // XXXgijs: this is a hack. The target will be nested
    907            // (with innerURI of moz-safe-about:whatever), and
    908            // the source isn't, so we won't pass if we finish
    909            // the loop. We *should* pass, though, so return here.
    910            // This hack can go away when bug 1228118 is fixed.
    911            return NS_OK;
    912          }
    913        }
    914      }
    915    } else if (schemesMatch && scheme.EqualsLiteral("moz-extension")) {
    916      // If it is not the same exension, we want to ensure we end up
    917      // calling CheckLoadURIFlags
    918      nsAutoCString host, otherHost;
    919      currentURI->GetHost(host);
    920      currentOtherURI->GetHost(otherHost);
    921      isExtensionMismatch = !host.Equals(otherHost);
    922    } else {
    923      bool equalExceptRef = false;
    924      rv = currentURI->EqualsExceptRef(currentOtherURI, &equalExceptRef);
    925      isSamePage = NS_SUCCEEDED(rv) && equalExceptRef;
    926    }
    927 
    928    // If schemes are not equal, or they're equal but the target URI
    929    // is different from the source URI and doesn't always allow linking
    930    // from the same scheme, or this is two different extensions, check
    931    // if the URI flags of the current target URI allow the current
    932    // source URI to link to it.
    933    // The policy is specified by the protocol flags on both URIs.
    934    if (!schemesMatch || (denySameSchemeLinks && !isSamePage) ||
    935        isExtensionMismatch) {
    936      return CheckLoadURIFlags(
    937          currentURI, currentOtherURI, sourceBaseURI, targetBaseURI, aFlags,
    938          aPrincipal->OriginAttributesRef().IsPrivateBrowsing(),
    939          aInnerWindowID);
    940    }
    941    // Otherwise... check if we can nest another level:
    942    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentURI);
    943    nsCOMPtr<nsINestedURI> nestedOtherURI = do_QueryInterface(currentOtherURI);
    944 
    945    // If schemes match and neither URI is nested further, we're OK.
    946    if (!nestedURI && !nestedOtherURI) {
    947      return NS_OK;
    948    }
    949    // If one is nested and the other isn't, something is wrong.
    950    if (!nestedURI != !nestedOtherURI) {
    951      return NS_ERROR_DOM_BAD_URI;
    952    }
    953    // Otherwise, both should be nested and we'll go through the loop again.
    954    nestedURI->GetInnerURI(getter_AddRefs(currentURI));
    955    nestedOtherURI->GetInnerURI(getter_AddRefs(currentOtherURI));
    956  }
    957 
    958  // We should never get here. We should always return from inside the loop.
    959  return NS_ERROR_DOM_BAD_URI;
    960 }
    961 
    962 /**
    963 * Helper method to check whether the target URI and its innermost ("base") URI
    964 * has protocol flags that should stop it from being loaded by the source URI
    965 * (and/or the source URI's innermost ("base") URI), taking into account any
    966 * nsIScriptSecurityManager flags originally passed to
    967 * CheckLoadURIWithPrincipal and friends.
    968 *
    969 * @return if success, access is allowed. Otherwise, deny access
    970 */
    971 nsresult nsScriptSecurityManager::CheckLoadURIFlags(
    972    nsIURI* aSourceURI, nsIURI* aTargetURI, nsIURI* aSourceBaseURI,
    973    nsIURI* aTargetBaseURI, uint32_t aFlags, bool aFromPrivateWindow,
    974    uint64_t aInnerWindowID) {
    975  // Note that the order of policy checks here is very important!
    976  // We start from most restrictive and work our way down.
    977  bool reportErrors = !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS);
    978  const char* errorTag = "CheckLoadURIError";
    979 
    980  nsAutoCString targetScheme;
    981  nsresult rv = aTargetBaseURI->GetScheme(targetScheme);
    982  if (NS_FAILED(rv)) return rv;
    983 
    984  // Check for system target URI.
    985  rv = DenyAccessIfURIHasFlags(aTargetURI,
    986                               nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
    987  if (NS_FAILED(rv)) {
    988    // Deny access, since the origin principal is not system
    989    if (reportErrors) {
    990      ReportError(errorTag, aSourceURI, aTargetURI, aFromPrivateWindow,
    991                  aInnerWindowID);
    992    }
    993    return rv;
    994  }
    995 
    996  // WebExtension URIs are only accessible if the ExtensionPolicyService allows
    997  // the source URI to load them.
    998  bool targetURIIsWebExtensionResource = false;
    999  rv = NS_URIChainHasFlags(aTargetURI,
   1000                           nsIProtocolHandler::URI_IS_WEBEXTENSION_RESOURCE,
   1001                           &targetURIIsWebExtensionResource);
   1002  NS_ENSURE_SUCCESS(rv, rv);
   1003  if (targetURIIsWebExtensionResource) {
   1004    bool isAccessible = false;
   1005    rv = ExtensionPolicyService::GetSingleton().SourceMayLoadExtensionURI(
   1006        aSourceURI, aTargetURI, aFromPrivateWindow, &isAccessible);
   1007    if (NS_SUCCEEDED(rv) && isAccessible) {
   1008      return NS_OK;
   1009    }
   1010    if (reportErrors) {
   1011      ReportError(errorTag, aSourceURI, aTargetURI, aFromPrivateWindow,
   1012                  aInnerWindowID);
   1013    }
   1014    return NS_ERROR_DOM_BAD_URI;
   1015  }
   1016 
   1017  // Check for chrome target URI
   1018  bool targetURIIsUIResource = false;
   1019  rv = NS_URIChainHasFlags(aTargetURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
   1020                           &targetURIIsUIResource);
   1021  NS_ENSURE_SUCCESS(rv, rv);
   1022  if (targetURIIsUIResource) {
   1023    // ALLOW_CHROME is a flag that we pass on all loads _except_ docshell
   1024    // loads (since docshell loads run the loaded content with its origin
   1025    // principal). We are effectively allowing resource:// and chrome://
   1026    // URIs to load as long as they are content accessible and as long
   1027    // they're not loading it as a document.
   1028    if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
   1029      bool sourceIsUIResource = false;
   1030      rv = NS_URIChainHasFlags(aSourceBaseURI,
   1031                               nsIProtocolHandler::URI_IS_UI_RESOURCE,
   1032                               &sourceIsUIResource);
   1033      NS_ENSURE_SUCCESS(rv, rv);
   1034      if (sourceIsUIResource) {
   1035        // Special case for moz-icon URIs loaded by a local resources like
   1036        // e.g. chrome: or resource:
   1037        if (targetScheme.EqualsLiteral("moz-icon")) {
   1038          return NS_OK;
   1039        }
   1040      }
   1041 
   1042      // Only allow some "about:" pages to have access to contentaccessible
   1043      // "chrome://branding/" assets. Otherwise web pages could easily and
   1044      // consistently detect the differences between channels when their
   1045      // branding differs. See tor-browser#43308 and tor-browser#42319.
   1046      // NOTE: The same assets under the alternative URI
   1047      // "resource:///chrome/browser/content/branding/" should already be
   1048      // inaccessible to web content, so we only add a condition for the chrome
   1049      // path.
   1050      if (targetScheme.EqualsLiteral("chrome")) {
   1051        nsAutoCString targetHost;
   1052        rv = aTargetBaseURI->GetHost(targetHost);
   1053        NS_ENSURE_SUCCESS(rv, rv);
   1054        if (targetHost.EqualsLiteral("branding")) {
   1055          // Disallow any Principal whose scheme is not "about", or is a
   1056          // contentaccessible "about" URI ("about:blank" or "about:srcdoc").
   1057          // NOTE: "about:blank" and "about:srcdoc" would be unexpected here
   1058          // since such a document spawned by a web document should inherit the
   1059          // same Principal URI. I.e. they would be "http:" or "https:" schemes.
   1060          // But we add this condition for extra assurances.
   1061          // NOTE: Documents with null Principals, like "about:blank" typed by
   1062          // the user, would also be excluded since the Principal URI would be
   1063          // "moz-nullprincipal:".
   1064          if (!aSourceBaseURI->SchemeIs("about") ||
   1065              NS_IsContentAccessibleAboutURI(aSourceBaseURI)) {
   1066            return NS_ERROR_DOM_BAD_URI;
   1067          }
   1068          // Also exclude "about:reader" from accessing branding assets. I.e. if
   1069          // a web page includes `<img src="chrome://branding/..." />` we do not
   1070          // want it to render within "about:reader" either.
   1071          // Though it is unknown whether the information within "about:reader"
   1072          // would be exploitable by a web page, we also want to exclude
   1073          // "about:reader" for consistency: if it does not display in the
   1074          // original web page, it should not display in "about:reader" either.
   1075          nsAutoCString sourcePath;
   1076          rv = aSourceBaseURI->GetFilePath(sourcePath);
   1077          NS_ENSURE_SUCCESS(rv, rv);
   1078          if (sourcePath.EqualsLiteral("reader")) {
   1079            return NS_ERROR_DOM_BAD_URI;
   1080          }
   1081        }
   1082      }
   1083 
   1084      if (targetScheme.EqualsLiteral("resource")) {
   1085        if (StaticPrefs::security_all_resource_uri_content_accessible()) {
   1086          return NS_OK;
   1087        }
   1088 
   1089        nsCOMPtr<nsIProtocolHandler> ph;
   1090        rv = sIOService->GetProtocolHandler("resource", getter_AddRefs(ph));
   1091        NS_ENSURE_SUCCESS(rv, rv);
   1092        if (!ph) {
   1093          return NS_ERROR_DOM_BAD_URI;
   1094        }
   1095 
   1096        nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
   1097        if (!rph) {
   1098          return NS_ERROR_DOM_BAD_URI;
   1099        }
   1100 
   1101        bool accessAllowed = false;
   1102        rph->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
   1103        if (accessAllowed) {
   1104          return NS_OK;
   1105        }
   1106      } else if (targetScheme.EqualsLiteral("chrome")) {
   1107        // Allow the load only if the chrome package is allowlisted.
   1108        nsCOMPtr<nsIXULChromeRegistry> reg(
   1109            do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
   1110        if (reg) {
   1111          bool accessAllowed = false;
   1112          reg->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
   1113          if (accessAllowed) {
   1114            return NS_OK;
   1115          }
   1116        }
   1117      } else if (targetScheme.EqualsLiteral("moz-page-thumb") ||
   1118                 targetScheme.EqualsLiteral("page-icon") ||
   1119                 targetScheme.EqualsLiteral("moz-newtab-wallpaper")) {
   1120        if (XRE_IsParentProcess()) {
   1121          return NS_OK;
   1122        }
   1123 
   1124        auto& remoteType = dom::ContentChild::GetSingleton()->GetRemoteType();
   1125        if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
   1126          return NS_OK;
   1127        }
   1128      }
   1129    }
   1130 
   1131    if (reportErrors) {
   1132      ReportError(errorTag, aSourceURI, aTargetURI, aFromPrivateWindow,
   1133                  aInnerWindowID);
   1134    }
   1135    return NS_ERROR_DOM_BAD_URI;
   1136  }
   1137 
   1138  // Check for target URI pointing to a file
   1139  bool targetURIIsLocalFile = false;
   1140  rv = NS_URIChainHasFlags(aTargetURI, nsIProtocolHandler::URI_IS_LOCAL_FILE,
   1141                           &targetURIIsLocalFile);
   1142  NS_ENSURE_SUCCESS(rv, rv);
   1143  if (targetURIIsLocalFile) {
   1144    // Allow domains that were allowlisted in the prefs. In 99.9% of cases,
   1145    // this array is empty.
   1146    bool isAllowlisted;
   1147    MOZ_ALWAYS_SUCCEEDS(InFileURIAllowlist(aSourceURI, &isAllowlisted));
   1148    if (isAllowlisted) {
   1149      return NS_OK;
   1150    }
   1151 
   1152    // Allow chrome://
   1153    if (aSourceBaseURI->SchemeIs("chrome")) {
   1154      return NS_OK;
   1155    }
   1156 
   1157    // Nothing else.
   1158    if (reportErrors) {
   1159      ReportError(errorTag, aSourceURI, aTargetURI, aFromPrivateWindow,
   1160                  aInnerWindowID);
   1161    }
   1162    return NS_ERROR_DOM_BAD_URI;
   1163  }
   1164 
   1165 #ifdef DEBUG
   1166  {
   1167    // Everyone is allowed to load this. The case URI_LOADABLE_BY_SUBSUMERS
   1168    // is handled by the caller which is just delegating to us as a helper.
   1169    bool hasSubsumersFlag = false;
   1170    NS_URIChainHasFlags(aTargetBaseURI,
   1171                        nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
   1172                        &hasSubsumersFlag);
   1173    bool hasLoadableByAnyone = false;
   1174    NS_URIChainHasFlags(aTargetBaseURI,
   1175                        nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
   1176                        &hasLoadableByAnyone);
   1177    MOZ_ASSERT(hasLoadableByAnyone || hasSubsumersFlag,
   1178               "why do we get here and do not have any of the two flags set?");
   1179  }
   1180 #endif
   1181 
   1182  return NS_OK;
   1183 }
   1184 
   1185 nsresult nsScriptSecurityManager::ReportError(const char* aMessageTag,
   1186                                              const nsACString& aSourceSpec,
   1187                                              const nsACString& aTargetSpec,
   1188                                              bool aFromPrivateWindow,
   1189                                              uint64_t aInnerWindowID) {
   1190  if (aSourceSpec.IsEmpty() || aTargetSpec.IsEmpty()) {
   1191    return NS_OK;
   1192  }
   1193 
   1194  nsCOMPtr<nsIStringBundle> bundle = BundleHelper::GetOrCreate();
   1195  if (NS_WARN_IF(!bundle)) {
   1196    return NS_OK;
   1197  }
   1198 
   1199  // Localize the error message
   1200  nsAutoString message;
   1201  AutoTArray<nsString, 2> formatStrings;
   1202  CopyASCIItoUTF16(aSourceSpec, *formatStrings.AppendElement());
   1203  CopyASCIItoUTF16(aTargetSpec, *formatStrings.AppendElement());
   1204  nsresult rv =
   1205      bundle->FormatStringFromName(aMessageTag, formatStrings, message);
   1206  NS_ENSURE_SUCCESS(rv, rv);
   1207 
   1208  nsCOMPtr<nsIConsoleService> console(
   1209      do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   1210  NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
   1211  nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
   1212  NS_ENSURE_TRUE(error, NS_ERROR_FAILURE);
   1213 
   1214  // using category of "SOP" so we can link to MDN
   1215  if (aInnerWindowID != 0) {
   1216    rv = error->InitWithWindowID(
   1217        message, ""_ns, 0, 0, nsIScriptError::errorFlag, "SOP"_ns,
   1218        aInnerWindowID, true /* From chrome context */);
   1219  } else {
   1220    rv = error->Init(message, ""_ns, 0, 0, nsIScriptError::errorFlag, "SOP"_ns,
   1221                     aFromPrivateWindow, true /* From chrome context */);
   1222  }
   1223  NS_ENSURE_SUCCESS(rv, rv);
   1224  console->LogMessage(error);
   1225  return NS_OK;
   1226 }
   1227 
   1228 nsresult nsScriptSecurityManager::ReportError(const char* aMessageTag,
   1229                                              nsIURI* aSource, nsIURI* aTarget,
   1230                                              bool aFromPrivateWindow,
   1231                                              uint64_t aInnerWindowID) {
   1232  NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
   1233 
   1234  // Get the source URL spec
   1235  nsAutoCString sourceSpec;
   1236  nsresult rv = aSource->GetAsciiSpec(sourceSpec);
   1237  NS_ENSURE_SUCCESS(rv, rv);
   1238 
   1239  // Get the target URL spec
   1240  nsAutoCString targetSpec;
   1241  rv = aTarget->GetAsciiSpec(targetSpec);
   1242  NS_ENSURE_SUCCESS(rv, rv);
   1243 
   1244  return ReportError(aMessageTag, sourceSpec, targetSpec, aFromPrivateWindow,
   1245                     aInnerWindowID);
   1246 }
   1247 
   1248 NS_IMETHODIMP
   1249 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(
   1250    nsIPrincipal* aPrincipal, const nsACString& aTargetURIStr,
   1251    uint32_t aFlags) {
   1252  nsresult rv;
   1253  nsCOMPtr<nsIURI> target;
   1254  rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr);
   1255  NS_ENSURE_SUCCESS(rv, rv);
   1256 
   1257  rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags, 0);
   1258  if (rv == NS_ERROR_DOM_BAD_URI) {
   1259    // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   1260    // return values.
   1261    return rv;
   1262  }
   1263  NS_ENSURE_SUCCESS(rv, rv);
   1264 
   1265  // Now start testing fixup -- since aTargetURIStr is a string, not
   1266  // an nsIURI, we may well end up fixing it up before loading.
   1267  // Note: This needs to stay in sync with the nsIURIFixup api.
   1268  nsCOMPtr<nsIURIFixup> fixup = components::URIFixup::Service();
   1269  if (!fixup) {
   1270    return rv;
   1271  }
   1272 
   1273  // URIFixup's keyword and alternate flags can only fixup to http/https, so we
   1274  // can skip testing them. This simplifies our life because this code can be
   1275  // invoked from the content process where the search service would not be
   1276  // available.
   1277  uint32_t flags[] = {nsIURIFixup::FIXUP_FLAG_NONE,
   1278                      nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS};
   1279  for (uint32_t i = 0; i < std::size(flags); ++i) {
   1280    uint32_t fixupFlags = flags[i];
   1281    if (aPrincipal->OriginAttributesRef().IsPrivateBrowsing()) {
   1282      fixupFlags |= nsIURIFixup::FIXUP_FLAG_PRIVATE_CONTEXT;
   1283    }
   1284    nsCOMPtr<nsIURIFixupInfo> fixupInfo;
   1285    rv = fixup->GetFixupURIInfo(aTargetURIStr, fixupFlags,
   1286                                getter_AddRefs(fixupInfo));
   1287    NS_ENSURE_SUCCESS(rv, rv);
   1288    rv = fixupInfo->GetPreferredURI(getter_AddRefs(target));
   1289    NS_ENSURE_SUCCESS(rv, rv);
   1290 
   1291    rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags, 0);
   1292    if (rv == NS_ERROR_DOM_BAD_URI) {
   1293      // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   1294      // return values.
   1295      return rv;
   1296    }
   1297    NS_ENSURE_SUCCESS(rv, rv);
   1298  }
   1299 
   1300  return rv;
   1301 }
   1302 
   1303 NS_IMETHODIMP
   1304 nsScriptSecurityManager::CheckLoadURIWithPrincipalFromJS(
   1305    nsIPrincipal* aPrincipal, nsIURI* aTargetURI, uint32_t aFlags,
   1306    uint64_t aInnerWindowID, JSContext* aCx) {
   1307  MOZ_ASSERT(aPrincipal,
   1308             "CheckLoadURIWithPrincipalFromJS must have a principal");
   1309  NS_ENSURE_ARG_POINTER(aPrincipal);
   1310  NS_ENSURE_ARG_POINTER(aTargetURI);
   1311 
   1312  nsresult rv =
   1313      CheckLoadURIWithPrincipal(aPrincipal, aTargetURI, aFlags, aInnerWindowID);
   1314  if (NS_FAILED(rv)) {
   1315    nsAutoCString uriStr;
   1316    (void)aTargetURI->GetSpec(uriStr);
   1317 
   1318    nsAutoCString message("Load of ");
   1319    message.Append(uriStr);
   1320 
   1321    nsAutoCString principalStr;
   1322    (void)aPrincipal->GetSpec(principalStr);
   1323    if (!principalStr.IsEmpty()) {
   1324      message.AppendPrintf(" from %s", principalStr.get());
   1325    }
   1326 
   1327    message.Append(" denied");
   1328 
   1329    dom::Throw(aCx, rv, message);
   1330  }
   1331 
   1332  return rv;
   1333 }
   1334 
   1335 NS_IMETHODIMP
   1336 nsScriptSecurityManager::CheckLoadURIStrWithPrincipalFromJS(
   1337    nsIPrincipal* aPrincipal, const nsACString& aTargetURIStr, uint32_t aFlags,
   1338    JSContext* aCx) {
   1339  nsCOMPtr<nsIURI> targetURI;
   1340  MOZ_TRY(NS_NewURI(getter_AddRefs(targetURI), aTargetURIStr));
   1341 
   1342  return CheckLoadURIWithPrincipalFromJS(aPrincipal, targetURI, aFlags, 0, aCx);
   1343 }
   1344 
   1345 NS_IMETHODIMP
   1346 nsScriptSecurityManager::InFileURIAllowlist(nsIURI* aUri, bool* aResult) {
   1347  MOZ_ASSERT(aUri);
   1348  MOZ_ASSERT(aResult);
   1349 
   1350  *aResult = false;
   1351  for (nsIURI* uri : EnsureFileURIAllowlist()) {
   1352    if (EqualOrSubdomain(aUri, uri)) {
   1353      *aResult = true;
   1354      return NS_OK;
   1355    }
   1356  }
   1357 
   1358  return NS_OK;
   1359 }
   1360 
   1361 ///////////////// Principals ///////////////////////
   1362 
   1363 NS_IMETHODIMP
   1364 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal** result) {
   1365  NS_ADDREF(*result = mSystemPrincipal);
   1366 
   1367  return NS_OK;
   1368 }
   1369 
   1370 NS_IMETHODIMP
   1371 nsScriptSecurityManager::CreateContentPrincipal(
   1372    nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
   1373    nsIPrincipal** aPrincipal) {
   1374  OriginAttributes attrs;
   1375  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1376    return NS_ERROR_INVALID_ARG;
   1377  }
   1378  nsCOMPtr<nsIPrincipal> prin =
   1379      BasePrincipal::CreateContentPrincipal(aURI, attrs);
   1380  prin.forget(aPrincipal);
   1381  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
   1382 }
   1383 
   1384 NS_IMETHODIMP
   1385 nsScriptSecurityManager::CreateContentPrincipalFromOrigin(
   1386    const nsACString& aOrigin, nsIPrincipal** aPrincipal) {
   1387  if (StringBeginsWith(aOrigin, "["_ns)) {
   1388    return NS_ERROR_INVALID_ARG;
   1389  }
   1390 
   1391  if (StringBeginsWith(aOrigin,
   1392                       nsLiteralCString(NS_NULLPRINCIPAL_SCHEME ":"))) {
   1393    return NS_ERROR_INVALID_ARG;
   1394  }
   1395 
   1396  nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateContentPrincipal(aOrigin);
   1397  prin.forget(aPrincipal);
   1398  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
   1399 }
   1400 
   1401 NS_IMETHODIMP
   1402 nsScriptSecurityManager::PrincipalToJSON(nsIPrincipal* aPrincipal,
   1403                                         nsACString& aJSON) {
   1404  aJSON.Truncate();
   1405  if (!aPrincipal) {
   1406    return NS_ERROR_FAILURE;
   1407  }
   1408 
   1409  BasePrincipal::Cast(aPrincipal)->ToJSON(aJSON);
   1410 
   1411  if (aJSON.IsEmpty()) {
   1412    return NS_ERROR_FAILURE;
   1413  }
   1414 
   1415  return NS_OK;
   1416 }
   1417 
   1418 NS_IMETHODIMP
   1419 nsScriptSecurityManager::JSONToPrincipal(const nsACString& aJSON,
   1420                                         nsIPrincipal** aPrincipal) {
   1421  if (aJSON.IsEmpty()) {
   1422    return NS_ERROR_FAILURE;
   1423  }
   1424 
   1425  nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(aJSON);
   1426 
   1427  if (!principal) {
   1428    return NS_ERROR_FAILURE;
   1429  }
   1430 
   1431  principal.forget(aPrincipal);
   1432  return NS_OK;
   1433 }
   1434 
   1435 NS_IMETHODIMP
   1436 nsScriptSecurityManager::CreateNullPrincipal(
   1437    JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
   1438    nsIPrincipal** aPrincipal) {
   1439  OriginAttributes attrs;
   1440  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1441    return NS_ERROR_INVALID_ARG;
   1442  }
   1443  nsCOMPtr<nsIPrincipal> prin = NullPrincipal::Create(attrs);
   1444  prin.forget(aPrincipal);
   1445  return NS_OK;
   1446 }
   1447 
   1448 NS_IMETHODIMP
   1449 nsScriptSecurityManager::GetLoadContextContentPrincipal(
   1450    nsIURI* aURI, nsILoadContext* aLoadContext, nsIPrincipal** aPrincipal) {
   1451  NS_ENSURE_STATE(aLoadContext);
   1452  OriginAttributes docShellAttrs;
   1453  aLoadContext->GetOriginAttributes(docShellAttrs);
   1454 
   1455  nsCOMPtr<nsIPrincipal> prin =
   1456      BasePrincipal::CreateContentPrincipal(aURI, docShellAttrs);
   1457  prin.forget(aPrincipal);
   1458  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
   1459 }
   1460 
   1461 NS_IMETHODIMP
   1462 nsScriptSecurityManager::GetDocShellContentPrincipal(
   1463    nsIURI* aURI, nsIDocShell* aDocShell, nsIPrincipal** aPrincipal) {
   1464  nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateContentPrincipal(
   1465      aURI, nsDocShell::Cast(aDocShell)->GetOriginAttributes());
   1466  prin.forget(aPrincipal);
   1467  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
   1468 }
   1469 
   1470 NS_IMETHODIMP
   1471 nsScriptSecurityManager::PrincipalWithOA(
   1472    nsIPrincipal* aPrincipal, JS::Handle<JS::Value> aOriginAttributes,
   1473    JSContext* aCx, nsIPrincipal** aReturnPrincipal) {
   1474  if (!aPrincipal) {
   1475    return NS_OK;
   1476  }
   1477  if (aPrincipal->GetIsContentPrincipal()) {
   1478    OriginAttributes attrs;
   1479    if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1480      return NS_ERROR_INVALID_ARG;
   1481    }
   1482    auto* contentPrincipal = static_cast<ContentPrincipal*>(aPrincipal);
   1483    RefPtr<ContentPrincipal> copy =
   1484        new ContentPrincipal(contentPrincipal, attrs);
   1485    NS_ENSURE_TRUE(copy, NS_ERROR_FAILURE);
   1486    copy.forget(aReturnPrincipal);
   1487  } else {
   1488    // We do this for null principals, system principals (both fine)
   1489    // ... and expanded principals, where we should probably do something
   1490    // cleverer, but I also don't think we care too much.
   1491    nsCOMPtr<nsIPrincipal> prin = aPrincipal;
   1492    prin.forget(aReturnPrincipal);
   1493  }
   1494 
   1495  return *aReturnPrincipal ? NS_OK : NS_ERROR_FAILURE;
   1496 }
   1497 
   1498 NS_IMETHODIMP
   1499 nsScriptSecurityManager::CanCreateWrapper(JSContext* cx, const nsIID& aIID,
   1500                                          nsISupports* aObj,
   1501                                          nsIClassInfo* aClassInfo) {
   1502  // XXX Special case for Exception ?
   1503 
   1504  // We give remote-XUL allowlisted domains a free pass here. See bug 932906.
   1505  JS::Rooted<JS::Realm*> contextRealm(cx, JS::GetCurrentRealmOrNull(cx));
   1506  MOZ_RELEASE_ASSERT(contextRealm);
   1507  if (!xpc::AllowContentXBLScope(contextRealm)) {
   1508    return NS_OK;
   1509  }
   1510 
   1511  if (nsContentUtils::IsCallerChrome()) {
   1512    return NS_OK;
   1513  }
   1514 
   1515  //-- Access denied, report an error
   1516  nsAutoCString originUTF8;
   1517  nsIPrincipal* subjectPrincipal = nsContentUtils::SubjectPrincipal();
   1518  GetPrincipalDomainOrigin(subjectPrincipal, originUTF8);
   1519  NS_ConvertUTF8toUTF16 originUTF16(originUTF8);
   1520  nsAutoCString classInfoNameUTF8;
   1521  if (aClassInfo) {
   1522    aClassInfo->GetClassDescription(classInfoNameUTF8);
   1523  }
   1524  if (classInfoNameUTF8.IsEmpty()) {
   1525    classInfoNameUTF8.AssignLiteral("UnnamedClass");
   1526  }
   1527 
   1528  nsCOMPtr<nsIStringBundle> bundle = BundleHelper::GetOrCreate();
   1529  if (NS_WARN_IF(!bundle)) {
   1530    return NS_OK;
   1531  }
   1532 
   1533  NS_ConvertUTF8toUTF16 classInfoUTF16(classInfoNameUTF8);
   1534  nsresult rv;
   1535  nsAutoString errorMsg;
   1536  if (originUTF16.IsEmpty()) {
   1537    AutoTArray<nsString, 1> formatStrings = {classInfoUTF16};
   1538    rv = bundle->FormatStringFromName("CreateWrapperDenied", formatStrings,
   1539                                      errorMsg);
   1540  } else {
   1541    AutoTArray<nsString, 2> formatStrings = {classInfoUTF16, originUTF16};
   1542    rv = bundle->FormatStringFromName("CreateWrapperDeniedForOrigin",
   1543                                      formatStrings, errorMsg);
   1544  }
   1545  NS_ENSURE_SUCCESS(rv, rv);
   1546 
   1547  SetPendingException(cx, errorMsg.get());
   1548  return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
   1549 }
   1550 
   1551 NS_IMETHODIMP
   1552 nsScriptSecurityManager::CanCreateInstance(JSContext* cx, const nsCID& aCID) {
   1553  if (nsContentUtils::IsCallerChrome()) {
   1554    return NS_OK;
   1555  }
   1556 
   1557  //-- Access denied, report an error
   1558  nsAutoCString errorMsg("Permission denied to create instance of class. CID=");
   1559  char cidStr[NSID_LENGTH];
   1560  aCID.ToProvidedString(cidStr);
   1561  errorMsg.Append(cidStr);
   1562  SetPendingExceptionASCII(cx, errorMsg.get());
   1563  return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
   1564 }
   1565 
   1566 NS_IMETHODIMP
   1567 nsScriptSecurityManager::CanGetService(JSContext* cx, const nsCID& aCID) {
   1568  if (nsContentUtils::IsCallerChrome()) {
   1569    return NS_OK;
   1570  }
   1571 
   1572  //-- Access denied, report an error
   1573  nsAutoCString errorMsg("Permission denied to get service. CID=");
   1574  char cidStr[NSID_LENGTH];
   1575  aCID.ToProvidedString(cidStr);
   1576  errorMsg.Append(cidStr);
   1577  SetPendingExceptionASCII(cx, errorMsg.get());
   1578  return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
   1579 }
   1580 
   1581 const char sJSEnabledPrefName[] = "javascript.enabled";
   1582 const char sFileOriginPolicyPrefName[] =
   1583    "security.fileuri.strict_origin_policy";
   1584 
   1585 static const char* kObservedPrefs[] = {sJSEnabledPrefName,
   1586                                       sFileOriginPolicyPrefName,
   1587                                       "capability.policy.", nullptr};
   1588 
   1589 /////////////////////////////////////////////
   1590 // Constructor, Destructor, Initialization //
   1591 /////////////////////////////////////////////
   1592 nsScriptSecurityManager::nsScriptSecurityManager(void)
   1593    : mPrefInitialized(false), mIsJavaScriptEnabled(false) {
   1594  static_assert(
   1595      sizeof(intptr_t) == sizeof(void*),
   1596      "intptr_t and void* have different lengths on this platform. "
   1597      "This may cause a security failure with the SecurityLevel union.");
   1598 }
   1599 
   1600 nsresult nsScriptSecurityManager::Init() {
   1601  nsresult rv;
   1602  RefPtr<nsIIOService> io = mozilla::components::IO::Service(&rv);
   1603  if (NS_FAILED(rv)) {
   1604    return rv;
   1605  }
   1606  sIOService = std::move(io);
   1607  InitPrefs();
   1608 
   1609  // Create our system principal singleton
   1610  mSystemPrincipal = SystemPrincipal::Init();
   1611 
   1612  return NS_OK;
   1613 }
   1614 
   1615 void nsScriptSecurityManager::InitJSCallbacks(JSContext* aCx) {
   1616  //-- Register security check callback in the JS engine
   1617  //   Currently this is used to control access to function.caller
   1618 
   1619  static const JSSecurityCallbacks securityCallbacks = {
   1620      ContentSecurityPolicyPermitsJSAction,
   1621      TrustedTypeUtils::HostGetCodeForEval,
   1622      JSPrincipalsSubsume,
   1623  };
   1624 
   1625  MOZ_ASSERT(!JS_GetSecurityCallbacks(aCx));
   1626  JS_SetSecurityCallbacks(aCx, &securityCallbacks);
   1627  JS_InitDestroyPrincipalsCallback(aCx, nsJSPrincipals::Destroy);
   1628 
   1629  JS_SetTrustedPrincipals(aCx, BasePrincipal::Cast(mSystemPrincipal));
   1630 }
   1631 
   1632 /* static */
   1633 void nsScriptSecurityManager::ClearJSCallbacks(JSContext* aCx) {
   1634  JS_SetSecurityCallbacks(aCx, nullptr);
   1635  JS_SetTrustedPrincipals(aCx, nullptr);
   1636 }
   1637 
   1638 static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
   1639 
   1640 nsScriptSecurityManager::~nsScriptSecurityManager(void) {
   1641  Preferences::UnregisterPrefixCallbacks(
   1642      nsScriptSecurityManager::ScriptSecurityPrefChanged, kObservedPrefs, this);
   1643  if (mDomainPolicy) {
   1644    mDomainPolicy->Deactivate();
   1645  }
   1646  // ContentChild might hold a reference to the domain policy,
   1647  // and it might release it only after the security manager is
   1648  // gone. But we can still assert this for the main process.
   1649  MOZ_ASSERT_IF(XRE_IsParentProcess(), !mDomainPolicy);
   1650 }
   1651 
   1652 void nsScriptSecurityManager::Shutdown() {
   1653  sIOService = nullptr;
   1654  BundleHelper::Shutdown();
   1655  SystemPrincipal::Shutdown();
   1656 }
   1657 
   1658 nsScriptSecurityManager* nsScriptSecurityManager::GetScriptSecurityManager() {
   1659  return gScriptSecMan;
   1660 }
   1661 
   1662 /* static */
   1663 void nsScriptSecurityManager::InitStatics() {
   1664  RefPtr<nsScriptSecurityManager> ssManager = new nsScriptSecurityManager();
   1665  nsresult rv = ssManager->Init();
   1666  if (NS_FAILED(rv)) {
   1667    MOZ_CRASH("ssManager->Init() failed");
   1668  }
   1669 
   1670  ClearOnShutdown(&gScriptSecMan);
   1671  gScriptSecMan = ssManager;
   1672 }
   1673 
   1674 // Currently this nsGenericFactory constructor is used only from FastLoad
   1675 // (XPCOM object deserialization) code, when "creating" the system principal
   1676 // singleton.
   1677 already_AddRefed<SystemPrincipal>
   1678 nsScriptSecurityManager::SystemPrincipalSingletonConstructor() {
   1679  if (gScriptSecMan)
   1680    return do_AddRef(gScriptSecMan->mSystemPrincipal)
   1681        .downcast<SystemPrincipal>();
   1682  return nullptr;
   1683 }
   1684 
   1685 struct IsWhitespace {
   1686  static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); };
   1687 };
   1688 struct IsWhitespaceOrComma {
   1689  static bool Test(char aChar) {
   1690    return aChar == ',' || NS_IsAsciiWhitespace(aChar);
   1691  };
   1692 };
   1693 
   1694 template <typename Predicate>
   1695 uint32_t SkipPast(const nsCString& str, uint32_t base) {
   1696  while (base < str.Length() && Predicate::Test(str[base])) {
   1697    ++base;
   1698  }
   1699  return base;
   1700 }
   1701 
   1702 template <typename Predicate>
   1703 uint32_t SkipUntil(const nsCString& str, uint32_t base) {
   1704  while (base < str.Length() && !Predicate::Test(str[base])) {
   1705    ++base;
   1706  }
   1707  return base;
   1708 }
   1709 
   1710 // static
   1711 void nsScriptSecurityManager::ScriptSecurityPrefChanged(const char* aPref,
   1712                                                        void* aSelf) {
   1713  static_cast<nsScriptSecurityManager*>(aSelf)->ScriptSecurityPrefChanged(
   1714      aPref);
   1715 }
   1716 
   1717 inline void nsScriptSecurityManager::ScriptSecurityPrefChanged(
   1718    const char* aPref) {
   1719  MOZ_ASSERT(mPrefInitialized);
   1720  mIsJavaScriptEnabled =
   1721      Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled);
   1722  sStrictFileOriginPolicy =
   1723      Preferences::GetBool(sFileOriginPolicyPrefName, false);
   1724  mFileURIAllowlist.reset();
   1725 }
   1726 
   1727 void nsScriptSecurityManager::AddSitesToFileURIAllowlist(
   1728    const nsCString& aSiteList) {
   1729  for (uint32_t base = SkipPast<IsWhitespace>(aSiteList, 0), bound = 0;
   1730       base < aSiteList.Length();
   1731       base = SkipPast<IsWhitespace>(aSiteList, bound)) {
   1732    // Grab the current site.
   1733    bound = SkipUntil<IsWhitespace>(aSiteList, base);
   1734    nsAutoCString site(Substring(aSiteList, base, bound - base));
   1735 
   1736    // Check if the URI is schemeless. If so, add both http and https.
   1737    nsAutoCString unused;
   1738    if (NS_FAILED(sIOService->ExtractScheme(site, unused))) {
   1739      AddSitesToFileURIAllowlist("http://"_ns + site);
   1740      AddSitesToFileURIAllowlist("https://"_ns + site);
   1741      continue;
   1742    }
   1743 
   1744    // Convert it to a URI and add it to our list.
   1745    nsCOMPtr<nsIURI> uri;
   1746    nsresult rv = NS_NewURI(getter_AddRefs(uri), site);
   1747    if (NS_SUCCEEDED(rv)) {
   1748      mFileURIAllowlist.ref().AppendElement(uri);
   1749    } else {
   1750      nsCOMPtr<nsIConsoleService> console(
   1751          do_GetService("@mozilla.org/consoleservice;1"));
   1752      if (console) {
   1753        nsAutoString msg =
   1754            u"Unable to to add site to file:// URI allowlist: "_ns +
   1755            NS_ConvertASCIItoUTF16(site);
   1756        console->LogStringMessage(msg.get());
   1757      }
   1758    }
   1759  }
   1760 }
   1761 
   1762 nsresult nsScriptSecurityManager::InitPrefs() {
   1763  nsIPrefBranch* branch = Preferences::GetRootBranch();
   1764  NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE);
   1765 
   1766  mPrefInitialized = true;
   1767 
   1768  // Set the initial value of the "javascript.enabled" prefs
   1769  ScriptSecurityPrefChanged();
   1770 
   1771  // set observer callbacks in case the value of the prefs change
   1772  Preferences::RegisterPrefixCallbacks(
   1773      nsScriptSecurityManager::ScriptSecurityPrefChanged, kObservedPrefs, this);
   1774 
   1775  return NS_OK;
   1776 }
   1777 
   1778 NS_IMETHODIMP
   1779 nsScriptSecurityManager::GetDomainPolicyActive(bool* aRv) {
   1780  *aRv = !!mDomainPolicy;
   1781  return NS_OK;
   1782 }
   1783 
   1784 NS_IMETHODIMP
   1785 nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv) {
   1786  if (!XRE_IsParentProcess()) {
   1787    return NS_ERROR_SERVICE_NOT_AVAILABLE;
   1788  }
   1789 
   1790  return ActivateDomainPolicyInternal(aRv);
   1791 }
   1792 
   1793 NS_IMETHODIMP
   1794 nsScriptSecurityManager::ActivateDomainPolicyInternal(nsIDomainPolicy** aRv) {
   1795  // We only allow one domain policy at a time. The holder of the previous
   1796  // policy must explicitly deactivate it first.
   1797  if (mDomainPolicy) {
   1798    return NS_ERROR_SERVICE_NOT_AVAILABLE;
   1799  }
   1800 
   1801  mDomainPolicy = new DomainPolicy();
   1802  nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
   1803  ptr.forget(aRv);
   1804  return NS_OK;
   1805 }
   1806 
   1807 // Intentionally non-scriptable. Script must have a reference to the
   1808 // nsIDomainPolicy to deactivate it.
   1809 void nsScriptSecurityManager::DeactivateDomainPolicy() {
   1810  mDomainPolicy = nullptr;
   1811 }
   1812 
   1813 void nsScriptSecurityManager::CloneDomainPolicy(DomainPolicyClone* aClone) {
   1814  MOZ_ASSERT(aClone);
   1815  if (mDomainPolicy) {
   1816    mDomainPolicy->CloneDomainPolicy(aClone);
   1817  } else {
   1818    aClone->active() = false;
   1819  }
   1820 }
   1821 
   1822 NS_IMETHODIMP
   1823 nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool* aRv) {
   1824  nsresult rv;
   1825 
   1826  // Compute our rule. If we don't have any domain policy set up that might
   1827  // provide exceptions to this rule, we're done.
   1828  *aRv = mIsJavaScriptEnabled;
   1829  if (!mDomainPolicy) {
   1830    return NS_OK;
   1831  }
   1832 
   1833  // We have a domain policy. Grab the appropriate set of exceptions to the
   1834  // rule (either the blocklist or the allowlist, depending on whether script
   1835  // is enabled or disabled by default).
   1836  nsCOMPtr<nsIDomainSet> exceptions;
   1837  nsCOMPtr<nsIDomainSet> superExceptions;
   1838  if (*aRv) {
   1839    mDomainPolicy->GetBlocklist(getter_AddRefs(exceptions));
   1840    mDomainPolicy->GetSuperBlocklist(getter_AddRefs(superExceptions));
   1841  } else {
   1842    mDomainPolicy->GetAllowlist(getter_AddRefs(exceptions));
   1843    mDomainPolicy->GetSuperAllowlist(getter_AddRefs(superExceptions));
   1844  }
   1845 
   1846  bool contains;
   1847  rv = exceptions->Contains(aURI, &contains);
   1848  NS_ENSURE_SUCCESS(rv, rv);
   1849  if (contains) {
   1850    *aRv = !*aRv;
   1851    return NS_OK;
   1852  }
   1853  rv = superExceptions->ContainsSuperDomain(aURI, &contains);
   1854  NS_ENSURE_SUCCESS(rv, rv);
   1855  if (contains) {
   1856    *aRv = !*aRv;
   1857  }
   1858 
   1859  return NS_OK;
   1860 }
   1861 
   1862 const nsTArray<nsCOMPtr<nsIURI>>&
   1863 nsScriptSecurityManager::EnsureFileURIAllowlist() {
   1864  if (mFileURIAllowlist.isSome()) {
   1865    return mFileURIAllowlist.ref();
   1866  }
   1867 
   1868  //
   1869  // Rebuild the set of principals for which we allow file:// URI loads. This
   1870  // implements a small subset of an old pref-based CAPS people that people
   1871  // have come to depend on. See bug 995943.
   1872  //
   1873 
   1874  mFileURIAllowlist.emplace();
   1875  nsAutoCString policies;
   1876  mozilla::Preferences::GetCString("capability.policy.policynames", policies);
   1877  for (uint32_t base = SkipPast<IsWhitespaceOrComma>(policies, 0), bound = 0;
   1878       base < policies.Length();
   1879       base = SkipPast<IsWhitespaceOrComma>(policies, bound)) {
   1880    // Grab the current policy name.
   1881    bound = SkipUntil<IsWhitespaceOrComma>(policies, base);
   1882    auto policyName = Substring(policies, base, bound - base);
   1883 
   1884    // Figure out if this policy allows loading file:// URIs. If not, we can
   1885    // skip it.
   1886    nsCString checkLoadURIPrefName =
   1887        "capability.policy."_ns + policyName + ".checkloaduri.enabled"_ns;
   1888    nsAutoString value;
   1889    nsresult rv = Preferences::GetString(checkLoadURIPrefName.get(), value);
   1890    if (NS_FAILED(rv) || !value.LowerCaseEqualsLiteral("allaccess")) {
   1891      continue;
   1892    }
   1893 
   1894    // Grab the list of domains associated with this policy.
   1895    nsCString domainPrefName =
   1896        "capability.policy."_ns + policyName + ".sites"_ns;
   1897    nsAutoCString siteList;
   1898    Preferences::GetCString(domainPrefName.get(), siteList);
   1899    AddSitesToFileURIAllowlist(siteList);
   1900  }
   1901 
   1902  return mFileURIAllowlist.ref();
   1903 }
   1904 
   1905 NS_IMETHODIMP
   1906 nsScriptSecurityManager::GetFirstUnexpectedJavaScriptLoad(
   1907    nsACString& aScriptFilename) {
   1908  aScriptFilename.Truncate();
   1909  return nsContentSecurityUtils::GetVeryFirstUnexpectedScriptFilename(
   1910      aScriptFilename);
   1911 }