From 59c135c1762b7943e8ad511a229063a06affe0fc Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 11 Sep 2015 18:48:43 -0400 Subject: [PATCH] Bug 1198078 - Add support for TYPE_INTERNAL_SERVICE_WORKER; r=ckerschb,tanvi --- dom/base/nsContentPolicy.cpp | 17 ++++++++++- dom/base/nsContentPolicyUtils.h | 1 + dom/base/nsContentUtils.cpp | 17 +++++++++++ dom/base/nsContentUtils.h | 12 ++++++++ dom/base/nsIContentPolicy.idl | 2 +- dom/base/nsIContentPolicyBase.idl | 11 +++++++- dom/base/nsISimpleContentPolicy.idl | 2 +- dom/cache/DBSchema.cpp | 5 ++-- dom/fetch/InternalRequest.cpp | 1 + dom/security/nsMixedContentBlocker.cpp | 31 +++++++++++++++++++-- dom/workers/ScriptLoader.cpp | 25 ++++++++--------- dom/workers/WorkerPrivate.h | 2 +- extensions/permissions/nsContentBlocker.cpp | 3 +- 13 files changed, 104 insertions(+), 25 deletions(-) diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 7407a04bf68b..9b2ec5528799 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -23,6 +23,7 @@ #include "nsILoadContext.h" #include "nsCOMArray.h" #include "nsContentUtils.h" +#include "mozilla/dom/nsMixedContentBlocker.h" using mozilla::LogLevel; @@ -119,6 +120,12 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, nsContentPolicyType externalType = nsContentUtils::InternalContentPolicyTypeToExternal(contentType); + nsContentPolicyType externalTypeOrScript = + nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentType); + + nsCOMPtr mixedContentBlocker = + do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID); + /* * Enumerate mPolicies and ask each of them, taking the logical AND of * their permissions. @@ -129,7 +136,15 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, int32_t count = entries.Count(); for (int32_t i = 0; i < count; i++) { /* check the appropriate policy */ - rv = (entries[i]->*policyMethod)(externalType, contentLocation, + // Send the internal content policy type to the mixed content blocker + // which needs to know about TYPE_INTERNAL_WORKER, + // TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER. + bool isMixedContentBlocker = mixedContentBlocker == entries[i]; + nsContentPolicyType type = externalType; + if (isMixedContentBlocker) { + type = externalTypeOrScript; + } + rv = (entries[i]->*policyMethod)(type, contentLocation, requestingLocation, requestingContext, mimeType, extra, requestPrincipal, decision); diff --git a/dom/base/nsContentPolicyUtils.h b/dom/base/nsContentPolicyUtils.h index e9d25ba556b4..e3bc0c051399 100644 --- a/dom/base/nsContentPolicyUtils.h +++ b/dom/base/nsContentPolicyUtils.h @@ -126,6 +126,7 @@ NS_CP_ContentTypeName(uint32_t contentType) CASE_RETURN( TYPE_INTERNAL_TRACK ); CASE_RETURN( TYPE_INTERNAL_XMLHTTPREQUEST ); CASE_RETURN( TYPE_INTERNAL_EVENTSOURCE ); + CASE_RETURN( TYPE_INTERNAL_SERVICE_WORKER ); default: return ""; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 5f461d2fd6b8..47fd964dcdfa 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7928,6 +7928,7 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType) case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: case nsIContentPolicy::TYPE_INTERNAL_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER: + case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: return nsIContentPolicy::TYPE_SCRIPT; case nsIContentPolicy::TYPE_INTERNAL_EMBED: @@ -7952,6 +7953,22 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType) } } +/* static */ +nsContentPolicyType +nsContentUtils::InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType) +{ + switch (aType) { + case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: + case nsIContentPolicy::TYPE_INTERNAL_WORKER: + case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER: + case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: + return aType; + + default: + return InternalContentPolicyTypeToExternal(aType); + } +} + nsresult nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal, diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index c768abbf04c8..ba80c3b54e76 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -953,6 +953,18 @@ public: */ static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType); + /** + * Map internal content policy types to external ones or script types: + * * TYPE_INTERNAL_SCRIPT + * * TYPE_INTERNAL_WORKER + * * TYPE_INTERNAL_SHARED_WORKER + * * TYPE_INTERNAL_SERVICE_WORKER + * + * + * Note: DO NOT call this function unless you know what you're doing! + */ + static nsContentPolicyType InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType); + /** * Quick helper to determine whether there are any mutation listeners * of a given type that apply to this content or any of its ancestors. diff --git a/dom/base/nsIContentPolicy.idl b/dom/base/nsIContentPolicy.idl index baa521b41bbb..63ec72e223e8 100644 --- a/dom/base/nsIContentPolicy.idl +++ b/dom/base/nsIContentPolicy.idl @@ -20,7 +20,7 @@ interface nsIPrincipal; * by launching a dialog to prompt the user for something). */ -[scriptable,uuid(3663021e-5670-496f-887b-b408d6526b5b)] +[scriptable,uuid(ce321216-c404-40a7-a711-d80454ec6b76)] interface nsIContentPolicy : nsIContentPolicyBase { /** diff --git a/dom/base/nsIContentPolicyBase.idl b/dom/base/nsIContentPolicyBase.idl index 77270779f5a1..e31608fe9bd5 100644 --- a/dom/base/nsIContentPolicyBase.idl +++ b/dom/base/nsIContentPolicyBase.idl @@ -24,7 +24,7 @@ typedef unsigned long nsContentPolicyType; * by launching a dialog to prompt the user for something). */ -[scriptable,uuid(20f7b9bf-d7d5-4987-ade8-b7dc0398d44a)] +[scriptable,uuid(8527ae0d-0c43-4413-bc46-85c0bcb66876)] interface nsIContentPolicyBase : nsISupports { /** @@ -271,6 +271,15 @@ interface nsIContentPolicyBase : nsISupports */ const nsContentPolicyType TYPE_INTERNAL_EVENTSOURCE = 34; + /** + * Indicates an internal constant for scripts loaded through a service + * worker. + * + * This will be mapped to TYPE_SCRIPT before being passed to content policy + * implementations. + */ + const nsContentPolicyType TYPE_INTERNAL_SERVICE_WORKER = 35; + /* When adding new content types, please update nsContentBlocker, * NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy * implementations, the static_assert in dom/cache/DBSchema.cpp, diff --git a/dom/base/nsISimpleContentPolicy.idl b/dom/base/nsISimpleContentPolicy.idl index 622cdc9e8f9c..493aee1a5472 100644 --- a/dom/base/nsISimpleContentPolicy.idl +++ b/dom/base/nsISimpleContentPolicy.idl @@ -28,7 +28,7 @@ interface nsIDOMElement; * by launching a dialog to prompt the user for something). */ -[scriptable,uuid(b181c97c-9d67-4da1-95a0-e0a202e1807c)] +[scriptable,uuid(b9df71e3-a9b3-4706-b2d5-e6c0d3d68ec7)] interface nsISimpleContentPolicy : nsIContentPolicyBase { /** diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp index 6c77a877f16f..52a93333425d 100644 --- a/dom/cache/DBSchema.cpp +++ b/dom/cache/DBSchema.cpp @@ -274,8 +274,9 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 && nsIContentPolicy::TYPE_INTERNAL_VIDEO == 31 && nsIContentPolicy::TYPE_INTERNAL_TRACK == 32 && nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST == 33 && - nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE == 34, - "nsContentPolicytType values are as expected"); + nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE == 34 && + nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER == 35, + "nsContentPolicyType values are as expected"); namespace { diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp index 119bdcc288bb..d2a8f2bc1f85 100644 --- a/dom/fetch/InternalRequest.cpp +++ b/dom/fetch/InternalRequest.cpp @@ -116,6 +116,7 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte context = RequestContext::Internal; break; case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: + case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: context = RequestContext::Script; break; case nsIContentPolicy::TYPE_INTERNAL_WORKER: diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index 59d8d6623984..1c66ccd1aafd 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -291,7 +291,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel, return NS_OK; } - uint32_t contentPolicyType = loadInfo->GetContentPolicyType(); + nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType(); nsCOMPtr requestingPrincipal = loadInfo->LoadingPrincipal(); // Since we are calling shouldLoad() directly on redirects, we don't go through the code @@ -310,7 +310,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel, } int16_t decision = REJECT_REQUEST; - rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternal(contentPolicyType), + rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentPolicyType), newUri, requestingLocation, loadInfo->LoadingNode(), @@ -378,9 +378,17 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, // to them. MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrScript(aContentType), "We should only see external content policy types here."); + // The content policy type that we receive may be an internal type for + // scripts. Let's remember if we have seen a worker type, and reset it to the + // external type in all cases right now. + bool isWorkerType = aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER; + aContentType = nsContentUtils::InternalContentPolicyTypeToExternal(aContentType); + // Assume active (high risk) content and blocked by default MixedContentTypes classification = eMixedScript; // Make decision to block/reject by default @@ -625,6 +633,23 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, return NS_OK; } + // Disallow mixed content loads for workers, shared workers and service + // workers. + if (isWorkerType) { + // For workers, we can assume that we're mixed content at this point, since + // the parent is https, and the protocol associated with aContentLocation + // doesn't map to the secure URI flags checked above. Assert this for + // sanity's sake +#ifdef DEBUG + bool isHttpsScheme = false; + rv = aContentLocation->SchemeIs("https", &isHttpsScheme); + NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(!isHttpsScheme); +#endif + *aDecision = REJECT_REQUEST; + return NS_OK; + } + // Determine if the rootDoc is https and if the user decided to allow Mixed Content nsCOMPtr docShell = NS_CP_GetDocShellFromContext(aRequestingContext); NS_ENSURE_TRUE(docShell, NS_OK); diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index e04fe3573667..5260070a1807 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -120,21 +120,18 @@ ChannelFromScriptURL(nsIPrincipal* principal, return NS_ERROR_DOM_SYNTAX_ERR; } - // If we're part of a document then check the content load policy. - if (parentDoc) { - int16_t shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri, - principal, parentDoc, - NS_LITERAL_CSTRING("text/javascript"), - nullptr, &shouldLoad, - nsContentUtils::GetContentPolicy(), - secMan); - if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { - if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) { - return rv = NS_ERROR_CONTENT_BLOCKED; - } - return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT; + int16_t shouldLoad = nsIContentPolicy::ACCEPT; + rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri, + principal, parentDoc, + NS_LITERAL_CSTRING("text/javascript"), + nullptr, &shouldLoad, + nsContentUtils::GetContentPolicy(), + secMan); + if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { + if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) { + return rv = NS_ERROR_CONTENT_BLOCKED; } + return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT; } if (aWorkerScriptType == DebuggerScript) { diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 1b0756cf9beb..c54ad9127508 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -732,7 +732,7 @@ public: case WorkerTypeShared: return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER; case WorkerTypeService: - return nsIContentPolicy::TYPE_SCRIPT; + return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER; default: MOZ_ASSERT_UNREACHABLE("Invalid worker type"); return nsIContentPolicy::TYPE_INVALID; diff --git a/extensions/permissions/nsContentBlocker.cpp b/extensions/permissions/nsContentBlocker.cpp index ea10dae97234..ab846a278dee 100644 --- a/extensions/permissions/nsContentBlocker.cpp +++ b/extensions/permissions/nsContentBlocker.cpp @@ -57,7 +57,8 @@ static const char *kTypeString[] = { "", // TYPE_INTERNAL_VIDEO "", // TYPE_INTERNAL_TRACK "", // TYPE_INTERNAL_XMLHTTPREQUEST - "" // TYPE_INTERNAL_EVENTSOURCE + "", // TYPE_INTERNAL_EVENTSOURCE + "", // TYPE_INTERNAL_SERVICE_WORKER }; #define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)