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