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