caps/src/nsScriptSecurityManager.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=4 et sw=4 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/. */
     7 #include "nsScriptSecurityManager.h"
     9 #include "mozilla/ArrayUtils.h"
    11 #include "js/OldDebugAPI.h"
    12 #include "xpcprivate.h"
    13 #include "XPCWrapper.h"
    14 #include "nsIServiceManager.h"
    15 #include "nsIScriptObjectPrincipal.h"
    16 #include "nsIScriptContext.h"
    17 #include "nsIURL.h"
    18 #include "nsINestedURI.h"
    19 #include "nspr.h"
    20 #include "nsJSPrincipals.h"
    21 #include "nsSystemPrincipal.h"
    22 #include "nsPrincipal.h"
    23 #include "nsNullPrincipal.h"
    24 #include "DomainPolicy.h"
    25 #include "nsXPIDLString.h"
    26 #include "nsCRT.h"
    27 #include "nsCRTGlue.h"
    28 #include "nsError.h"
    29 #include "nsDOMCID.h"
    30 #include "nsIXPConnect.h"
    31 #include "nsIXPCSecurityManager.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 "nsIXPConnect.h"
    42 #include "nsIScriptGlobalObject.h"
    43 #include "nsPIDOMWindow.h"
    44 #include "nsIDocShell.h"
    45 #include "nsIPrompt.h"
    46 #include "nsIWindowWatcher.h"
    47 #include "nsIConsoleService.h"
    48 #include "nsIJSRuntimeService.h"
    49 #include "nsIObserverService.h"
    50 #include "nsIContent.h"
    51 #include "nsAutoPtr.h"
    52 #include "nsDOMJSUtils.h"
    53 #include "nsAboutProtocolUtils.h"
    54 #include "nsIClassInfo.h"
    55 #include "nsIURIFixup.h"
    56 #include "nsCDefaultURIFixup.h"
    57 #include "nsIChromeRegistry.h"
    58 #include "nsIContentSecurityPolicy.h"
    59 #include "nsIAsyncVerifyRedirectCallback.h"
    60 #include "mozilla/Preferences.h"
    61 #include "mozilla/dom/BindingUtils.h"
    62 #include <stdint.h>
    63 #include "mozilla/ClearOnShutdown.h"
    64 #include "mozilla/StaticPtr.h"
    65 #include "nsContentUtils.h"
    66 #include "nsCxPusher.h"
    67 #include "nsJSUtils.h"
    69 // This should be probably defined on some other place... but I couldn't find it
    70 #define WEBAPPS_PERM_NAME "webapps-manage"
    72 using namespace mozilla;
    73 using namespace mozilla::dom;
    75 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
    77 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
    78 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr;
    79 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
    80 bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
    82 bool
    83 nsScriptSecurityManager::SubjectIsPrivileged()
    84 {
    85     JSContext *cx = GetCurrentJSContext();
    86     if (cx && xpc::IsUniversalXPConnectEnabled(cx))
    87         return true;
    88     bool isSystem = false;
    89     return NS_SUCCEEDED(SubjectPrincipalIsSystem(&isSystem)) && isSystem;
    90 }
    92 ///////////////////////////
    93 // Convenience Functions //
    94 ///////////////////////////
    95 // Result of this function should not be freed.
    96 static inline const char16_t *
    97 IDToString(JSContext *cx, jsid id_)
    98 {
    99     JS::RootedId id(cx, id_);
   100     if (JSID_IS_STRING(id))
   101         return JS_GetInternedStringChars(JSID_TO_STRING(id));
   103     JS::Rooted<JS::Value> idval(cx);
   104     if (!JS_IdToValue(cx, id, &idval))
   105         return nullptr;
   106     JSString *str = JS::ToString(cx, idval);
   107     if(!str)
   108         return nullptr;
   109     return JS_GetStringCharsZ(cx, str);
   110 }
   112 class nsAutoInPrincipalDomainOriginSetter {
   113 public:
   114     nsAutoInPrincipalDomainOriginSetter() {
   115         ++sInPrincipalDomainOrigin;
   116     }
   117     ~nsAutoInPrincipalDomainOriginSetter() {
   118         --sInPrincipalDomainOrigin;
   119     }
   120     static uint32_t sInPrincipalDomainOrigin;
   121 };
   122 uint32_t nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
   124 static
   125 nsresult
   126 GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin)
   127 {
   128   if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
   129       // Allow a single recursive call to GetPrincipalDomainOrigin, since that
   130       // might be happening on a different principal from the first call.  But
   131       // after that, cut off the recursion; it just indicates that something
   132       // we're doing in this method causes us to reenter a security check here.
   133       return NS_ERROR_NOT_AVAILABLE;
   134   }
   136   nsAutoInPrincipalDomainOriginSetter autoSetter;
   138   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
   139   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
   141   nsAutoCString hostPort;
   143   nsresult rv = uri->GetHostPort(hostPort);
   144   if (NS_SUCCEEDED(rv)) {
   145     nsAutoCString scheme;
   146     rv = uri->GetScheme(scheme);
   147     NS_ENSURE_SUCCESS(rv, rv);
   148     aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
   149   }
   150   else {
   151     // Some URIs (e.g., nsSimpleURI) don't support host. Just
   152     // get the full spec.
   153     rv = uri->GetSpec(aOrigin);
   154     NS_ENSURE_SUCCESS(rv, rv);
   155   }
   157   return NS_OK;
   158 }
   160 static
   161 nsresult
   162 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
   163                          nsACString& aOrigin)
   164 {
   166   nsCOMPtr<nsIURI> uri;
   167   aPrincipal->GetDomain(getter_AddRefs(uri));
   168   if (!uri) {
   169     aPrincipal->GetURI(getter_AddRefs(uri));
   170   }
   171   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
   173   return GetOriginFromURI(uri, aOrigin);
   174 }
   176 inline void SetPendingException(JSContext *cx, const char *aMsg)
   177 {
   178     JS_ReportError(cx, "%s", aMsg);
   179 }
   181 inline void SetPendingException(JSContext *cx, const char16_t *aMsg)
   182 {
   183     JS_ReportError(cx, "%hs", aMsg);
   184 }
   186 // Helper class to get stuff from the ClassInfo and not waste extra time with
   187 // virtual method calls for things it has already gotten
   188 class ClassInfoData
   189 {
   190 public:
   191     ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
   192         : mClassInfo(aClassInfo),
   193           mName(const_cast<char *>(aName)),
   194           mDidGetFlags(false),
   195           mMustFreeName(false)
   196     {
   197     }
   199     ~ClassInfoData()
   200     {
   201         if (mMustFreeName)
   202             nsMemory::Free(mName);
   203     }
   205     uint32_t GetFlags()
   206     {
   207         if (!mDidGetFlags) {
   208             if (mClassInfo) {
   209                 nsresult rv = mClassInfo->GetFlags(&mFlags);
   210                 if (NS_FAILED(rv)) {
   211                     mFlags = 0;
   212                 }
   213             } else {
   214                 mFlags = 0;
   215             }
   217             mDidGetFlags = true;
   218         }
   220         return mFlags;
   221     }
   223     bool IsDOMClass()
   224     {
   225         return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
   226     }
   228     const char* GetName()
   229     {
   230         if (!mName) {
   231             if (mClassInfo) {
   232                 mClassInfo->GetClassDescription(&mName);
   233             }
   235             if (mName) {
   236                 mMustFreeName = true;
   237             } else {
   238                 mName = const_cast<char *>("UnnamedClass");
   239             }
   240         }
   242         return mName;
   243     }
   245 private:
   246     nsIClassInfo *mClassInfo; // WEAK
   247     uint32_t mFlags;
   248     char *mName;
   249     bool mDidGetFlags;
   250     bool mMustFreeName;
   251 };
   253 JSContext *
   254 nsScriptSecurityManager::GetCurrentJSContext()
   255 {
   256     // Get JSContext from stack.
   257     return nsXPConnect::XPConnect()->GetCurrentJSContext();
   258 }
   260 JSContext *
   261 nsScriptSecurityManager::GetSafeJSContext()
   262 {
   263     // Get JSContext from stack.
   264     return nsXPConnect::XPConnect()->GetSafeJSContext();
   265 }
   267 /* static */
   268 bool
   269 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
   270                                              nsIURI* aTargetURI)
   271 {
   272     return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
   273 }
   275 // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
   276 // is consistent with NS_SecurityCompareURIs.  See nsNetUtil.h.
   277 uint32_t
   278 nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
   279 {
   280     return NS_SecurityHashURI(aURI);
   281 }
   283 NS_IMETHODIMP
   284 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
   285                                              nsIPrincipal** aPrincipal)
   286 {
   287     NS_PRECONDITION(aChannel, "Must have channel!");
   288     nsCOMPtr<nsISupports> owner;
   289     aChannel->GetOwner(getter_AddRefs(owner));
   290     if (owner) {
   291         CallQueryInterface(owner, aPrincipal);
   292         if (*aPrincipal) {
   293             return NS_OK;
   294         }
   295     }
   297     // OK, get the principal from the URI.  Make sure this does the same thing
   298     // as nsDocument::Reset and XULDocument::StartDocumentLoad.
   299     nsCOMPtr<nsIURI> uri;
   300     nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   301     NS_ENSURE_SUCCESS(rv, rv);
   303     nsCOMPtr<nsIDocShell> docShell;
   304     NS_QueryNotificationCallbacks(aChannel, docShell);
   306     if (docShell) {
   307         return GetDocShellCodebasePrincipal(uri, docShell, aPrincipal);
   308     }
   310     return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID,
   311         /* isInBrowserElement */ false, aPrincipal);
   312 }
   314 NS_IMETHODIMP
   315 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
   316                                            bool* aIsSystem)
   317 {
   318     *aIsSystem = (aPrincipal == mSystemPrincipal);
   319     return NS_OK;
   320 }
   322 NS_IMETHODIMP_(nsIPrincipal *)
   323 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
   324 {
   325     NS_ASSERTION(cx == GetCurrentJSContext(),
   326                  "Uh, cx is not the current JS context!");
   328     nsresult rv = NS_ERROR_FAILURE;
   329     nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
   330     if (NS_FAILED(rv))
   331         return nullptr;
   333     return principal;
   334 }
   336 /////////////////////////////
   337 // nsScriptSecurityManager //
   338 /////////////////////////////
   340 ////////////////////////////////////
   341 // Methods implementing ISupports //
   342 ////////////////////////////////////
   343 NS_IMPL_ISUPPORTS(nsScriptSecurityManager,
   344                   nsIScriptSecurityManager,
   345                   nsIXPCSecurityManager,
   346                   nsIChannelEventSink,
   347                   nsIObserver)
   349 ///////////////////////////////////////////////////
   350 // Methods implementing nsIScriptSecurityManager //
   351 ///////////////////////////////////////////////////
   353 ///////////////// Security Checks /////////////////
   355 bool
   356 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
   357 {
   358     // Get the security manager
   359     nsScriptSecurityManager *ssm =
   360         nsScriptSecurityManager::GetScriptSecurityManager();
   362     NS_ASSERTION(ssm, "Failed to get security manager service");
   363     if (!ssm)
   364         return false;
   366     nsresult rv;
   367     nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
   369     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
   370     if (NS_FAILED(rv))
   371         return false; // Not just absence of principal, but failure.
   373     if (!subjectPrincipal)
   374         return true;
   376     nsCOMPtr<nsIContentSecurityPolicy> csp;
   377     rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
   378     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
   380     // don't do anything unless there's a CSP
   381     if (!csp)
   382         return true;
   384     bool evalOK = true;
   385     bool reportViolation = false;
   386     rv = csp->GetAllowsEval(&reportViolation, &evalOK);
   388     if (NS_FAILED(rv))
   389     {
   390         NS_WARNING("CSP: failed to get allowsEval");
   391         return true; // fail open to not break sites.
   392     }
   394     if (reportViolation) {
   395         nsAutoString fileName;
   396         unsigned lineNum = 0;
   397         NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
   399         JS::AutoFilename scriptFilename;
   400         if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
   401             if (const char *file = scriptFilename.get()) {
   402                 CopyUTF8toUTF16(nsDependentCString(file), fileName);
   403             }
   404         }
   405         csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
   406                                  fileName,
   407                                  scriptSample,
   408                                  lineNum,
   409                                  EmptyString(),
   410                                  EmptyString());
   411     }
   413     return evalOK;
   414 }
   416 // static
   417 bool
   418 nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first,
   419                                              JSPrincipals *second)
   420 {
   421     return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
   422 }
   424 NS_IMETHODIMP
   425 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
   426                                          nsIURI* aTargetURI)
   427 {
   428     nsresult rv;
   430     // Get a context if necessary
   431     if (!cx)
   432     {
   433         cx = GetCurrentJSContext();
   434         if (!cx)
   435             return NS_OK; // No JS context, so allow access
   436     }
   438     // Get a principal from the context
   439     nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
   440     if (NS_FAILED(rv))
   441         return rv;
   443     if (!sourcePrincipal)
   444     {
   445         NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
   446         return NS_OK;
   447     }
   449     if (sourcePrincipal == mSystemPrincipal)
   450     {
   451         // This is a system (chrome) script, so allow access
   452         return NS_OK;
   453     }
   455     // Get the original URI from the source principal.
   456     // This has the effect of ignoring any change to document.domain
   457     // which must be done to avoid DNS spoofing (bug 154930)
   458     nsCOMPtr<nsIURI> sourceURI;
   459     sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
   460     if (!sourceURI) {
   461       sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
   462       NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
   463     }
   465     // Compare origins
   466     if (!SecurityCompareURIs(sourceURI, aTargetURI))
   467     {
   468          ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
   469          return NS_ERROR_DOM_BAD_URI;
   470     }
   471     return NS_OK;
   472 }
   474 NS_IMETHODIMP
   475 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
   476                                             nsIURI* aTargetURI,
   477                                             bool reportError)
   478 {
   479     if (!SecurityCompareURIs(aSourceURI, aTargetURI))
   480     {
   481          if (reportError) {
   482             ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"),
   483                      aSourceURI, aTargetURI);
   484          }
   485          return NS_ERROR_DOM_BAD_URI;
   486     }
   487     return NS_OK;
   488 }
   490 /*static*/ uint32_t
   491 nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
   492 {
   493     nsCOMPtr<nsIURI> uri;
   494     aPrincipal->GetDomain(getter_AddRefs(uri));
   495     if (!uri)
   496         aPrincipal->GetURI(getter_AddRefs(uri));
   497     return SecurityHashURI(uri);
   498 }
   500 /* static */ bool
   501 nsScriptSecurityManager::AppAttributesEqual(nsIPrincipal* aFirst,
   502                                             nsIPrincipal* aSecond)
   503 {
   504     MOZ_ASSERT(aFirst && aSecond, "Don't pass null pointers!");
   506     uint32_t firstAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   507     if (!aFirst->GetUnknownAppId()) {
   508         firstAppId = aFirst->GetAppId();
   509     }
   511     uint32_t secondAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   512     if (!aSecond->GetUnknownAppId()) {
   513         secondAppId = aSecond->GetAppId();
   514     }
   516     return ((firstAppId == secondAppId) &&
   517             (aFirst->GetIsInBrowserElement() == aSecond->GetIsInBrowserElement()));
   518 }
   520 NS_IMETHODIMP
   521 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
   522 {
   523     // Get principal of currently executing script.
   524     nsresult rv;
   525     nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
   526     if (NS_FAILED(rv))
   527         return rv;
   529     // Native code can load all URIs.
   530     if (!principal)
   531         return NS_OK;
   533     rv = CheckLoadURIWithPrincipal(principal, aURI,
   534                                    nsIScriptSecurityManager::STANDARD);
   535     if (NS_SUCCEEDED(rv)) {
   536         // OK to load
   537         return NS_OK;
   538     }
   540     // See if we're attempting to load a file: URI. If so, let a
   541     // UniversalXPConnect capability trump the above check.
   542     bool isFile = false;
   543     bool isRes = false;
   544     if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
   545         NS_FAILED(aURI->SchemeIs("resource", &isRes)))
   546         return NS_ERROR_FAILURE;
   547     if (isFile || isRes)
   548     {
   549         if (SubjectIsPrivileged())
   550             return NS_OK;
   551     }
   553     // Report error.
   554     nsAutoCString spec;
   555     if (NS_FAILED(aURI->GetAsciiSpec(spec)))
   556         return NS_ERROR_FAILURE;
   557     nsAutoCString msg("Access to '");
   558     msg.Append(spec);
   559     msg.AppendLiteral("' from script denied");
   560     SetPendingException(cx, msg.get());
   561     return NS_ERROR_DOM_BAD_URI;
   562 }
   564 /**
   565  * Helper method to handle cases where a flag passed to
   566  * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
   567  * nsIProtocolHandler flags set.
   568  * @return if success, access is allowed. Otherwise, deny access
   569  */
   570 static nsresult
   571 DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
   572 {
   573     NS_PRECONDITION(aURI, "Must have URI!");
   575     bool uriHasFlags;
   576     nsresult rv =
   577         NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
   578     NS_ENSURE_SUCCESS(rv, rv);
   580     if (uriHasFlags) {
   581         return NS_ERROR_DOM_BAD_URI;
   582     }
   584     return NS_OK;
   585 }
   587 static bool
   588 EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
   589 {
   590     // Make a clone of the incoming URI, because we're going to mutate it.
   591     nsCOMPtr<nsIURI> probe;
   592     nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
   593     NS_ENSURE_SUCCESS(rv, false);
   595     nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   596     NS_ENSURE_TRUE(tldService, false);
   597     while (true) {
   598         if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
   599             return true;
   600         }
   602         nsAutoCString host, newHost;
   603         nsresult rv = probe->GetHost(host);
   604         NS_ENSURE_SUCCESS(rv, false);
   606         rv = tldService->GetNextSubDomain(host, newHost);
   607         if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
   608             return false;
   609         }
   610         NS_ENSURE_SUCCESS(rv, false);
   611         rv = probe->SetHost(newHost);
   612         NS_ENSURE_SUCCESS(rv, false);
   613     }
   614 }
   616 NS_IMETHODIMP
   617 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
   618                                                    nsIURI *aTargetURI,
   619                                                    uint32_t aFlags)
   620 {
   621     NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
   622     // If someone passes a flag that we don't understand, we should
   623     // fail, because they may need a security check that we don't
   624     // provide.
   625     NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
   626                                nsIScriptSecurityManager::ALLOW_CHROME |
   627                                nsIScriptSecurityManager::DISALLOW_SCRIPT |
   628                                nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
   629                                nsIScriptSecurityManager::DONT_REPORT_ERRORS),
   630                     NS_ERROR_UNEXPECTED);
   631     NS_ENSURE_ARG_POINTER(aPrincipal);
   632     NS_ENSURE_ARG_POINTER(aTargetURI);
   634     // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
   635     // would do such inheriting. That would be URIs that do not have their own
   636     // security context. We do this even for the system principal.
   637     if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
   638         nsresult rv =
   639             DenyAccessIfURIHasFlags(aTargetURI,
   640                                     nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
   641         NS_ENSURE_SUCCESS(rv, rv);
   642     }
   644     if (aPrincipal == mSystemPrincipal) {
   645         // Allow access
   646         return NS_OK;
   647     }
   649     nsCOMPtr<nsIURI> sourceURI;
   650     aPrincipal->GetURI(getter_AddRefs(sourceURI));
   651     if (!sourceURI) {
   652         nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aPrincipal);
   653         if (expanded) {
   654             nsTArray< nsCOMPtr<nsIPrincipal> > *whiteList;
   655             expanded->GetWhiteList(&whiteList);
   656             for (uint32_t i = 0; i < whiteList->Length(); ++i) {
   657                 nsresult rv = CheckLoadURIWithPrincipal((*whiteList)[i],
   658                                                         aTargetURI,
   659                                                         aFlags);
   660                 if (NS_SUCCEEDED(rv)) {
   661                     // Allow access if it succeeded with one of the white listed principals
   662                     return NS_OK;
   663                 }
   664             }
   665             // None of our whitelisted principals worked.
   666             return NS_ERROR_DOM_BAD_URI;
   667         }
   668         NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal "
   669                  "must have a URI!");
   670         return NS_ERROR_UNEXPECTED;
   671     }
   673     // Automatic loads are not allowed from certain protocols.
   674     if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
   675         nsresult rv =
   676             DenyAccessIfURIHasFlags(sourceURI,
   677                                     nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
   678         NS_ENSURE_SUCCESS(rv, rv);
   679     }
   681     // If either URI is a nested URI, get the base URI
   682     nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
   683     nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
   685     //-- get the target scheme
   686     nsAutoCString targetScheme;
   687     nsresult rv = targetBaseURI->GetScheme(targetScheme);
   688     if (NS_FAILED(rv)) return rv;
   690     //-- Some callers do not allow loading javascript:
   691     if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
   692          targetScheme.EqualsLiteral("javascript"))
   693     {
   694        return NS_ERROR_DOM_BAD_URI;
   695     }
   697     NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
   698     bool reportErrors = !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS);
   700     // Check for uris that are only loadable by principals that subsume them
   701     bool hasFlags;
   702     rv = NS_URIChainHasFlags(targetBaseURI,
   703                              nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
   704                              &hasFlags);
   705     NS_ENSURE_SUCCESS(rv, rv);
   707     if (hasFlags) {
   708         return aPrincipal->CheckMayLoad(targetBaseURI, true, false);
   709     }
   711     //-- get the source scheme
   712     nsAutoCString sourceScheme;
   713     rv = sourceBaseURI->GetScheme(sourceScheme);
   714     if (NS_FAILED(rv)) return rv;
   716     if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
   717         // A null principal can target its own URI.
   718         if (sourceURI == aTargetURI) {
   719             return NS_OK;
   720         }
   721     }
   722     else if (targetScheme.Equals(sourceScheme,
   723                                  nsCaseInsensitiveCStringComparator()))
   724     {
   725         // every scheme can access another URI from the same scheme,
   726         // as long as they don't represent null principals...
   727         // Or they don't require an special permission to do so
   728         // See bug#773886
   730         bool hasFlags;
   731         rv = NS_URIChainHasFlags(targetBaseURI,
   732                                  nsIProtocolHandler::URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM,
   733                                  &hasFlags);
   734         NS_ENSURE_SUCCESS(rv, rv);
   736         if (hasFlags) {
   737             // In this case, we allow opening only if the source and target URIS
   738             // are on the same domain, or the opening URI has the webapps
   739             // permision granted
   740             if (!SecurityCompareURIs(sourceBaseURI,targetBaseURI) &&
   741                 !nsContentUtils::IsExactSitePermAllow(aPrincipal,WEBAPPS_PERM_NAME)){
   742                 return NS_ERROR_DOM_BAD_URI;
   743             }
   744         }
   745         return NS_OK;
   746     }
   748     // If the schemes don't match, the policy is specified by the protocol
   749     // flags on the target URI.  Note that the order of policy checks here is
   750     // very important!  We start from most restrictive and work our way down.
   751     // Note that since we're working with the innermost URI, we can just use
   752     // the methods that work on chains of nested URIs and they will only look
   753     // at the flags for our one URI.
   755     // Check for system target URI
   756     rv = DenyAccessIfURIHasFlags(targetBaseURI,
   757                                  nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
   758     if (NS_FAILED(rv)) {
   759         // Deny access, since the origin principal is not system
   760         if (reportErrors) {
   761             ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   762         }
   763         return rv;
   764     }
   766     // Check for chrome target URI
   767     rv = NS_URIChainHasFlags(targetBaseURI,
   768                              nsIProtocolHandler::URI_IS_UI_RESOURCE,
   769                              &hasFlags);
   770     NS_ENSURE_SUCCESS(rv, rv);
   771     if (hasFlags) {
   772         if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
   773             if (!targetScheme.EqualsLiteral("chrome")) {
   774                 // for now don't change behavior for resource: or moz-icon:
   775                 return NS_OK;
   776             }
   778             // allow load only if chrome package is whitelisted
   779             nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
   780                                                  NS_CHROMEREGISTRY_CONTRACTID));
   781             if (reg) {
   782                 bool accessAllowed = false;
   783                 reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
   784                 if (accessAllowed) {
   785                     return NS_OK;
   786                 }
   787             }
   788         }
   790         // resource: and chrome: are equivalent, securitywise
   791         // That's bogus!!  Fix this.  But watch out for
   792         // the view-source stylesheet?
   793         bool sourceIsChrome;
   794         rv = NS_URIChainHasFlags(sourceBaseURI,
   795                                  nsIProtocolHandler::URI_IS_UI_RESOURCE,
   796                                  &sourceIsChrome);
   797         NS_ENSURE_SUCCESS(rv, rv);
   798         if (sourceIsChrome) {
   799             return NS_OK;
   800         }
   801         if (reportErrors) {
   802             ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   803         }
   804         return NS_ERROR_DOM_BAD_URI;
   805     }
   807     // Check for target URI pointing to a file
   808     rv = NS_URIChainHasFlags(targetBaseURI,
   809                              nsIProtocolHandler::URI_IS_LOCAL_FILE,
   810                              &hasFlags);
   811     NS_ENSURE_SUCCESS(rv, rv);
   812     if (hasFlags) {
   813         // Allow domains that were whitelisted in the prefs. In 99.9% of cases,
   814         // this array is empty.
   815         for (size_t i = 0; i < mFileURIWhitelist.Length(); ++i) {
   816             if (EqualOrSubdomain(sourceURI, mFileURIWhitelist[i])) {
   817                 return NS_OK;
   818             }
   819         }
   821         // resource: and chrome: are equivalent, securitywise
   822         // That's bogus!!  Fix this.  But watch out for
   823         // the view-source stylesheet?
   824         bool sourceIsChrome;
   825         rv = NS_URIChainHasFlags(sourceURI,
   826                                  nsIProtocolHandler::URI_IS_UI_RESOURCE,
   827                                  &sourceIsChrome);
   828         NS_ENSURE_SUCCESS(rv, rv);
   829         if (sourceIsChrome) {
   830             return NS_OK;
   831         }
   833         if (reportErrors) {
   834             ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   835         }
   836         return NS_ERROR_DOM_BAD_URI;
   837     }
   839     // OK, everyone is allowed to load this, since unflagged handlers are
   840     // deprecated but treated as URI_LOADABLE_BY_ANYONE.  But check whether we
   841     // need to warn.  At some point we'll want to make this warning into an
   842     // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
   843     rv = NS_URIChainHasFlags(targetBaseURI,
   844                              nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
   845                              &hasFlags);
   846     NS_ENSURE_SUCCESS(rv, rv);
   847     if (!hasFlags) {
   848         nsXPIDLString message;
   849         NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
   850         const char16_t* formatStrings[] = { ucsTargetScheme.get() };
   851         rv = sStrBundle->
   852             FormatStringFromName(MOZ_UTF16("ProtocolFlagError"),
   853                                  formatStrings,
   854                                  ArrayLength(formatStrings),
   855                                  getter_Copies(message));
   856         if (NS_SUCCEEDED(rv)) {
   857             nsCOMPtr<nsIConsoleService> console(
   858               do_GetService("@mozilla.org/consoleservice;1"));
   859             NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
   861             console->LogStringMessage(message.get());
   862         }
   863     }
   865     return NS_OK;
   866 }
   868 nsresult
   869 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
   870                                      nsIURI* aSource, nsIURI* aTarget)
   871 {
   872     nsresult rv;
   873     NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
   875     // Get the source URL spec
   876     nsAutoCString sourceSpec;
   877     rv = aSource->GetAsciiSpec(sourceSpec);
   878     NS_ENSURE_SUCCESS(rv, rv);
   880     // Get the target URL spec
   881     nsAutoCString targetSpec;
   882     rv = aTarget->GetAsciiSpec(targetSpec);
   883     NS_ENSURE_SUCCESS(rv, rv);
   885     // Localize the error message
   886     nsXPIDLString message;
   887     NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
   888     NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
   889     const char16_t *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
   890     rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
   891                                           formatStrings,
   892                                           ArrayLength(formatStrings),
   893                                           getter_Copies(message));
   894     NS_ENSURE_SUCCESS(rv, rv);
   896     // If a JS context was passed in, set a JS exception.
   897     // Otherwise, print the error message directly to the JS console
   898     // and to standard output
   899     if (cx)
   900     {
   901         SetPendingException(cx, message.get());
   902     }
   903     else // Print directly to the console
   904     {
   905         nsCOMPtr<nsIConsoleService> console(
   906             do_GetService("@mozilla.org/consoleservice;1"));
   907         NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
   909         console->LogStringMessage(message.get());
   910     }
   911     return NS_OK;
   912 }
   914 NS_IMETHODIMP
   915 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
   916                                                       const nsACString& aTargetURIStr,
   917                                                       uint32_t aFlags)
   918 {
   919     nsresult rv;
   920     nsCOMPtr<nsIURI> target;
   921     rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
   922                    nullptr, nullptr, sIOService);
   923     NS_ENSURE_SUCCESS(rv, rv);
   925     rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
   926     if (rv == NS_ERROR_DOM_BAD_URI) {
   927         // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   928         // return values.
   929         return rv;
   930     }
   931     NS_ENSURE_SUCCESS(rv, rv);
   933     // Now start testing fixup -- since aTargetURIStr is a string, not
   934     // an nsIURI, we may well end up fixing it up before loading.
   935     // Note: This needs to stay in sync with the nsIURIFixup api.
   936     nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
   937     if (!fixup) {
   938         return rv;
   939     }
   941     uint32_t flags[] = {
   942         nsIURIFixup::FIXUP_FLAG_NONE,
   943         nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS,
   944         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
   945         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
   946         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
   947         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
   948     };
   950     for (uint32_t i = 0; i < ArrayLength(flags); ++i) {
   951         rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr,
   952                                    getter_AddRefs(target));
   953         NS_ENSURE_SUCCESS(rv, rv);
   955         rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
   956         if (rv == NS_ERROR_DOM_BAD_URI) {
   957             // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   958             // return values.
   959             return rv;
   960         }
   961         NS_ENSURE_SUCCESS(rv, rv);
   962     }
   964     return rv;
   965 }
   967 bool
   968 nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
   969 {
   970     MOZ_ASSERT(aGlobal);
   971     MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal));
   972     AutoJSContext cx;
   973     JS::RootedObject global(cx, js::UncheckedUnwrap(aGlobal, /* stopAtOuter = */ false));
   975     // Check the bits on the compartment private.
   976     return xpc::Scriptability::Get(aGlobal).Allowed();
   977 }
   979 ///////////////// Principals ///////////////////////
   980 NS_IMETHODIMP
   981 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
   982 {
   983     nsresult rv;
   984     *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
   985     if (NS_SUCCEEDED(rv))
   986         NS_IF_ADDREF(*aSubjectPrincipal);
   987     return rv;
   988 }
   990 nsIPrincipal*
   991 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
   992 {
   993     NS_PRECONDITION(rv, "Null out param");
   994     JSContext *cx = GetCurrentJSContext();
   995     if (!cx)
   996     {
   997         *rv = NS_OK;
   998         return nullptr;
   999     }
  1000     return GetSubjectPrincipal(cx, rv);
  1003 NS_IMETHODIMP
  1004 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
  1006     NS_ADDREF(*result = mSystemPrincipal);
  1008     return NS_OK;
  1011 NS_IMETHODIMP
  1012 nsScriptSecurityManager::SubjectPrincipalIsSystem(bool* aIsSystem)
  1014     NS_ENSURE_ARG_POINTER(aIsSystem);
  1015     *aIsSystem = false;
  1017     if (!mSystemPrincipal)
  1018         return NS_OK;
  1020     nsCOMPtr<nsIPrincipal> subject;
  1021     nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
  1022     if (NS_FAILED(rv))
  1023         return rv;
  1025     if(!subject)
  1027         // No subject principal means no JS is running;
  1028         // this is the equivalent of system principal code
  1029         *aIsSystem = true;
  1030         return NS_OK;
  1033     return mSystemPrincipal->Equals(subject, aIsSystem);
  1036 nsresult
  1037 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId,
  1038                                                  bool aInMozBrowser,
  1039                                                  nsIPrincipal **result)
  1041     // I _think_ it's safe to not create null principals here based on aURI.
  1042     // At least all the callers would do the right thing in those cases, as far
  1043     // as I can tell.  --bz
  1045     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
  1046     if (uriPrinc) {
  1047         nsCOMPtr<nsIPrincipal> principal;
  1048         uriPrinc->GetPrincipal(getter_AddRefs(principal));
  1049         if (!principal || principal == mSystemPrincipal) {
  1050             return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
  1053         principal.forget(result);
  1055         return NS_OK;
  1058     nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
  1059     if (!codebase)
  1060         return NS_ERROR_OUT_OF_MEMORY;
  1062     nsresult rv = codebase->Init(aURI, aAppId, aInMozBrowser);
  1063     if (NS_FAILED(rv))
  1064         return rv;
  1066     NS_ADDREF(*result = codebase);
  1068     return NS_OK;
  1071 NS_IMETHODIMP
  1072 nsScriptSecurityManager::GetSimpleCodebasePrincipal(nsIURI* aURI,
  1073                                                     nsIPrincipal** aPrincipal)
  1075   return GetCodebasePrincipalInternal(aURI,
  1076                                       nsIScriptSecurityManager::UNKNOWN_APP_ID,
  1077                                       false, aPrincipal);
  1080 NS_IMETHODIMP
  1081 nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI,
  1082                                                    nsIPrincipal** aPrincipal)
  1084   return GetCodebasePrincipalInternal(aURI,  nsIScriptSecurityManager::NO_APP_ID,
  1085                                       false, aPrincipal);
  1088 NS_IMETHODIMP
  1089 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI,
  1090                                               nsIPrincipal** aPrincipal)
  1092   return GetNoAppCodebasePrincipal(aURI, aPrincipal);
  1095 NS_IMETHODIMP
  1096 nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
  1097                                                  uint32_t aAppId,
  1098                                                  bool aInMozBrowser,
  1099                                                  nsIPrincipal** aPrincipal)
  1101   NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
  1102                  NS_ERROR_INVALID_ARG);
  1104   return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal);
  1107 NS_IMETHODIMP
  1108 nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
  1109                                                       nsIDocShell* aDocShell,
  1110                                                       nsIPrincipal** aPrincipal)
  1112   return GetCodebasePrincipalInternal(aURI,
  1113                                       aDocShell->GetAppId(),
  1114                                       aDocShell->GetIsInBrowserElement(),
  1115                                       aPrincipal);
  1118 nsresult
  1119 nsScriptSecurityManager::GetCodebasePrincipalInternal(nsIURI *aURI,
  1120                                                       uint32_t aAppId,
  1121                                                       bool aInMozBrowser,
  1122                                                       nsIPrincipal **result)
  1124     NS_ENSURE_ARG(aURI);
  1126     bool inheritsPrincipal;
  1127     nsresult rv =
  1128         NS_URIChainHasFlags(aURI,
  1129                             nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
  1130                             &inheritsPrincipal);
  1131     if (NS_FAILED(rv) || inheritsPrincipal) {
  1132         return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
  1135     nsCOMPtr<nsIPrincipal> principal;
  1136     rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser,
  1137                                  getter_AddRefs(principal));
  1138     NS_ENSURE_SUCCESS(rv, rv);
  1139     NS_IF_ADDREF(*result = principal);
  1141     return NS_OK;
  1144 nsIPrincipal*
  1145 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
  1146                                              nsresult* rv)
  1148     *rv = NS_OK;
  1149     JSCompartment *compartment = js::GetContextCompartment(cx);
  1151     // The context should always be in a compartment, either one it has entered
  1152     // or the one associated with its global.
  1153     MOZ_ASSERT(!!compartment);
  1155     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
  1156     return nsJSPrincipals::get(principals);
  1159 // static
  1160 nsIPrincipal*
  1161 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
  1163     JSCompartment *compartment = js::GetObjectCompartment(aObj);
  1164     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
  1165     return nsJSPrincipals::get(principals);
  1168 ////////////////////////////////////////////////
  1169 // Methods implementing nsIXPCSecurityManager //
  1170 ////////////////////////////////////////////////
  1172 NS_IMETHODIMP
  1173 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
  1174                                           const nsIID &aIID,
  1175                                           nsISupports *aObj,
  1176                                           nsIClassInfo *aClassInfo)
  1178 // XXX Special case for nsIXPCException ?
  1179     ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nullptr);
  1180     if (objClassInfo.IsDOMClass())
  1182         return NS_OK;
  1185     // We give remote-XUL whitelisted domains a free pass here. See bug 932906.
  1186     if (!xpc::AllowXBLScope(js::GetContextCompartment(cx)))
  1188         return NS_OK;
  1191     if (SubjectIsPrivileged())
  1193         return NS_OK;
  1196     //-- Access denied, report an error
  1197     NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
  1198     nsAutoCString origin;
  1199     nsresult rv2;
  1200     nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2);
  1201     if (NS_SUCCEEDED(rv2) && subjectPrincipal) {
  1202         GetPrincipalDomainOrigin(subjectPrincipal, origin);
  1204     NS_ConvertUTF8toUTF16 originUnicode(origin);
  1205     NS_ConvertUTF8toUTF16 classInfoName(objClassInfo.GetName());
  1206     const char16_t* formatStrings[] = {
  1207         classInfoName.get(),
  1208         originUnicode.get()
  1209     };
  1210     uint32_t length = ArrayLength(formatStrings);
  1211     if (originUnicode.IsEmpty()) {
  1212         --length;
  1213     } else {
  1214         strName.AppendLiteral("ForOrigin");
  1216     nsXPIDLString errorMsg;
  1217     // We need to keep our existing failure rv and not override it
  1218     // with a likely success code from the following string bundle
  1219     // call in order to throw the correct security exception later.
  1220     rv2 = sStrBundle->FormatStringFromName(strName.get(),
  1221                                            formatStrings,
  1222                                            length,
  1223                                            getter_Copies(errorMsg));
  1224     NS_ENSURE_SUCCESS(rv2, rv2);
  1226     SetPendingException(cx, errorMsg.get());
  1227     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1230 NS_IMETHODIMP
  1231 nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
  1232                                            const nsCID &aCID)
  1234     if (SubjectIsPrivileged()) {
  1235         return NS_OK;
  1238     //-- Access denied, report an error
  1239     nsAutoCString errorMsg("Permission denied to create instance of class. CID=");
  1240     char cidStr[NSID_LENGTH];
  1241     aCID.ToProvidedString(cidStr);
  1242     errorMsg.Append(cidStr);
  1243     SetPendingException(cx, errorMsg.get());
  1244     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1247 NS_IMETHODIMP
  1248 nsScriptSecurityManager::CanGetService(JSContext *cx,
  1249                                        const nsCID &aCID)
  1251     if (SubjectIsPrivileged()) {
  1252         return NS_OK;
  1255     //-- Access denied, report an error
  1256     nsAutoCString errorMsg("Permission denied to get service. CID=");
  1257     char cidStr[NSID_LENGTH];
  1258     aCID.ToProvidedString(cidStr);
  1259     errorMsg.Append(cidStr);
  1260     SetPendingException(cx, errorMsg.get());
  1261     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1264 /////////////////////////////////////////////
  1265 // Method implementing nsIChannelEventSink //
  1266 /////////////////////////////////////////////
  1267 NS_IMETHODIMP
  1268 nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel, 
  1269                                                 nsIChannel* newChannel,
  1270                                                 uint32_t redirFlags,
  1271                                                 nsIAsyncVerifyRedirectCallback *cb)
  1273     nsCOMPtr<nsIPrincipal> oldPrincipal;
  1274     GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
  1276     nsCOMPtr<nsIURI> newURI;
  1277     newChannel->GetURI(getter_AddRefs(newURI));
  1278     nsCOMPtr<nsIURI> newOriginalURI;
  1279     newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
  1281     NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
  1283     const uint32_t flags =
  1284         nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
  1285         nsIScriptSecurityManager::DISALLOW_SCRIPT;
  1286     nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
  1287     if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
  1288         rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
  1291     if (NS_FAILED(rv))
  1292         return rv;
  1294     cb->OnRedirectVerifyCallback(NS_OK);
  1295     return NS_OK;
  1299 /////////////////////////////////////
  1300 // Method implementing nsIObserver //
  1301 /////////////////////////////////////
  1302 const char sJSEnabledPrefName[] = "javascript.enabled";
  1303 const char sFileOriginPolicyPrefName[] =
  1304     "security.fileuri.strict_origin_policy";
  1306 static const char* kObservedPrefs[] = {
  1307   sJSEnabledPrefName,
  1308   sFileOriginPolicyPrefName,
  1309   "capability.policy.",
  1310   nullptr
  1311 };
  1314 NS_IMETHODIMP
  1315 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
  1316                                  const char16_t* aMessage)
  1318     ScriptSecurityPrefChanged();
  1319     return NS_OK;
  1322 /////////////////////////////////////////////
  1323 // Constructor, Destructor, Initialization //
  1324 /////////////////////////////////////////////
  1325 nsScriptSecurityManager::nsScriptSecurityManager(void)
  1326     : mPrefInitialized(false)
  1327     , mIsJavaScriptEnabled(false)
  1329     static_assert(sizeof(intptr_t) == sizeof(void*),
  1330                   "intptr_t and void* have different lengths on this platform. "
  1331                   "This may cause a security failure with the SecurityLevel union.");
  1334 nsresult nsScriptSecurityManager::Init()
  1336     nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
  1337     NS_ENSURE_SUCCESS(rv, rv);
  1339     InitPrefs();
  1341     nsCOMPtr<nsIStringBundleService> bundleService =
  1342         mozilla::services::GetStringBundleService();
  1343     if (!bundleService)
  1344         return NS_ERROR_FAILURE;
  1346     rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
  1347     NS_ENSURE_SUCCESS(rv, rv);
  1349     // Create our system principal singleton
  1350     nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
  1351     NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
  1353     mSystemPrincipal = system;
  1355     //-- Register security check callback in the JS engine
  1356     //   Currently this is used to control access to function.caller
  1357     rv = nsXPConnect::XPConnect()->GetRuntime(&sRuntime);
  1358     NS_ENSURE_SUCCESS(rv, rv);
  1360     static const JSSecurityCallbacks securityCallbacks = {
  1361         ContentSecurityPolicyPermitsJSAction,
  1362         JSPrincipalsSubsume,
  1363     };
  1365     MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
  1366     JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
  1367     JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
  1369     JS_SetTrustedPrincipals(sRuntime, system);
  1371     return NS_OK;
  1374 static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
  1376 nsScriptSecurityManager::~nsScriptSecurityManager(void)
  1378     Preferences::RemoveObservers(this, kObservedPrefs);
  1379     if (mDomainPolicy)
  1380         mDomainPolicy->Deactivate();
  1381     MOZ_ASSERT(!mDomainPolicy);
  1384 void
  1385 nsScriptSecurityManager::Shutdown()
  1387     if (sRuntime) {
  1388         JS_SetSecurityCallbacks(sRuntime, nullptr);
  1389         JS_SetTrustedPrincipals(sRuntime, nullptr);
  1390         sRuntime = nullptr;
  1393     NS_IF_RELEASE(sIOService);
  1394     NS_IF_RELEASE(sStrBundle);
  1397 nsScriptSecurityManager *
  1398 nsScriptSecurityManager::GetScriptSecurityManager()
  1400     if (!gScriptSecMan && nsXPConnect::XPConnect())
  1402         nsRefPtr<nsScriptSecurityManager> ssManager = new nsScriptSecurityManager();
  1404         nsresult rv;
  1405         rv = ssManager->Init();
  1406         if (NS_FAILED(rv)) {
  1407             return nullptr;
  1410         rv = nsXPConnect::XPConnect()->
  1411             SetDefaultSecurityManager(ssManager);
  1412         if (NS_FAILED(rv)) {
  1413             NS_WARNING("Failed to install xpconnect security manager!");
  1414             return nullptr;
  1417         ClearOnShutdown(&gScriptSecMan);
  1418         gScriptSecMan = ssManager;
  1420     return gScriptSecMan;
  1423 // Currently this nsGenericFactory constructor is used only from FastLoad
  1424 // (XPCOM object deserialization) code, when "creating" the system principal
  1425 // singleton.
  1426 nsSystemPrincipal *
  1427 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
  1429     nsIPrincipal *sysprin = nullptr;
  1430     if (gScriptSecMan)
  1431         NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
  1432     return static_cast<nsSystemPrincipal*>(sysprin);
  1435 struct IsWhitespace {
  1436     static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); };
  1437 };
  1438 struct IsWhitespaceOrComma {
  1439     static bool Test(char aChar) { return aChar == ',' || NS_IsAsciiWhitespace(aChar); };
  1440 };
  1442 template <typename Predicate>
  1443 uint32_t SkipPast(const nsCString& str, uint32_t base)
  1445     while (base < str.Length() && Predicate::Test(str[base])) {
  1446         ++base;
  1448     return base;
  1451 template <typename Predicate>
  1452 uint32_t SkipUntil(const nsCString& str, uint32_t base)
  1454     while (base < str.Length() && !Predicate::Test(str[base])) {
  1455         ++base;
  1457     return base;
  1460 inline void
  1461 nsScriptSecurityManager::ScriptSecurityPrefChanged()
  1463     MOZ_ASSERT(mPrefInitialized);
  1464     mIsJavaScriptEnabled =
  1465         Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled);
  1466     sStrictFileOriginPolicy =
  1467         Preferences::GetBool(sFileOriginPolicyPrefName, false);
  1469     //
  1470     // Rebuild the set of principals for which we allow file:// URI loads. This
  1471     // implements a small subset of an old pref-based CAPS people that people
  1472     // have come to depend on. See bug 995943.
  1473     //
  1475     mFileURIWhitelist.Clear();
  1476     auto policies = mozilla::Preferences::GetCString("capability.policy.policynames");
  1477     for (uint32_t base = SkipPast<IsWhitespaceOrComma>(policies, 0), bound = 0;
  1478          base < policies.Length();
  1479          base = SkipPast<IsWhitespaceOrComma>(policies, bound))
  1481         // Grab the current policy name.
  1482         bound = SkipUntil<IsWhitespaceOrComma>(policies, base);
  1483         auto policyName = Substring(policies, base, bound - base);
  1485         // Figure out if this policy allows loading file:// URIs. If not, we can skip it.
  1486         nsCString checkLoadURIPrefName = NS_LITERAL_CSTRING("capability.policy.") +
  1487                                          policyName +
  1488                                          NS_LITERAL_CSTRING(".checkloaduri.enabled");
  1489         if (!Preferences::GetString(checkLoadURIPrefName.get()).LowerCaseEqualsLiteral("allaccess")) {
  1490             continue;
  1493         // Grab the list of domains associated with this policy.
  1494         nsCString domainPrefName = NS_LITERAL_CSTRING("capability.policy.") +
  1495                                    policyName +
  1496                                    NS_LITERAL_CSTRING(".sites");
  1497         auto siteList = Preferences::GetCString(domainPrefName.get());
  1498         AddSitesToFileURIWhitelist(siteList);
  1502 void
  1503 nsScriptSecurityManager::AddSitesToFileURIWhitelist(const nsCString& aSiteList)
  1505     for (uint32_t base = SkipPast<IsWhitespace>(aSiteList, 0), bound = 0;
  1506          base < aSiteList.Length();
  1507          base = SkipPast<IsWhitespace>(aSiteList, bound))
  1509         // Grab the current site.
  1510         bound = SkipUntil<IsWhitespace>(aSiteList, base);
  1511         nsAutoCString site(Substring(aSiteList, base, bound - base));
  1513         // Check if the URI is schemeless. If so, add both http and https.
  1514         nsAutoCString unused;
  1515         if (NS_FAILED(sIOService->ExtractScheme(site, unused))) {
  1516             AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("http://") + site);
  1517             AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("https://") + site);
  1518             continue;
  1521         // Convert it to a URI and add it to our list.
  1522         nsCOMPtr<nsIURI> uri;
  1523         nsresult rv = NS_NewURI(getter_AddRefs(uri), site, nullptr, nullptr, sIOService);
  1524         if (NS_SUCCEEDED(rv)) {
  1525             mFileURIWhitelist.AppendElement(uri);
  1526         } else {
  1527             nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1"));
  1528             if (console) {
  1529                 nsAutoString msg = NS_LITERAL_STRING("Unable to to add site to file:// URI whitelist: ") +
  1530                                    NS_ConvertASCIItoUTF16(site);
  1531                 console->LogStringMessage(msg.get());
  1537 nsresult
  1538 nsScriptSecurityManager::InitPrefs()
  1540     nsIPrefBranch* branch = Preferences::GetRootBranch();
  1541     NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE);
  1543     mPrefInitialized = true;
  1545     // Set the initial value of the "javascript.enabled" prefs
  1546     ScriptSecurityPrefChanged();
  1548     // set observer callbacks in case the value of the prefs change
  1549     Preferences::AddStrongObservers(this, kObservedPrefs);
  1551     return NS_OK;
  1554 namespace mozilla {
  1556 void
  1557 GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
  1559   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1561   if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  1562     aAppId = nsIScriptSecurityManager::NO_APP_ID;
  1565   aJarPrefix.Truncate();
  1567   // Fallback.
  1568   if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
  1569     return;
  1572   // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
  1573   aJarPrefix.AppendInt(aAppId);
  1574   aJarPrefix.Append('+');
  1575   aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
  1576   aJarPrefix.Append('+');
  1578   return;
  1581 } // namespace mozilla
  1583 NS_IMETHODIMP
  1584 nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
  1585                                       bool aInMozBrowser,
  1586                                       nsACString& aJarPrefix)
  1588   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1590   mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
  1591   return NS_OK;
  1594 NS_IMETHODIMP
  1595 nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
  1597     *aRv = !!mDomainPolicy;
  1598     return NS_OK;
  1601 NS_IMETHODIMP
  1602 nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
  1604     // We only allow one domain policy at a time. The holder of the previous
  1605     // policy must explicitly deactivate it first.
  1606     if (mDomainPolicy) {
  1607         return NS_ERROR_SERVICE_NOT_AVAILABLE;
  1610     mDomainPolicy = new DomainPolicy();
  1611     nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
  1612     ptr.forget(aRv);
  1613     return NS_OK;
  1616 // Intentionally non-scriptable. Script must have a reference to the
  1617 // nsIDomainPolicy to deactivate it.
  1618 void
  1619 nsScriptSecurityManager::DeactivateDomainPolicy()
  1621     mDomainPolicy = nullptr;
  1624 NS_IMETHODIMP
  1625 nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
  1627     nsresult rv;
  1629     // Compute our rule. If we don't have any domain policy set up that might
  1630     // provide exceptions to this rule, we're done.
  1631     *aRv = mIsJavaScriptEnabled;
  1632     if (!mDomainPolicy) {
  1633         return NS_OK;
  1636     // We have a domain policy. Grab the appropriate set of exceptions to the
  1637     // rule (either the blacklist or the whitelist, depending on whether script
  1638     // is enabled or disabled by default).
  1639     nsCOMPtr<nsIDomainSet> exceptions;
  1640     nsCOMPtr<nsIDomainSet> superExceptions;
  1641     if (*aRv) {
  1642         mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions));
  1643         mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions));
  1644     } else {
  1645         mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions));
  1646         mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions));
  1649     bool contains;
  1650     rv = exceptions->Contains(aURI, &contains);
  1651     NS_ENSURE_SUCCESS(rv, rv);
  1652     if (contains) {
  1653         *aRv = !*aRv;
  1654         return NS_OK;
  1656     rv = superExceptions->ContainsSuperDomain(aURI, &contains);
  1657     NS_ENSURE_SUCCESS(rv, rv);
  1658     if (contains) {
  1659         *aRv = !*aRv;
  1662     return NS_OK;

mercurial