LCOV - code coverage report
Current view: top level - caps - nsScriptSecurityManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 255 714 35.7 %
Date: 2017-07-14 16:53:18 Functions: 34 70 48.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: 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/ArrayUtils.h"
      10             : 
      11             : #include "xpcpublic.h"
      12             : #include "XPCWrapper.h"
      13             : #include "nsIInputStreamChannel.h"
      14             : #include "nsILoadContext.h"
      15             : #include "nsIServiceManager.h"
      16             : #include "nsIScriptObjectPrincipal.h"
      17             : #include "nsIScriptContext.h"
      18             : #include "nsIURL.h"
      19             : #include "nsINestedURI.h"
      20             : #include "nspr.h"
      21             : #include "nsJSPrincipals.h"
      22             : #include "mozilla/BasePrincipal.h"
      23             : #include "SystemPrincipal.h"
      24             : #include "NullPrincipal.h"
      25             : #include "DomainPolicy.h"
      26             : #include "nsXPIDLString.h"
      27             : #include "nsCRT.h"
      28             : #include "nsCRTGlue.h"
      29             : #include "nsDocShell.h"
      30             : #include "nsError.h"
      31             : #include "nsDOMCID.h"
      32             : #include "nsTextFormatter.h"
      33             : #include "nsIStringBundle.h"
      34             : #include "nsNetUtil.h"
      35             : #include "nsIEffectiveTLDService.h"
      36             : #include "nsIProperties.h"
      37             : #include "nsDirectoryServiceDefs.h"
      38             : #include "nsIFile.h"
      39             : #include "nsIFileURL.h"
      40             : #include "nsIZipReader.h"
      41             : #include "nsIScriptGlobalObject.h"
      42             : #include "nsPIDOMWindow.h"
      43             : #include "nsIDocShell.h"
      44             : #include "nsIPrompt.h"
      45             : #include "nsIWindowWatcher.h"
      46             : #include "nsIConsoleService.h"
      47             : #include "nsIObserverService.h"
      48             : #include "nsIContent.h"
      49             : #include "nsDOMJSUtils.h"
      50             : #include "nsAboutProtocolUtils.h"
      51             : #include "nsIClassInfo.h"
      52             : #include "nsIURIFixup.h"
      53             : #include "nsCDefaultURIFixup.h"
      54             : #include "nsIChromeRegistry.h"
      55             : #include "nsIContentSecurityPolicy.h"
      56             : #include "nsIAsyncVerifyRedirectCallback.h"
      57             : #include "mozilla/Preferences.h"
      58             : #include "mozilla/dom/BindingUtils.h"
      59             : #include <stdint.h>
      60             : #include "mozilla/dom/ScriptSettings.h"
      61             : #include "mozilla/ClearOnShutdown.h"
      62             : #include "mozilla/StaticPtr.h"
      63             : #include "nsContentUtils.h"
      64             : #include "nsJSUtils.h"
      65             : #include "nsILoadInfo.h"
      66             : #include "nsIDOMXULCommandDispatcher.h"
      67             : #include "nsITreeSelection.h"
      68             : 
      69             : // This should be probably defined on some other place... but I couldn't find it
      70             : #define WEBAPPS_PERM_NAME "webapps-manage"
      71             : 
      72             : using namespace mozilla;
      73             : using namespace mozilla::dom;
      74             : 
      75             : nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
      76             : nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr;
      77             : JSContext       *nsScriptSecurityManager::sContext   = nullptr;
      78             : bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
      79             : 
      80             : ///////////////////////////
      81             : // Convenience Functions //
      82             : ///////////////////////////
      83             : 
      84             : class nsAutoInPrincipalDomainOriginSetter {
      85             : public:
      86           0 :     nsAutoInPrincipalDomainOriginSetter() {
      87           0 :         ++sInPrincipalDomainOrigin;
      88           0 :     }
      89           0 :     ~nsAutoInPrincipalDomainOriginSetter() {
      90           0 :         --sInPrincipalDomainOrigin;
      91           0 :     }
      92             :     static uint32_t sInPrincipalDomainOrigin;
      93             : };
      94             : uint32_t nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
      95             : 
      96             : static
      97             : nsresult
      98           0 : GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin)
      99             : {
     100           0 :   if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
     101             :       // Allow a single recursive call to GetPrincipalDomainOrigin, since that
     102             :       // might be happening on a different principal from the first call.  But
     103             :       // after that, cut off the recursion; it just indicates that something
     104             :       // we're doing in this method causes us to reenter a security check here.
     105           0 :       return NS_ERROR_NOT_AVAILABLE;
     106             :   }
     107             : 
     108           0 :   nsAutoInPrincipalDomainOriginSetter autoSetter;
     109             : 
     110           0 :   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
     111           0 :   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
     112             : 
     113           0 :   nsAutoCString hostPort;
     114             : 
     115           0 :   nsresult rv = uri->GetHostPort(hostPort);
     116           0 :   if (NS_SUCCEEDED(rv)) {
     117           0 :     nsAutoCString scheme;
     118           0 :     rv = uri->GetScheme(scheme);
     119           0 :     NS_ENSURE_SUCCESS(rv, rv);
     120           0 :     aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
     121             :   }
     122             :   else {
     123             :     // Some URIs (e.g., nsSimpleURI) don't support host. Just
     124             :     // get the full spec.
     125           0 :     rv = uri->GetSpec(aOrigin);
     126           0 :     NS_ENSURE_SUCCESS(rv, rv);
     127             :   }
     128             : 
     129           0 :   return NS_OK;
     130             : }
     131             : 
     132             : static
     133             : nsresult
     134           0 : GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
     135             :                          nsACString& aOrigin)
     136             : {
     137             : 
     138           0 :   nsCOMPtr<nsIURI> uri;
     139           0 :   aPrincipal->GetDomain(getter_AddRefs(uri));
     140           0 :   if (!uri) {
     141           0 :     aPrincipal->GetURI(getter_AddRefs(uri));
     142             :   }
     143           0 :   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
     144             : 
     145           0 :   return GetOriginFromURI(uri, aOrigin);
     146             : }
     147             : 
     148           0 : inline void SetPendingExceptionASCII(JSContext *cx, const char *aMsg)
     149             : {
     150           0 :     JS_ReportErrorASCII(cx, "%s", aMsg);
     151           0 : }
     152             : 
     153           0 : inline void SetPendingException(JSContext *cx, const char16_t *aMsg)
     154             : {
     155           0 :     NS_ConvertUTF16toUTF8 msg(aMsg);
     156           0 :     JS_ReportErrorUTF8(cx, "%s", msg.get());
     157           0 : }
     158             : 
     159             : // Helper class to get stuff from the ClassInfo and not waste extra time with
     160             : // virtual method calls for things it has already gotten
     161             : class ClassInfoData
     162             : {
     163             : public:
     164        7695 :     ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
     165        7695 :         : mClassInfo(aClassInfo),
     166             :           mFlags(0),
     167             :           mName(const_cast<char *>(aName)),
     168             :           mDidGetFlags(false),
     169        7695 :           mMustFreeName(false)
     170             :     {
     171        7695 :     }
     172             : 
     173        7695 :     ~ClassInfoData()
     174        7695 :     {
     175        7695 :         if (mMustFreeName)
     176           0 :             free(mName);
     177        7695 :     }
     178             : 
     179        7695 :     uint32_t GetFlags()
     180             :     {
     181        7695 :         if (!mDidGetFlags) {
     182        7695 :             if (mClassInfo) {
     183        5889 :                 nsresult rv = mClassInfo->GetFlags(&mFlags);
     184        5889 :                 if (NS_FAILED(rv)) {
     185           0 :                     mFlags = 0;
     186             :                 }
     187             :             } else {
     188        1806 :                 mFlags = 0;
     189             :             }
     190             : 
     191        7695 :             mDidGetFlags = true;
     192             :         }
     193             : 
     194        7695 :         return mFlags;
     195             :     }
     196             : 
     197        7695 :     bool IsDOMClass()
     198             :     {
     199        7695 :         return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
     200             :     }
     201             : 
     202           0 :     const char* GetName()
     203             :     {
     204           0 :         if (!mName) {
     205           0 :             if (mClassInfo) {
     206           0 :                 mClassInfo->GetClassDescription(&mName);
     207             :             }
     208             : 
     209           0 :             if (mName) {
     210           0 :                 mMustFreeName = true;
     211             :             } else {
     212           0 :                 mName = const_cast<char *>("UnnamedClass");
     213             :             }
     214             :         }
     215             : 
     216           0 :         return mName;
     217             :     }
     218             : 
     219             : private:
     220             :     nsIClassInfo *mClassInfo; // WEAK
     221             :     uint32_t mFlags;
     222             :     char *mName;
     223             :     bool mDidGetFlags;
     224             :     bool mMustFreeName;
     225             : };
     226             : 
     227             : /* static */
     228             : bool
     229          89 : nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
     230             :                                              nsIURI* aTargetURI)
     231             : {
     232          89 :     return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
     233             : }
     234             : 
     235             : // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
     236             : // is consistent with NS_SecurityCompareURIs.  See nsNetUtil.h.
     237             : uint32_t
     238           0 : nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
     239             : {
     240           0 :     return NS_SecurityHashURI(aURI);
     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         120 : nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
     254             :                                                    nsIPrincipal** aPrincipal)
     255             : {
     256             :   return GetChannelResultPrincipal(aChannel, aPrincipal,
     257         120 :                                    /*aIgnoreSandboxing*/ false);
     258             : }
     259             : 
     260             : nsresult
     261           0 : nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(nsIChannel* aChannel,
     262             :                                                                  nsIPrincipal** aPrincipal)
     263             : {
     264             :   return GetChannelResultPrincipal(aChannel, aPrincipal,
     265           0 :                                    /*aIgnoreSandboxing*/ true);
     266             : }
     267             : 
     268             : nsresult
     269         120 : nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
     270             :                                                    nsIPrincipal** aPrincipal,
     271             :                                                    bool aIgnoreSandboxing)
     272             : {
     273         120 :   NS_PRECONDITION(aChannel, "Must have channel!");
     274             :   // Check whether we have an nsILoadInfo that says what we should do.
     275         240 :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     276         120 :   if (loadInfo && loadInfo->GetForceInheritPrincipalOverruleOwner()) {
     277           0 :     nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
     278           0 :     if (!principalToInherit) {
     279           0 :       principalToInherit = loadInfo->TriggeringPrincipal();
     280             :     }
     281           0 :     principalToInherit.forget(aPrincipal);
     282           0 :     return NS_OK;
     283             :   }
     284             : 
     285         240 :   nsCOMPtr<nsISupports> owner;
     286         120 :   aChannel->GetOwner(getter_AddRefs(owner));
     287         120 :   if (owner) {
     288          13 :     CallQueryInterface(owner, aPrincipal);
     289          13 :     if (*aPrincipal) {
     290          13 :       return NS_OK;
     291             :     }
     292             :   }
     293             : 
     294         107 :   if (loadInfo) {
     295         107 :         if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
     296           0 :           MOZ_ALWAYS_TRUE(NS_SUCCEEDED(loadInfo->GetSandboxedLoadingPrincipal(aPrincipal)));
     297           0 :           MOZ_ASSERT(*aPrincipal);
     298             :             // if the new NullPrincipal (above) loads an iframe[srcdoc], we
     299             :             // need to inherit an existing CSP to avoid bypasses (bug 1073952).
     300             :             // We continue inheriting for nested frames with e.g., data: URLs.
     301           0 :             if (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT) {
     302           0 :               nsCOMPtr<nsIURI> uri;
     303           0 :               aChannel->GetURI(getter_AddRefs(uri));
     304           0 :               nsAutoCString URISpec;
     305           0 :               uri->GetSpec(URISpec);
     306           0 :               bool isData = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData);
     307           0 :               if (URISpec.EqualsLiteral("about:srcdoc") || isData) {
     308           0 :                 nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
     309           0 :                 if (!principalToInherit) {
     310           0 :                   principalToInherit = loadInfo->TriggeringPrincipal();
     311             :                 }
     312           0 :                 nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
     313           0 :                 principalToInherit->GetCsp(getter_AddRefs(originalCSP));
     314           0 :                 if (originalCSP) {
     315             :                   // if the principalToInherit had a CSP,
     316             :                   // add it to the newly created NullPrincipal
     317             :                   // (unless it already has one)
     318           0 :                   nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
     319           0 :                   (*aPrincipal)->GetCsp(getter_AddRefs(nullPrincipalCSP));
     320           0 :                   if (nullPrincipalCSP) {
     321           0 :                     MOZ_ASSERT(nullPrincipalCSP == originalCSP,
     322             :                               "There should be no other CSP here.");
     323             :                     // CSPs are equal, no need to set it again.
     324           0 :                     return NS_OK;
     325             :                   } else {
     326           0 :                     nsresult rv = (*aPrincipal)->SetCsp(originalCSP);
     327           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     328             :                   }
     329             :                 }
     330             :               }
     331             :             }
     332           0 :           return NS_OK;
     333             :         }
     334             : 
     335         107 :     bool forceInherit = loadInfo->GetForceInheritPrincipal();
     336         107 :     if (aIgnoreSandboxing && !forceInherit) {
     337             :       // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of
     338             :       // sandboxing:
     339           0 :       if (loadInfo->GetLoadingSandboxed() &&
     340           0 :         loadInfo->GetForceInheritPrincipalDropped()) {
     341           0 :         forceInherit = true;
     342             :       }
     343             :     }
     344         107 :     if (forceInherit) {
     345           2 :       nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
     346           1 :       if (!principalToInherit) {
     347           0 :         principalToInherit = loadInfo->TriggeringPrincipal();
     348             :       }
     349           1 :       principalToInherit.forget(aPrincipal);
     350           1 :       return NS_OK;
     351             :     }
     352             : 
     353         106 :     auto securityMode = loadInfo->GetSecurityMode();
     354             :     // The data: inheritance flags should only apply to the initial load,
     355             :     // not to loads that it might have redirected to.
     356         196 :     if (loadInfo->RedirectChain().IsEmpty() &&
     357         106 :         (securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS ||
     358          16 :          securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS ||
     359             :          securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) {
     360             : 
     361         180 :       nsCOMPtr<nsIURI> uri;
     362          90 :       nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
     363          90 :       NS_ENSURE_SUCCESS(rv, rv);
     364         180 :       nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
     365          90 :       if (!principalToInherit) {
     366          90 :         principalToInherit = loadInfo->TriggeringPrincipal();
     367             :       }
     368          90 :       bool inheritForAboutBlank = loadInfo->GetAboutBlankInherits();
     369             : 
     370          90 :       if (nsContentUtils::ChannelShouldInheritPrincipal(principalToInherit,
     371             :                                                         uri,
     372             :                                                         inheritForAboutBlank,
     373             :                                                         false)) {
     374           0 :         principalToInherit.forget(aPrincipal);
     375           0 :         return NS_OK;
     376             :       }
     377             :     }
     378             :   }
     379         106 :   return GetChannelURIPrincipal(aChannel, aPrincipal);
     380             : }
     381             : 
     382             : /* The principal of the URI that this channel is loading. This is never
     383             :  * affected by things like sandboxed loads, or loads where we forcefully
     384             :  * inherit the principal.  Think of this as the principal of the server
     385             :  * which this channel is loading from.  Most callers should use
     386             :  * GetChannelResultPrincipal instead of GetChannelURIPrincipal.  Only
     387             :  * call GetChannelURIPrincipal if you are sure that you want the
     388             :  * principal that matches the uri, even in cases when the load is
     389             :  * sandboxed or when the load could be a blob or data uri (i.e even when
     390             :  * you encounter loads that may or may not be sandboxed and loads
     391             :  * that may or may not inherit)."
     392             :  */
     393             : NS_IMETHODIMP
     394         112 : nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
     395             :                                                 nsIPrincipal** aPrincipal)
     396             : {
     397         112 :     NS_PRECONDITION(aChannel, "Must have channel!");
     398             : 
     399             :     // Get the principal from the URI.  Make sure this does the same thing
     400             :     // as nsDocument::Reset and XULDocument::StartDocumentLoad.
     401         224 :     nsCOMPtr<nsIURI> uri;
     402         112 :     nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
     403         112 :     NS_ENSURE_SUCCESS(rv, rv);
     404             : 
     405         224 :     nsCOMPtr<nsILoadInfo> loadInfo;
     406         112 :     aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
     407             : 
     408             :     // Inherit the origin attributes from loadInfo.
     409             :     // If this is a top-level document load, the origin attributes of the
     410             :     // loadInfo will be set from nsDocShell::DoURILoad.
     411             :     // For subresource loading, the origin attributes of the loadInfo is from
     412             :     // its loadingPrincipal.
     413         224 :     OriginAttributes attrs;
     414             : 
     415             :     // For addons loadInfo might be null.
     416         112 :     if (loadInfo) {
     417         112 :       attrs = loadInfo->GetOriginAttributes();
     418             :     }
     419             : 
     420             :     nsCOMPtr<nsIPrincipal> prin =
     421         224 :       BasePrincipal::CreateCodebasePrincipal(uri, attrs);
     422         112 :     prin.forget(aPrincipal);
     423         112 :     return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
     424             : }
     425             : 
     426             : NS_IMETHODIMP
     427         804 : nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
     428             :                                            bool* aIsSystem)
     429             : {
     430         804 :     *aIsSystem = (aPrincipal == mSystemPrincipal);
     431         804 :     return NS_OK;
     432             : }
     433             : 
     434             : /////////////////////////////
     435             : // nsScriptSecurityManager //
     436             : /////////////////////////////
     437             : 
     438             : ////////////////////////////////////
     439             : // Methods implementing ISupports //
     440             : ////////////////////////////////////
     441        1819 : NS_IMPL_ISUPPORTS(nsScriptSecurityManager,
     442             :                   nsIScriptSecurityManager,
     443             :                   nsIObserver)
     444             : 
     445             : ///////////////////////////////////////////////////
     446             : // Methods implementing nsIScriptSecurityManager //
     447             : ///////////////////////////////////////////////////
     448             : 
     449             : ///////////////// Security Checks /////////////////
     450             : 
     451             : bool
     452           1 : nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
     453             : {
     454           1 :     MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
     455           2 :     nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
     456           2 :     nsCOMPtr<nsIContentSecurityPolicy> csp;
     457           1 :     nsresult rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
     458           1 :     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
     459             : 
     460             :     // don't do anything unless there's a CSP
     461           1 :     if (!csp)
     462           1 :         return true;
     463             : 
     464           0 :     bool evalOK = true;
     465           0 :     bool reportViolation = false;
     466           0 :     rv = csp->GetAllowsEval(&reportViolation, &evalOK);
     467             : 
     468           0 :     if (NS_FAILED(rv))
     469             :     {
     470           0 :         NS_WARNING("CSP: failed to get allowsEval");
     471           0 :         return true; // fail open to not break sites.
     472             :     }
     473             : 
     474           0 :     if (reportViolation) {
     475           0 :         nsAutoString fileName;
     476           0 :         unsigned lineNum = 0;
     477           0 :         NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
     478             : 
     479           0 :         JS::AutoFilename scriptFilename;
     480           0 :         if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
     481           0 :             if (const char *file = scriptFilename.get()) {
     482           0 :                 CopyUTF8toUTF16(nsDependentCString(file), fileName);
     483             :             }
     484             :         } else {
     485           0 :             MOZ_ASSERT(!JS_IsExceptionPending(cx));
     486             :         }
     487           0 :         csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
     488             :                                  fileName,
     489             :                                  scriptSample,
     490             :                                  lineNum,
     491           0 :                                  EmptyString(),
     492           0 :                                  EmptyString());
     493             :     }
     494             : 
     495           0 :     return evalOK;
     496             : }
     497             : 
     498             : // static
     499             : bool
     500          89 : nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first,
     501             :                                              JSPrincipals *second)
     502             : {
     503          89 :     return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
     504             : }
     505             : 
     506             : NS_IMETHODIMP
     507           0 : nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
     508             :                                             nsIURI* aTargetURI,
     509             :                                             bool reportError)
     510             : {
     511           0 :     if (!SecurityCompareURIs(aSourceURI, aTargetURI))
     512             :     {
     513           0 :          if (reportError) {
     514           0 :             ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"),
     515           0 :                      aSourceURI, aTargetURI);
     516             :          }
     517           0 :          return NS_ERROR_DOM_BAD_URI;
     518             :     }
     519           0 :     return NS_OK;
     520             : }
     521             : 
     522             : /*static*/ uint32_t
     523           0 : nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
     524             : {
     525           0 :     nsCOMPtr<nsIURI> uri;
     526           0 :     aPrincipal->GetDomain(getter_AddRefs(uri));
     527           0 :     if (!uri)
     528           0 :         aPrincipal->GetURI(getter_AddRefs(uri));
     529           0 :     return SecurityHashURI(uri);
     530             : }
     531             : 
     532             : NS_IMETHODIMP
     533           0 : nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
     534             : {
     535             :     // Get principal of currently executing script.
     536           0 :     MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
     537           0 :     nsIPrincipal* principal = nsContentUtils::SubjectPrincipal();
     538             :     nsresult rv = CheckLoadURIWithPrincipal(principal, aURI,
     539           0 :                                             nsIScriptSecurityManager::STANDARD);
     540           0 :     if (NS_SUCCEEDED(rv)) {
     541             :         // OK to load
     542           0 :         return NS_OK;
     543             :     }
     544             : 
     545             :     // Report error.
     546           0 :     nsAutoCString spec;
     547           0 :     if (NS_FAILED(aURI->GetAsciiSpec(spec)))
     548           0 :         return NS_ERROR_FAILURE;
     549           0 :     nsAutoCString msg("Access to '");
     550           0 :     msg.Append(spec);
     551           0 :     msg.AppendLiteral("' from script denied");
     552           0 :     SetPendingExceptionASCII(cx, msg.get());
     553           0 :     return NS_ERROR_DOM_BAD_URI;
     554             : }
     555             : 
     556             : /**
     557             :  * Helper method to handle cases where a flag passed to
     558             :  * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
     559             :  * nsIProtocolHandler flags set.
     560             :  * @return if success, access is allowed. Otherwise, deny access
     561             :  */
     562             : static nsresult
     563           2 : DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
     564             : {
     565           2 :     NS_PRECONDITION(aURI, "Must have URI!");
     566             : 
     567             :     bool uriHasFlags;
     568             :     nsresult rv =
     569           2 :         NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
     570           2 :     NS_ENSURE_SUCCESS(rv, rv);
     571             : 
     572           2 :     if (uriHasFlags) {
     573           0 :         return NS_ERROR_DOM_BAD_URI;
     574             :     }
     575             : 
     576           2 :     return NS_OK;
     577             : }
     578             : 
     579             : static bool
     580           0 : EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
     581             : {
     582             :     // Make a clone of the incoming URI, because we're going to mutate it.
     583           0 :     nsCOMPtr<nsIURI> probe;
     584           0 :     nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
     585           0 :     NS_ENSURE_SUCCESS(rv, false);
     586             : 
     587           0 :     nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
     588           0 :     NS_ENSURE_TRUE(tldService, false);
     589             :     while (true) {
     590           0 :         if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
     591           0 :             return true;
     592             :         }
     593             : 
     594           0 :         nsAutoCString host, newHost;
     595           0 :         rv = probe->GetHost(host);
     596           0 :         NS_ENSURE_SUCCESS(rv, false);
     597             : 
     598           0 :         rv = tldService->GetNextSubDomain(host, newHost);
     599           0 :         if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
     600           0 :             return false;
     601             :         }
     602           0 :         NS_ENSURE_SUCCESS(rv, false);
     603           0 :         rv = probe->SetHost(newHost);
     604           0 :         NS_ENSURE_SUCCESS(rv, false);
     605           0 :     }
     606             : }
     607             : 
     608             : NS_IMETHODIMP
     609          89 : nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
     610             :                                                    nsIURI *aTargetURI,
     611             :                                                    uint32_t aFlags)
     612             : {
     613          89 :     NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
     614             :     // If someone passes a flag that we don't understand, we should
     615             :     // fail, because they may need a security check that we don't
     616             :     // provide.
     617          89 :     NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
     618             :                                nsIScriptSecurityManager::ALLOW_CHROME |
     619             :                                nsIScriptSecurityManager::DISALLOW_SCRIPT |
     620             :                                nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
     621             :                                nsIScriptSecurityManager::DONT_REPORT_ERRORS),
     622             :                     NS_ERROR_UNEXPECTED);
     623          89 :     NS_ENSURE_ARG_POINTER(aPrincipal);
     624          89 :     NS_ENSURE_ARG_POINTER(aTargetURI);
     625             : 
     626             :     // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
     627             :     // would do such inheriting. That would be URIs that do not have their own
     628             :     // security context. We do this even for the system principal.
     629          89 :     if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
     630             :         nsresult rv =
     631             :             DenyAccessIfURIHasFlags(aTargetURI,
     632           0 :                                     nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
     633           0 :         NS_ENSURE_SUCCESS(rv, rv);
     634             :     }
     635             : 
     636          89 :     if (aPrincipal == mSystemPrincipal) {
     637             :         // Allow access
     638          43 :         return NS_OK;
     639             :     }
     640             : 
     641          92 :     nsCOMPtr<nsIURI> sourceURI;
     642          46 :     aPrincipal->GetURI(getter_AddRefs(sourceURI));
     643          46 :     if (!sourceURI) {
     644           0 :         nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aPrincipal);
     645           0 :         if (expanded) {
     646             :             nsTArray< nsCOMPtr<nsIPrincipal> > *whiteList;
     647           0 :             expanded->GetWhiteList(&whiteList);
     648           0 :             for (uint32_t i = 0; i < whiteList->Length(); ++i) {
     649           0 :                 nsresult rv = CheckLoadURIWithPrincipal((*whiteList)[i],
     650             :                                                         aTargetURI,
     651           0 :                                                         aFlags);
     652           0 :                 if (NS_SUCCEEDED(rv)) {
     653             :                     // Allow access if it succeeded with one of the white listed principals
     654           0 :                     return NS_OK;
     655             :                 }
     656             :             }
     657             :             // None of our whitelisted principals worked.
     658           0 :             return NS_ERROR_DOM_BAD_URI;
     659             :         }
     660           0 :         NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal "
     661             :                  "must have a URI!");
     662           0 :         return NS_ERROR_UNEXPECTED;
     663             :     }
     664             : 
     665             :     // Automatic loads are not allowed from certain protocols.
     666          46 :     if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
     667             :         nsresult rv =
     668           0 :             DenyAccessIfURIHasFlags(sourceURI,
     669           0 :                                     nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
     670           0 :         NS_ENSURE_SUCCESS(rv, rv);
     671             :     }
     672             : 
     673             :     // If either URI is a nested URI, get the base URI
     674          92 :     nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
     675          92 :     nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
     676             : 
     677             :     //-- get the target scheme
     678          92 :     nsAutoCString targetScheme;
     679          46 :     nsresult rv = targetBaseURI->GetScheme(targetScheme);
     680          46 :     if (NS_FAILED(rv)) return rv;
     681             : 
     682             :     //-- Some callers do not allow loading javascript:
     683          47 :     if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
     684           1 :          targetScheme.EqualsLiteral("javascript"))
     685             :     {
     686           0 :        return NS_ERROR_DOM_BAD_URI;
     687             :     }
     688             : 
     689             :     // Check for uris that are only loadable by principals that subsume them
     690             :     bool hasFlags;
     691          46 :     rv = NS_URIChainHasFlags(targetBaseURI,
     692             :                              nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
     693          46 :                              &hasFlags);
     694          46 :     NS_ENSURE_SUCCESS(rv, rv);
     695             : 
     696          46 :     if (hasFlags) {
     697             :         // check nothing else in the URI chain has flags that prevent
     698             :         // access:
     699           0 :         rv = CheckLoadURIFlags(sourceURI, aTargetURI, sourceBaseURI,
     700           0 :                                targetBaseURI, aFlags);
     701           0 :         NS_ENSURE_SUCCESS(rv, rv);
     702             :         // Check the principal is allowed to load the target.
     703           0 :         return aPrincipal->CheckMayLoad(targetBaseURI, true, false);
     704             :     }
     705             : 
     706             :     //-- get the source scheme
     707          92 :     nsAutoCString sourceScheme;
     708          46 :     rv = sourceBaseURI->GetScheme(sourceScheme);
     709          46 :     if (NS_FAILED(rv)) return rv;
     710             : 
     711             :     // When comparing schemes, if the relevant pref is set, view-source URIs
     712             :     // are reachable from same-protocol (so e.g. file: can link to
     713             :     // view-source:file). This is required for reftests.
     714             :     static bool sViewSourceReachableFromInner = false;
     715             :     static bool sCachedViewSourcePref = false;
     716          46 :     if (!sCachedViewSourcePref) {
     717           2 :         sCachedViewSourcePref = true;
     718             :         mozilla::Preferences::AddBoolVarCache(&sViewSourceReachableFromInner,
     719           2 :             "security.view-source.reachable-from-inner-protocol");
     720             :     }
     721             : 
     722          46 :     bool targetIsViewSource = false;
     723             : 
     724          46 :     if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
     725             :         // A null principal can target its own URI.
     726           0 :         if (sourceURI == aTargetURI) {
     727           0 :             return NS_OK;
     728             :         }
     729             :     }
     730          46 :     else if (sViewSourceReachableFromInner &&
     731           0 :              sourceScheme.EqualsIgnoreCase(targetScheme.get()) &&
     732          46 :              NS_SUCCEEDED(aTargetURI->SchemeIs("view-source", &targetIsViewSource)) &&
     733             :              targetIsViewSource)
     734             :     {
     735             :         // exception for foo: linking to view-source:foo for reftests...
     736           0 :         return NS_OK;
     737             :     }
     738             : 
     739             :     // If we get here, check all the schemes can link to each other, from the top down:
     740          46 :     nsCaseInsensitiveCStringComparator stringComparator;
     741          92 :     nsCOMPtr<nsIURI> currentURI = sourceURI;
     742          92 :     nsCOMPtr<nsIURI> currentOtherURI = aTargetURI;
     743             : 
     744          46 :     bool denySameSchemeLinks = false;
     745             :     rv = NS_URIChainHasFlags(aTargetURI, nsIProtocolHandler::URI_SCHEME_NOT_SELF_LINKABLE,
     746          46 :                              &denySameSchemeLinks);
     747          46 :     if (NS_FAILED(rv)) return rv;
     748             : 
     749          46 :     while (currentURI && currentOtherURI) {
     750          46 :         nsAutoCString scheme, otherScheme;
     751          46 :         currentURI->GetScheme(scheme);
     752          46 :         currentOtherURI->GetScheme(otherScheme);
     753             : 
     754          46 :         bool schemesMatch = scheme.Equals(otherScheme, stringComparator);
     755          46 :         bool isSamePage = false;
     756             :         // about: URIs are special snowflakes.
     757          46 :         if (scheme.EqualsLiteral("about") && schemesMatch) {
     758           0 :             nsAutoCString moduleName, otherModuleName;
     759             :             // about: pages can always link to themselves:
     760           0 :             isSamePage =
     761           0 :               NS_SUCCEEDED(NS_GetAboutModuleName(currentURI, moduleName)) &&
     762           0 :               NS_SUCCEEDED(NS_GetAboutModuleName(currentOtherURI, otherModuleName)) &&
     763           0 :               moduleName.Equals(otherModuleName);
     764           0 :             if (!isSamePage) {
     765             :                 // We will have allowed the load earlier if the source page has
     766             :                 // system principal. So we know the source has a content
     767             :                 // principal, and it's trying to link to something else.
     768             :                 // Linkable about: pages are always reachable, even if we hit
     769             :                 // the CheckLoadURIFlags call below.
     770             :                 // We punch only 1 other hole: iff the source is unlinkable,
     771             :                 // we let them link to other pages explicitly marked SAFE
     772             :                 // for content. This avoids world-linkable about: pages linking
     773             :                 // to non-world-linkable about: pages.
     774           0 :                 nsCOMPtr<nsIAboutModule> module, otherModule;
     775             :                 bool knowBothModules =
     776           0 :                     NS_SUCCEEDED(NS_GetAboutModule(currentURI, getter_AddRefs(module))) &&
     777           0 :                     NS_SUCCEEDED(NS_GetAboutModule(currentOtherURI, getter_AddRefs(otherModule)));
     778           0 :                 uint32_t aboutModuleFlags = 0;
     779           0 :                 uint32_t otherAboutModuleFlags = 0;
     780           0 :                 knowBothModules = knowBothModules &&
     781           0 :                     NS_SUCCEEDED(module->GetURIFlags(currentURI, &aboutModuleFlags)) &&
     782           0 :                     NS_SUCCEEDED(otherModule->GetURIFlags(currentOtherURI, &otherAboutModuleFlags));
     783           0 :                 if (knowBothModules) {
     784           0 :                     isSamePage =
     785           0 :                         !(aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) &&
     786           0 :                         (otherAboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT);
     787           0 :                     if (isSamePage && otherAboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
     788             :                         //XXXgijs: this is a hack. The target will be nested
     789             :                         // (with innerURI of moz-safe-about:whatever), and
     790             :                         // the source isn't, so we won't pass if we finish
     791             :                         // the loop. We *should* pass, though, so return here.
     792             :                         // This hack can go away when bug 1228118 is fixed.
     793           0 :                         return NS_OK;
     794             :                     }
     795             :                 }
     796             :             }
     797             :         } else {
     798          46 :             bool equalExceptRef = false;
     799          46 :             rv = currentURI->EqualsExceptRef(currentOtherURI, &equalExceptRef);
     800          46 :             isSamePage = NS_SUCCEEDED(rv) && equalExceptRef;
     801             :         }
     802             : 
     803             :         // If schemes are not equal, or they're equal but the target URI
     804             :         // is different from the source URI and doesn't always allow linking
     805             :         // from the same scheme, check if the URI flags of the current target
     806             :         // URI allow the current source URI to link to it.
     807             :         // The policy is specified by the protocol flags on both URIs.
     808          46 :         if (!schemesMatch || (denySameSchemeLinks && !isSamePage)) {
     809           2 :             return CheckLoadURIFlags(currentURI, currentOtherURI,
     810           2 :                                      sourceBaseURI, targetBaseURI, aFlags);
     811             :         }
     812             :         // Otherwise... check if we can nest another level:
     813          44 :         nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentURI);
     814          44 :         nsCOMPtr<nsINestedURI> nestedOtherURI = do_QueryInterface(currentOtherURI);
     815             : 
     816             :         // If schemes match and neither URI is nested further, we're OK.
     817          44 :         if (!nestedURI && !nestedOtherURI) {
     818          44 :             return NS_OK;
     819             :         }
     820             :         // If one is nested and the other isn't, something is wrong.
     821           0 :         if (!nestedURI != !nestedOtherURI) {
     822           0 :             return NS_ERROR_DOM_BAD_URI;
     823             :         }
     824             :         // Otherwise, both should be nested and we'll go through the loop again.
     825           0 :         nestedURI->GetInnerURI(getter_AddRefs(currentURI));
     826           0 :         nestedOtherURI->GetInnerURI(getter_AddRefs(currentOtherURI));
     827             :     }
     828             : 
     829             :     // We should never get here. We should always return from inside the loop.
     830           0 :     return NS_ERROR_DOM_BAD_URI;
     831             : }
     832             : 
     833             : /**
     834             :  * Helper method to check whether the target URI and its innermost ("base") URI
     835             :  * has protocol flags that should stop it from being loaded by the source URI
     836             :  * (and/or the source URI's innermost ("base") URI), taking into account any
     837             :  * nsIScriptSecurityManager flags originally passed to
     838             :  * CheckLoadURIWithPrincipal and friends.
     839             :  *
     840             :  * @return if success, access is allowed. Otherwise, deny access
     841             :  */
     842             : nsresult
     843           2 : nsScriptSecurityManager::CheckLoadURIFlags(nsIURI *aSourceURI,
     844             :                                            nsIURI *aTargetURI,
     845             :                                            nsIURI *aSourceBaseURI,
     846             :                                            nsIURI *aTargetBaseURI,
     847             :                                            uint32_t aFlags)
     848             : {
     849             :     // Note that the order of policy checks here is very important!
     850             :     // We start from most restrictive and work our way down.
     851           2 :     bool reportErrors = !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS);
     852           2 :     NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
     853             : 
     854           4 :     nsAutoCString targetScheme;
     855           2 :     nsresult rv = aTargetBaseURI->GetScheme(targetScheme);
     856           2 :     if (NS_FAILED(rv)) return rv;
     857             : 
     858             :     // Check for system target URI
     859             :     rv = DenyAccessIfURIHasFlags(aTargetURI,
     860           2 :                                  nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
     861           2 :     if (NS_FAILED(rv)) {
     862             :         // Deny access, since the origin principal is not system
     863           0 :         if (reportErrors) {
     864           0 :             ReportError(nullptr, errorTag, aSourceURI, aTargetURI);
     865             :         }
     866           0 :         return rv;
     867             :     }
     868             : 
     869             :     // Check for chrome target URI
     870           2 :     bool hasFlags = false;
     871             :     rv = NS_URIChainHasFlags(aTargetBaseURI,
     872             :                              nsIProtocolHandler::URI_IS_UI_RESOURCE,
     873           2 :                              &hasFlags);
     874           2 :     NS_ENSURE_SUCCESS(rv, rv);
     875           2 :     if (hasFlags) {
     876           2 :         if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
     877             : 
     878             :             // For now, don't change behavior for resource:// or moz-icon:// and
     879             :             // just allow them.
     880           2 :             if (!targetScheme.EqualsLiteral("chrome")) {
     881           2 :                 return NS_OK;
     882             :             }
     883             : 
     884             :             // Allow a URI_IS_UI_RESOURCE source to link to a URI_IS_UI_RESOURCE
     885             :             // target if ALLOW_CHROME is set.
     886             :             //
     887             :             // ALLOW_CHROME is a flag that we pass on all loads _except_ docshell
     888             :             // loads (since docshell loads run the loaded content with its origin
     889             :             // principal). So we're effectively allowing resource://, chrome://,
     890             :             // and moz-icon:// source URIs to load resource://, chrome://, and
     891             :             // moz-icon:// files, so long as they're not loading it as a document.
     892             :             bool sourceIsUIResource;
     893             :             rv = NS_URIChainHasFlags(aSourceBaseURI,
     894             :                                      nsIProtocolHandler::URI_IS_UI_RESOURCE,
     895           2 :                                      &sourceIsUIResource);
     896           2 :             NS_ENSURE_SUCCESS(rv, rv);
     897           2 :             if (sourceIsUIResource) {
     898           0 :                 return NS_OK;
     899             :             }
     900             : 
     901             :             // Allow the load only if the chrome package is whitelisted.
     902             :             nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
     903           2 :                                                  NS_CHROMEREGISTRY_CONTRACTID));
     904           2 :             if (reg) {
     905           2 :                 bool accessAllowed = false;
     906           2 :                 reg->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
     907           2 :                 if (accessAllowed) {
     908           2 :                     return NS_OK;
     909             :                 }
     910             :             }
     911             :         }
     912             : 
     913             :         static bool sCanLoadChromeInContent = false;
     914             :         static bool sCachedCanLoadChromeInContentPref = false;
     915           0 :         if (!sCachedCanLoadChromeInContentPref) {
     916           0 :             sCachedCanLoadChromeInContentPref = true;
     917             :             mozilla::Preferences::AddBoolVarCache(&sCanLoadChromeInContent,
     918           0 :                 "security.allow_chrome_frames_inside_content");
     919             :         }
     920           0 :         if (sCanLoadChromeInContent) {
     921             :             // Special-case the hidden window: it's allowed to load
     922             :             // URI_IS_UI_RESOURCE no matter what.  Bug 1145470 tracks removing this.
     923           0 :             nsAutoCString sourceSpec;
     924           0 :             if (NS_SUCCEEDED(aSourceBaseURI->GetSpec(sourceSpec)) &&
     925           0 :                 sourceSpec.EqualsLiteral("resource://gre-resources/hiddenWindow.html")) {
     926           0 :                 return NS_OK;
     927             :             }
     928             :         }
     929             : 
     930           0 :         if (reportErrors) {
     931           0 :             ReportError(nullptr, errorTag, aSourceURI, aTargetURI);
     932             :         }
     933           0 :         return NS_ERROR_DOM_BAD_URI;
     934             :     }
     935             : 
     936             :     // Check for target URI pointing to a file
     937             :     rv = NS_URIChainHasFlags(aTargetURI,
     938             :                              nsIProtocolHandler::URI_IS_LOCAL_FILE,
     939           0 :                              &hasFlags);
     940           0 :     NS_ENSURE_SUCCESS(rv, rv);
     941           0 :     if (hasFlags) {
     942             :         // Allow domains that were whitelisted in the prefs. In 99.9% of cases,
     943             :         // this array is empty.
     944           0 :         for (nsIURI* uri : EnsureFileURIWhitelist()) {
     945           0 :             if (EqualOrSubdomain(aSourceURI, uri)) {
     946           0 :                 return NS_OK;
     947             :             }
     948             :         }
     949             : 
     950             :         // Allow chrome://
     951           0 :         bool isChrome = false;
     952           0 :         if (NS_SUCCEEDED(aSourceBaseURI->SchemeIs("chrome", &isChrome)) && isChrome) {
     953           0 :             return NS_OK;
     954             :         }
     955             : 
     956             :         // Nothing else.
     957           0 :         if (reportErrors) {
     958           0 :             ReportError(nullptr, errorTag, aSourceURI, aTargetURI);
     959             :         }
     960           0 :         return NS_ERROR_DOM_BAD_URI;
     961             :     }
     962             : 
     963             :     // OK, everyone is allowed to load this, since unflagged handlers are
     964             :     // deprecated but treated as URI_LOADABLE_BY_ANYONE.  But check whether we
     965             :     // need to warn.  At some point we'll want to make this warning into an
     966             :     // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
     967             :     rv = NS_URIChainHasFlags(aTargetBaseURI,
     968             :                              nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
     969           0 :                              &hasFlags);
     970           0 :     NS_ENSURE_SUCCESS(rv, rv);
     971             :     // NB: we also get here if the base URI is URI_LOADABLE_BY_SUBSUMERS,
     972             :     // and none of the rest of the nested chain of URIs for aTargetURI
     973             :     // prohibits the load, so avoid warning in that case:
     974           0 :     bool hasSubsumersFlag = false;
     975             :     rv = NS_URIChainHasFlags(aTargetBaseURI,
     976             :                              nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
     977           0 :                              &hasSubsumersFlag);
     978           0 :     NS_ENSURE_SUCCESS(rv, rv);
     979           0 :     if (!hasFlags && !hasSubsumersFlag) {
     980           0 :         nsXPIDLString message;
     981           0 :         NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
     982           0 :         const char16_t* formatStrings[] = { ucsTargetScheme.get() };
     983             :         rv = sStrBundle->
     984           0 :             FormatStringFromName(u"ProtocolFlagError",
     985             :                                  formatStrings,
     986           0 :                                  ArrayLength(formatStrings),
     987           0 :                                  getter_Copies(message));
     988           0 :         if (NS_SUCCEEDED(rv)) {
     989             :             nsCOMPtr<nsIConsoleService> console(
     990           0 :               do_GetService("@mozilla.org/consoleservice;1"));
     991           0 :             NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
     992             : 
     993           0 :             console->LogStringMessage(message.get());
     994             :         }
     995             :     }
     996             : 
     997           0 :     return NS_OK;
     998             : }
     999             : 
    1000             : nsresult
    1001           0 : nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
    1002             :                                      nsIURI* aSource, nsIURI* aTarget)
    1003             : {
    1004             :     nsresult rv;
    1005           0 :     NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
    1006             : 
    1007             :     // Get the source URL spec
    1008           0 :     nsAutoCString sourceSpec;
    1009           0 :     rv = aSource->GetAsciiSpec(sourceSpec);
    1010           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1011             : 
    1012             :     // Get the target URL spec
    1013           0 :     nsAutoCString targetSpec;
    1014           0 :     rv = aTarget->GetAsciiSpec(targetSpec);
    1015           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1016             : 
    1017             :     // Localize the error message
    1018           0 :     nsXPIDLString message;
    1019           0 :     NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
    1020           0 :     NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
    1021           0 :     const char16_t *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
    1022           0 :     rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
    1023             :                                           formatStrings,
    1024           0 :                                           ArrayLength(formatStrings),
    1025           0 :                                           getter_Copies(message));
    1026           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1027             : 
    1028             :     // If a JS context was passed in, set a JS exception.
    1029             :     // Otherwise, print the error message directly to the JS console
    1030             :     // and to standard output
    1031           0 :     if (cx)
    1032             :     {
    1033           0 :         SetPendingException(cx, message.get());
    1034             :     }
    1035             :     else // Print directly to the console
    1036             :     {
    1037             :         nsCOMPtr<nsIConsoleService> console(
    1038           0 :             do_GetService("@mozilla.org/consoleservice;1"));
    1039           0 :         NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
    1040             : 
    1041           0 :         console->LogStringMessage(message.get());
    1042             :     }
    1043           0 :     return NS_OK;
    1044             : }
    1045             : 
    1046             : NS_IMETHODIMP
    1047           0 : nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
    1048             :                                                       const nsACString& aTargetURIStr,
    1049             :                                                       uint32_t aFlags)
    1050             : {
    1051             :     nsresult rv;
    1052           0 :     nsCOMPtr<nsIURI> target;
    1053           0 :     rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
    1054           0 :                    nullptr, nullptr, sIOService);
    1055           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1056             : 
    1057           0 :     rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
    1058           0 :     if (rv == NS_ERROR_DOM_BAD_URI) {
    1059             :         // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
    1060             :         // return values.
    1061           0 :         return rv;
    1062             :     }
    1063           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1064             : 
    1065             :     // Now start testing fixup -- since aTargetURIStr is a string, not
    1066             :     // an nsIURI, we may well end up fixing it up before loading.
    1067             :     // Note: This needs to stay in sync with the nsIURIFixup api.
    1068           0 :     nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
    1069           0 :     if (!fixup) {
    1070           0 :         return rv;
    1071             :     }
    1072             : 
    1073             :     uint32_t flags[] = {
    1074             :         nsIURIFixup::FIXUP_FLAG_NONE,
    1075             :         nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS,
    1076             :         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
    1077             :         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
    1078             :         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
    1079             :         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
    1080           0 :     };
    1081             : 
    1082           0 :     for (uint32_t i = 0; i < ArrayLength(flags); ++i) {
    1083           0 :         rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr,
    1084           0 :                                    getter_AddRefs(target));
    1085           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1086             : 
    1087           0 :         rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
    1088           0 :         if (rv == NS_ERROR_DOM_BAD_URI) {
    1089             :             // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
    1090             :             // return values.
    1091           0 :             return rv;
    1092             :         }
    1093           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1094             :     }
    1095             : 
    1096           0 :     return rv;
    1097             : }
    1098             : 
    1099             : ///////////////// Principals ///////////////////////
    1100             : 
    1101             : NS_IMETHODIMP
    1102         109 : nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
    1103             : {
    1104         109 :     NS_ADDREF(*result = mSystemPrincipal);
    1105             : 
    1106         109 :     return NS_OK;
    1107             : }
    1108             : 
    1109             : NS_IMETHODIMP
    1110           0 : nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI,
    1111             :                                               nsIPrincipal** aPrincipal)
    1112             : {
    1113           0 :   OriginAttributes attrs;
    1114             :   nsCOMPtr<nsIPrincipal> prin =
    1115           0 :     BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
    1116           0 :   prin.forget(aPrincipal);
    1117           0 :   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    1118             : }
    1119             : 
    1120             : NS_IMETHODIMP
    1121           0 : nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
    1122             :                                                  JSContext* aCx, nsIPrincipal** aPrincipal)
    1123             : {
    1124           0 :   OriginAttributes attrs;
    1125           0 :   if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    1126           0 :       return NS_ERROR_INVALID_ARG;
    1127             :   }
    1128           0 :   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
    1129           0 :   prin.forget(aPrincipal);
    1130           0 :   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    1131             : }
    1132             : 
    1133             : NS_IMETHODIMP
    1134           0 : nsScriptSecurityManager::CreateCodebasePrincipalFromOrigin(const nsACString& aOrigin,
    1135             :                                                            nsIPrincipal** aPrincipal)
    1136             : {
    1137           0 :   if (StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("["))) {
    1138           0 :     return NS_ERROR_INVALID_ARG;
    1139             :   }
    1140             : 
    1141           0 :   if (StringBeginsWith(aOrigin, NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":"))) {
    1142           0 :     return NS_ERROR_INVALID_ARG;
    1143             :   }
    1144             : 
    1145           0 :   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aOrigin);
    1146           0 :   prin.forget(aPrincipal);
    1147           0 :   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    1148             : }
    1149             : 
    1150             : NS_IMETHODIMP
    1151           0 : nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttributes,
    1152             :                                              JSContext* aCx, nsIPrincipal** aPrincipal)
    1153             : {
    1154           0 :   OriginAttributes attrs;
    1155           0 :   if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    1156           0 :       return NS_ERROR_INVALID_ARG;
    1157             :   }
    1158           0 :   nsCOMPtr<nsIPrincipal> prin = NullPrincipal::Create(attrs);
    1159           0 :   prin.forget(aPrincipal);
    1160           0 :   return NS_OK;
    1161             : }
    1162             : 
    1163             : NS_IMETHODIMP
    1164           3 : nsScriptSecurityManager::
    1165             :   GetLoadContextCodebasePrincipal(nsIURI* aURI,
    1166             :                                   nsILoadContext* aLoadContext,
    1167             :                                   nsIPrincipal** aPrincipal)
    1168             : {
    1169           3 :   NS_ENSURE_STATE(aLoadContext);
    1170           6 :   OriginAttributes docShellAttrs;
    1171           3 :   aLoadContext->GetOriginAttributes(docShellAttrs);
    1172             : 
    1173             :   nsCOMPtr<nsIPrincipal> prin =
    1174           6 :     BasePrincipal::CreateCodebasePrincipal(aURI, docShellAttrs);
    1175           3 :   prin.forget(aPrincipal);
    1176           3 :   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    1177             : }
    1178             : 
    1179             : NS_IMETHODIMP
    1180           1 : nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
    1181             :                                                       nsIDocShell* aDocShell,
    1182             :                                                       nsIPrincipal** aPrincipal)
    1183             : {
    1184             :   nsCOMPtr<nsIPrincipal> prin =
    1185           2 :     BasePrincipal::CreateCodebasePrincipal(aURI, nsDocShell::Cast(aDocShell)->GetOriginAttributes());
    1186           1 :   prin.forget(aPrincipal);
    1187           2 :   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
    1188             : }
    1189             : 
    1190             : // static
    1191             : nsIPrincipal*
    1192           0 : nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
    1193             : {
    1194           0 :     JSCompartment *compartment = js::GetObjectCompartment(aObj);
    1195           0 :     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
    1196           0 :     return nsJSPrincipals::get(principals);
    1197             : }
    1198             : 
    1199             : NS_IMETHODIMP
    1200        7695 : nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
    1201             :                                           const nsIID &aIID,
    1202             :                                           nsISupports *aObj,
    1203             :                                           nsIClassInfo *aClassInfo)
    1204             : {
    1205             : // XXX Special case for nsIXPCException ?
    1206       15390 :     ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nullptr);
    1207        7695 :     if (objClassInfo.IsDOMClass())
    1208             :     {
    1209        2400 :         return NS_OK;
    1210             :     }
    1211             : 
    1212             :     // We give remote-XUL whitelisted domains a free pass here. See bug 932906.
    1213        5295 :     JSCompartment* contextCompartment = js::GetContextCompartment(cx);
    1214        5295 :     if (!xpc::AllowContentXBLScope(contextCompartment))
    1215             :     {
    1216           0 :         return NS_OK;
    1217             :     }
    1218             : 
    1219        5295 :     if (nsContentUtils::IsCallerChrome())
    1220             :     {
    1221        5295 :         return NS_OK;
    1222             :     }
    1223             : 
    1224             :     // We want to expose nsIDOMXULCommandDispatcher and nsITreeSelection implementations
    1225             :     // in XBL scopes.
    1226           0 :     if (xpc::IsContentXBLScope(contextCompartment)) {
    1227           0 :       nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher = do_QueryInterface(aObj);
    1228           0 :       if (dispatcher) {
    1229           0 :         return NS_OK;
    1230             :       }
    1231             : 
    1232           0 :       nsCOMPtr<nsITreeSelection> treeSelection = do_QueryInterface(aObj);
    1233           0 :       if (treeSelection) {
    1234           0 :         return NS_OK;
    1235             :       }
    1236             :     }
    1237             : 
    1238             :     //-- Access denied, report an error
    1239           0 :     NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
    1240           0 :     nsAutoCString origin;
    1241           0 :     nsIPrincipal* subjectPrincipal = nsContentUtils::SubjectPrincipal();
    1242           0 :     GetPrincipalDomainOrigin(subjectPrincipal, origin);
    1243           0 :     NS_ConvertUTF8toUTF16 originUnicode(origin);
    1244           0 :     NS_ConvertUTF8toUTF16 classInfoName(objClassInfo.GetName());
    1245             :     const char16_t* formatStrings[] = {
    1246           0 :         classInfoName.get(),
    1247           0 :         originUnicode.get()
    1248           0 :     };
    1249           0 :     uint32_t length = ArrayLength(formatStrings);
    1250           0 :     if (originUnicode.IsEmpty()) {
    1251           0 :         --length;
    1252             :     } else {
    1253           0 :         strName.AppendLiteral("ForOrigin");
    1254             :     }
    1255           0 :     nsXPIDLString errorMsg;
    1256           0 :     nsresult rv = sStrBundle->FormatStringFromName(strName.get(),
    1257             :                                                    formatStrings,
    1258             :                                                    length,
    1259           0 :                                                    getter_Copies(errorMsg));
    1260           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1261             : 
    1262           0 :     SetPendingException(cx, errorMsg.get());
    1263           0 :     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
    1264             : }
    1265             : 
    1266             : NS_IMETHODIMP
    1267         419 : nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
    1268             :                                            const nsCID &aCID)
    1269             : {
    1270         419 :     if (nsContentUtils::IsCallerChrome()) {
    1271         419 :         return NS_OK;
    1272             :     }
    1273             : 
    1274             :     //-- Access denied, report an error
    1275           0 :     nsAutoCString errorMsg("Permission denied to create instance of class. CID=");
    1276             :     char cidStr[NSID_LENGTH];
    1277           0 :     aCID.ToProvidedString(cidStr);
    1278           0 :     errorMsg.Append(cidStr);
    1279           0 :     SetPendingExceptionASCII(cx, errorMsg.get());
    1280           0 :     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
    1281             : }
    1282             : 
    1283             : NS_IMETHODIMP
    1284           0 : nsScriptSecurityManager::CanGetService(JSContext *cx,
    1285             :                                        const nsCID &aCID)
    1286             : {
    1287           0 :     if (nsContentUtils::IsCallerChrome()) {
    1288           0 :         return NS_OK;
    1289             :     }
    1290             : 
    1291             :     //-- Access denied, report an error
    1292           0 :     nsAutoCString errorMsg("Permission denied to get service. CID=");
    1293             :     char cidStr[NSID_LENGTH];
    1294           0 :     aCID.ToProvidedString(cidStr);
    1295           0 :     errorMsg.Append(cidStr);
    1296           0 :     SetPendingExceptionASCII(cx, errorMsg.get());
    1297           0 :     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
    1298             : }
    1299             : 
    1300             : /////////////////////////////////////
    1301             : // Method implementing nsIObserver //
    1302             : /////////////////////////////////////
    1303             : const char sJSEnabledPrefName[] = "javascript.enabled";
    1304             : const char sFileOriginPolicyPrefName[] =
    1305             :     "security.fileuri.strict_origin_policy";
    1306             : 
    1307             : static const char* kObservedPrefs[] = {
    1308             :   sJSEnabledPrefName,
    1309             :   sFileOriginPolicyPrefName,
    1310             :   "capability.policy.",
    1311             :   nullptr
    1312             : };
    1313             : 
    1314             : 
    1315             : NS_IMETHODIMP
    1316           7 : nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
    1317             :                                  const char16_t* aMessage)
    1318             : {
    1319           7 :     ScriptSecurityPrefChanged();
    1320           7 :     return NS_OK;
    1321             : }
    1322             : 
    1323             : /////////////////////////////////////////////
    1324             : // Constructor, Destructor, Initialization //
    1325             : /////////////////////////////////////////////
    1326           3 : nsScriptSecurityManager::nsScriptSecurityManager(void)
    1327             :     : mPrefInitialized(false)
    1328           3 :     , mIsJavaScriptEnabled(false)
    1329             : {
    1330             :     static_assert(sizeof(intptr_t) == sizeof(void*),
    1331             :                   "intptr_t and void* have different lengths on this platform. "
    1332             :                   "This may cause a security failure with the SecurityLevel union.");
    1333           3 : }
    1334             : 
    1335           3 : nsresult nsScriptSecurityManager::Init()
    1336             : {
    1337           3 :     nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
    1338           3 :     NS_ENSURE_SUCCESS(rv, rv);
    1339             : 
    1340           3 :     InitPrefs();
    1341             : 
    1342             :     nsCOMPtr<nsIStringBundleService> bundleService =
    1343           6 :         mozilla::services::GetStringBundleService();
    1344           3 :     if (!bundleService)
    1345           0 :         return NS_ERROR_FAILURE;
    1346             : 
    1347           3 :     rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
    1348           3 :     NS_ENSURE_SUCCESS(rv, rv);
    1349             : 
    1350             :     // Create our system principal singleton
    1351           6 :     RefPtr<SystemPrincipal> system = SystemPrincipal::Create();
    1352             : 
    1353           3 :     mSystemPrincipal = system;
    1354             : 
    1355             :     //-- Register security check callback in the JS engine
    1356             :     //   Currently this is used to control access to function.caller
    1357           3 :     sContext = danger::GetJSContext();
    1358             : 
    1359             :     static const JSSecurityCallbacks securityCallbacks = {
    1360             :         ContentSecurityPolicyPermitsJSAction,
    1361             :         JSPrincipalsSubsume,
    1362             :     };
    1363             : 
    1364           3 :     MOZ_ASSERT(!JS_GetSecurityCallbacks(sContext));
    1365           3 :     JS_SetSecurityCallbacks(sContext, &securityCallbacks);
    1366           3 :     JS_InitDestroyPrincipalsCallback(sContext, nsJSPrincipals::Destroy);
    1367             : 
    1368           3 :     JS_SetTrustedPrincipals(sContext, system);
    1369             : 
    1370           3 :     return NS_OK;
    1371             : }
    1372             : 
    1373           3 : static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
    1374             : 
    1375           0 : nsScriptSecurityManager::~nsScriptSecurityManager(void)
    1376             : {
    1377           0 :     Preferences::RemoveObservers(this, kObservedPrefs);
    1378           0 :     if (mDomainPolicy) {
    1379           0 :         mDomainPolicy->Deactivate();
    1380             :     }
    1381             :     // ContentChild might hold a reference to the domain policy,
    1382             :     // and it might release it only after the security manager is
    1383             :     // gone. But we can still assert this for the main process.
    1384           0 :     MOZ_ASSERT_IF(XRE_IsParentProcess(),
    1385             :                   !mDomainPolicy);
    1386           0 : }
    1387             : 
    1388             : void
    1389           0 : nsScriptSecurityManager::Shutdown()
    1390             : {
    1391           0 :     if (sContext) {
    1392           0 :         JS_SetSecurityCallbacks(sContext, nullptr);
    1393           0 :         JS_SetTrustedPrincipals(sContext, nullptr);
    1394           0 :         sContext = nullptr;
    1395             :     }
    1396             : 
    1397           0 :     NS_IF_RELEASE(sIOService);
    1398           0 :     NS_IF_RELEASE(sStrBundle);
    1399           0 : }
    1400             : 
    1401             : nsScriptSecurityManager *
    1402           9 : nsScriptSecurityManager::GetScriptSecurityManager()
    1403             : {
    1404           9 :     return gScriptSecMan;
    1405             : }
    1406             : 
    1407             : /* static */ void
    1408           3 : nsScriptSecurityManager::InitStatics()
    1409             : {
    1410           6 :     RefPtr<nsScriptSecurityManager> ssManager = new nsScriptSecurityManager();
    1411           3 :     nsresult rv = ssManager->Init();
    1412           3 :     if (NS_FAILED(rv)) {
    1413           0 :         MOZ_CRASH("ssManager->Init() failed");
    1414             :     }
    1415             : 
    1416           3 :     ClearOnShutdown(&gScriptSecMan);
    1417           3 :     gScriptSecMan = ssManager;
    1418           3 : }
    1419             : 
    1420             : // Currently this nsGenericFactory constructor is used only from FastLoad
    1421             : // (XPCOM object deserialization) code, when "creating" the system principal
    1422             : // singleton.
    1423             : SystemPrincipal *
    1424          24 : nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
    1425             : {
    1426          24 :     nsIPrincipal *sysprin = nullptr;
    1427          24 :     if (gScriptSecMan)
    1428          24 :         NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
    1429          24 :     return static_cast<SystemPrincipal*>(sysprin);
    1430             : }
    1431             : 
    1432             : struct IsWhitespace {
    1433           0 :     static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); };
    1434             : };
    1435             : struct IsWhitespaceOrComma {
    1436           0 :     static bool Test(char aChar) { return aChar == ',' || NS_IsAsciiWhitespace(aChar); };
    1437             : };
    1438             : 
    1439             : template <typename Predicate>
    1440           0 : uint32_t SkipPast(const nsCString& str, uint32_t base)
    1441             : {
    1442           0 :     while (base < str.Length() && Predicate::Test(str[base])) {
    1443           0 :         ++base;
    1444             :     }
    1445           0 :     return base;
    1446             : }
    1447             : 
    1448             : template <typename Predicate>
    1449           0 : uint32_t SkipUntil(const nsCString& str, uint32_t base)
    1450             : {
    1451           0 :     while (base < str.Length() && !Predicate::Test(str[base])) {
    1452           0 :         ++base;
    1453             :     }
    1454           0 :     return base;
    1455             : }
    1456             : 
    1457             : inline void
    1458          10 : nsScriptSecurityManager::ScriptSecurityPrefChanged()
    1459             : {
    1460          10 :     MOZ_ASSERT(mPrefInitialized);
    1461          10 :     mIsJavaScriptEnabled =
    1462          10 :         Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled);
    1463          10 :     sStrictFileOriginPolicy =
    1464          10 :         Preferences::GetBool(sFileOriginPolicyPrefName, false);
    1465          10 :     mFileURIWhitelist.reset();
    1466          10 : }
    1467             : 
    1468             : void
    1469           0 : nsScriptSecurityManager::AddSitesToFileURIWhitelist(const nsCString& aSiteList)
    1470             : {
    1471           0 :     for (uint32_t base = SkipPast<IsWhitespace>(aSiteList, 0), bound = 0;
    1472           0 :          base < aSiteList.Length();
    1473             :          base = SkipPast<IsWhitespace>(aSiteList, bound))
    1474             :     {
    1475             :         // Grab the current site.
    1476           0 :         bound = SkipUntil<IsWhitespace>(aSiteList, base);
    1477           0 :         nsAutoCString site(Substring(aSiteList, base, bound - base));
    1478             : 
    1479             :         // Check if the URI is schemeless. If so, add both http and https.
    1480           0 :         nsAutoCString unused;
    1481           0 :         if (NS_FAILED(sIOService->ExtractScheme(site, unused))) {
    1482           0 :             AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("http://") + site);
    1483           0 :             AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("https://") + site);
    1484           0 :             continue;
    1485             :         }
    1486             : 
    1487             :         // Convert it to a URI and add it to our list.
    1488           0 :         nsCOMPtr<nsIURI> uri;
    1489           0 :         nsresult rv = NS_NewURI(getter_AddRefs(uri), site, nullptr, nullptr, sIOService);
    1490           0 :         if (NS_SUCCEEDED(rv)) {
    1491           0 :             mFileURIWhitelist.ref().AppendElement(uri);
    1492             :         } else {
    1493           0 :             nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1"));
    1494           0 :             if (console) {
    1495           0 :                 nsAutoString msg = NS_LITERAL_STRING("Unable to to add site to file:// URI whitelist: ") +
    1496           0 :                                    NS_ConvertASCIItoUTF16(site);
    1497           0 :                 console->LogStringMessage(msg.get());
    1498             :             }
    1499             :         }
    1500             :     }
    1501           0 : }
    1502             : 
    1503             : nsresult
    1504           3 : nsScriptSecurityManager::InitPrefs()
    1505             : {
    1506           3 :     nsIPrefBranch* branch = Preferences::GetRootBranch();
    1507           3 :     NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE);
    1508             : 
    1509           3 :     mPrefInitialized = true;
    1510             : 
    1511             :     // Set the initial value of the "javascript.enabled" prefs
    1512           3 :     ScriptSecurityPrefChanged();
    1513             : 
    1514             :     // set observer callbacks in case the value of the prefs change
    1515           3 :     Preferences::AddStrongObservers(this, kObservedPrefs);
    1516             : 
    1517           3 :     OriginAttributes::InitPrefs();
    1518             : 
    1519           3 :     return NS_OK;
    1520             : }
    1521             : 
    1522             : NS_IMETHODIMP
    1523           0 : nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
    1524             : {
    1525           0 :     *aRv = !!mDomainPolicy;
    1526           0 :     return NS_OK;
    1527             : }
    1528             : 
    1529             : NS_IMETHODIMP
    1530           0 : nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
    1531             : {
    1532           0 :     if (!XRE_IsParentProcess()) {
    1533           0 :         return NS_ERROR_SERVICE_NOT_AVAILABLE;
    1534             :     }
    1535             : 
    1536           0 :     return ActivateDomainPolicyInternal(aRv);
    1537             : }
    1538             : 
    1539             : NS_IMETHODIMP
    1540           0 : nsScriptSecurityManager::ActivateDomainPolicyInternal(nsIDomainPolicy** aRv)
    1541             : {
    1542             :     // We only allow one domain policy at a time. The holder of the previous
    1543             :     // policy must explicitly deactivate it first.
    1544           0 :     if (mDomainPolicy) {
    1545           0 :         return NS_ERROR_SERVICE_NOT_AVAILABLE;
    1546             :     }
    1547             : 
    1548           0 :     mDomainPolicy = new DomainPolicy();
    1549           0 :     nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
    1550           0 :     ptr.forget(aRv);
    1551           0 :     return NS_OK;
    1552             : }
    1553             : 
    1554             : // Intentionally non-scriptable. Script must have a reference to the
    1555             : // nsIDomainPolicy to deactivate it.
    1556             : void
    1557           0 : nsScriptSecurityManager::DeactivateDomainPolicy()
    1558             : {
    1559           0 :     mDomainPolicy = nullptr;
    1560           0 : }
    1561             : 
    1562             : void
    1563           2 : nsScriptSecurityManager::CloneDomainPolicy(DomainPolicyClone* aClone)
    1564             : {
    1565           2 :     MOZ_ASSERT(aClone);
    1566           2 :     if (mDomainPolicy) {
    1567           0 :         mDomainPolicy->CloneDomainPolicy(aClone);
    1568             :     } else {
    1569           2 :         aClone->active() = false;
    1570             :     }
    1571           2 : }
    1572             : 
    1573             : NS_IMETHODIMP
    1574          11 : nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
    1575             : {
    1576             :     nsresult rv;
    1577             : 
    1578             :     // Compute our rule. If we don't have any domain policy set up that might
    1579             :     // provide exceptions to this rule, we're done.
    1580          11 :     *aRv = mIsJavaScriptEnabled;
    1581          11 :     if (!mDomainPolicy) {
    1582          11 :         return NS_OK;
    1583             :     }
    1584             : 
    1585             :     // We have a domain policy. Grab the appropriate set of exceptions to the
    1586             :     // rule (either the blacklist or the whitelist, depending on whether script
    1587             :     // is enabled or disabled by default).
    1588           0 :     nsCOMPtr<nsIDomainSet> exceptions;
    1589           0 :     nsCOMPtr<nsIDomainSet> superExceptions;
    1590           0 :     if (*aRv) {
    1591           0 :         mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions));
    1592           0 :         mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions));
    1593             :     } else {
    1594           0 :         mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions));
    1595           0 :         mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions));
    1596             :     }
    1597             : 
    1598             :     bool contains;
    1599           0 :     rv = exceptions->Contains(aURI, &contains);
    1600           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1601           0 :     if (contains) {
    1602           0 :         *aRv = !*aRv;
    1603           0 :         return NS_OK;
    1604             :     }
    1605           0 :     rv = superExceptions->ContainsSuperDomain(aURI, &contains);
    1606           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1607           0 :     if (contains) {
    1608           0 :         *aRv = !*aRv;
    1609             :     }
    1610             : 
    1611           0 :     return NS_OK;
    1612             : }
    1613             : 
    1614             : const nsTArray<nsCOMPtr<nsIURI>>&
    1615           0 : nsScriptSecurityManager::EnsureFileURIWhitelist()
    1616             : {
    1617           0 :     if (mFileURIWhitelist.isSome()) {
    1618           0 :         return mFileURIWhitelist.ref();
    1619             :     }
    1620             : 
    1621             :     //
    1622             :     // Rebuild the set of principals for which we allow file:// URI loads. This
    1623             :     // implements a small subset of an old pref-based CAPS people that people
    1624             :     // have come to depend on. See bug 995943.
    1625             :     //
    1626             : 
    1627           0 :     mFileURIWhitelist.emplace();
    1628           0 :     auto policies = mozilla::Preferences::GetCString("capability.policy.policynames");
    1629           0 :     for (uint32_t base = SkipPast<IsWhitespaceOrComma>(policies, 0), bound = 0;
    1630           0 :          base < policies.Length();
    1631             :          base = SkipPast<IsWhitespaceOrComma>(policies, bound))
    1632             :     {
    1633             :         // Grab the current policy name.
    1634           0 :         bound = SkipUntil<IsWhitespaceOrComma>(policies, base);
    1635           0 :         auto policyName = Substring(policies, base, bound - base);
    1636             : 
    1637             :         // Figure out if this policy allows loading file:// URIs. If not, we can skip it.
    1638           0 :         nsCString checkLoadURIPrefName = NS_LITERAL_CSTRING("capability.policy.") +
    1639           0 :                                          policyName +
    1640           0 :                                          NS_LITERAL_CSTRING(".checkloaduri.enabled");
    1641           0 :         if (!Preferences::GetString(checkLoadURIPrefName.get()).LowerCaseEqualsLiteral("allaccess")) {
    1642           0 :             continue;
    1643             :         }
    1644             : 
    1645             :         // Grab the list of domains associated with this policy.
    1646           0 :         nsCString domainPrefName = NS_LITERAL_CSTRING("capability.policy.") +
    1647           0 :                                    policyName +
    1648           0 :                                    NS_LITERAL_CSTRING(".sites");
    1649           0 :         auto siteList = Preferences::GetCString(domainPrefName.get());
    1650           0 :         AddSitesToFileURIWhitelist(siteList);
    1651             :     }
    1652             : 
    1653           0 :     return mFileURIWhitelist.ref();
    1654           9 : }

Generated by: LCOV version 1.13