mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1247687 - Implement csp for Module Workers; r=evilpie,asuth,rpl,ckerschb
Depends on D155691 Differential Revision: https://phabricator.services.mozilla.com/D156102
This commit is contained in:
parent
55f1e53d70
commit
1c5ad3e91d
@ -144,8 +144,10 @@ inline const char* NS_CP_ContentTypeName(nsContentPolicyType contentType) {
|
||||
CASE_RETURN(TYPE_INTERNAL_FRAME_MESSAGEMANAGER_SCRIPT);
|
||||
CASE_RETURN(TYPE_INTERNAL_FETCH_PRELOAD);
|
||||
CASE_RETURN(TYPE_UA_FONT);
|
||||
CASE_RETURN(TYPE_INTERNAL_WORKER_STATIC_MODULE);
|
||||
CASE_RETURN(TYPE_PROXIED_WEBRTC_MEDIA);
|
||||
CASE_RETURN(TYPE_WEB_IDENTITY);
|
||||
CASE_RETURN(TYPE_END);
|
||||
case nsIContentPolicy::TYPE_INVALID:
|
||||
break;
|
||||
// Do not add default: so that compilers can catch the missing case.
|
||||
|
@ -3495,6 +3495,7 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType) {
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_AUDIOWORKLET:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_PAINTWORKLET:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_CHROMEUTILS_COMPILED_SCRIPT:
|
||||
|
@ -433,6 +433,20 @@ interface nsIContentPolicy : nsISupports
|
||||
*/
|
||||
TYPE_WEB_IDENTITY = 57,
|
||||
|
||||
/**
|
||||
* Indicates the load of a static module on workers.
|
||||
*/
|
||||
TYPE_INTERNAL_WORKER_STATIC_MODULE = 58,
|
||||
|
||||
/**
|
||||
* Used to indicate the end of this list, not a content policy. If you want
|
||||
* to add a new content policy type, place it before this sentinel value
|
||||
* TYPE_END, have it use TYPE_END's current value, and increment TYPE_END by
|
||||
* one. (TYPE_END should always have the highest numerical value.)
|
||||
*/
|
||||
TYPE_END = 59,
|
||||
|
||||
|
||||
/* When adding new content types, please update
|
||||
* NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective,
|
||||
* DoContentSecurityChecks, all nsIContentPolicy implementations, the
|
||||
|
4
dom/cache/DBSchema.cpp
vendored
4
dom/cache/DBSchema.cpp
vendored
@ -342,7 +342,9 @@ static_assert(
|
||||
nsIContentPolicy::TYPE_INTERNAL_FRAME_MESSAGEMANAGER_SCRIPT == 53 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD == 54 &&
|
||||
nsIContentPolicy::TYPE_UA_FONT == 55 &&
|
||||
nsIContentPolicy::TYPE_WEB_IDENTITY == 57,
|
||||
nsIContentPolicy::TYPE_WEB_IDENTITY == 57 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE == 58 &&
|
||||
nsIContentPolicy::TYPE_END == 59,
|
||||
"nsContentPolicyType values are as expected");
|
||||
|
||||
namespace {
|
||||
|
@ -274,6 +274,7 @@ RequestDestination InternalRequest::MapContentPolicyTypeToRequestDestination(
|
||||
case nsIContentPolicy::TYPE_SCRIPT:
|
||||
return RequestDestination::Script;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE:
|
||||
return RequestDestination::Worker;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
return RequestDestination::Sharedworker;
|
||||
@ -350,6 +351,7 @@ RequestDestination InternalRequest::MapContentPolicyTypeToRequestDestination(
|
||||
case nsIContentPolicy::TYPE_WEB_IDENTITY:
|
||||
return RequestDestination::_empty;
|
||||
case nsIContentPolicy::TYPE_INVALID:
|
||||
case nsIContentPolicy::TYPE_END:
|
||||
break;
|
||||
// Do not add default: so that compilers can catch the missing case.
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace dom {
|
||||
* | TYPE_STYLESHEET
|
||||
* "track" | TYPE_INTERNAL_TRACK
|
||||
* "video" | TYPE_INTERNAL_VIDEO
|
||||
* "worker" | TYPE_INTERNAL_WORKER
|
||||
* "worker" | TYPE_INTERNAL_WORKER, TYPE_INTERNAL_WORKER_STATIC_MODULE
|
||||
* "xslt" | TYPE_XSLT
|
||||
* "" | Default for everything else.
|
||||
*
|
||||
|
@ -31,6 +31,7 @@ nsCString MapInternalContentPolicyTypeToDest(nsContentPolicyType aType) {
|
||||
case nsIContentPolicy::TYPE_SCRIPT:
|
||||
return "script"_ns;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE:
|
||||
return "worker"_ns;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
return "sharedworker"_ns;
|
||||
@ -108,6 +109,7 @@ nsCString MapInternalContentPolicyTypeToDest(nsContentPolicyType aType) {
|
||||
return "empty"_ns;
|
||||
case nsIContentPolicy::TYPE_WEB_IDENTITY:
|
||||
return "webidentity"_ns;
|
||||
case nsIContentPolicy::TYPE_END:
|
||||
case nsIContentPolicy::TYPE_INVALID:
|
||||
break;
|
||||
// Do not add default: so that compilers can catch the missing case.
|
||||
|
@ -304,6 +304,7 @@ CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType) {
|
||||
return nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE;
|
||||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
|
||||
return nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE;
|
||||
@ -353,6 +354,7 @@ CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType) {
|
||||
// Fall through to error for all other directives
|
||||
// Note that we should never end up here for navigate-to
|
||||
case nsIContentPolicy::TYPE_INVALID:
|
||||
case nsIContentPolicy::TYPE_END:
|
||||
MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
|
||||
// Do not add default: so that compilers can catch the missing case.
|
||||
}
|
||||
|
@ -443,6 +443,8 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// external type in all cases right now.
|
||||
bool isWorkerType =
|
||||
internalContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
|
||||
internalContentType ==
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE ||
|
||||
internalContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
|
||||
internalContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;
|
||||
ExtContentPolicyType contentType =
|
||||
|
@ -119,10 +119,9 @@ nsresult ChannelFromScriptURL(
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri = aScriptURL;
|
||||
|
||||
// If we have the document, use it. Unfortunately, for dedicated workers
|
||||
// 'parentDoc' ends up being the parent document, which is not the document
|
||||
// that we want to use. So make sure to avoid using 'parentDoc' in that
|
||||
// situation.
|
||||
// Only use the document when its principal matches the principal of the
|
||||
// current request. This means scripts fetched using the Workers' own
|
||||
// principal won't inherit properties of the document, in particular the CSP.
|
||||
if (parentDoc && parentDoc->NodePrincipal() != principal) {
|
||||
parentDoc = nullptr;
|
||||
}
|
||||
@ -140,6 +139,7 @@ nsresult ChannelFromScriptURL(
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
if (parentDoc) {
|
||||
// This is the path for top level dedicated worker scripts with a document
|
||||
rv = NS_NewChannel(getter_AddRefs(channel), uri, parentDoc, aSecFlags,
|
||||
aContentPolicyType,
|
||||
nullptr, // aPerformanceStorage
|
||||
@ -148,6 +148,11 @@ nsresult ChannelFromScriptURL(
|
||||
aLoadFlags, ios);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
|
||||
} else {
|
||||
// This branch is used in the following cases:
|
||||
// * Shared and ServiceWorkers (who do not have a doc)
|
||||
// * Static Module Imports
|
||||
// * ImportScripts
|
||||
|
||||
// We must have a loadGroup with a load context for the principal to
|
||||
// traverse the channel correctly.
|
||||
MOZ_ASSERT(loadGroup);
|
||||
@ -161,6 +166,8 @@ nsresult ChannelFromScriptURL(
|
||||
}
|
||||
|
||||
if (aClientInfo.isSome()) {
|
||||
// If we have an existing clientInfo (true for all modules and
|
||||
// importScripts), we will use this branch
|
||||
rv = NS_NewChannel(getter_AddRefs(channel), uri, principal,
|
||||
aClientInfo.ref(), aController, aSecFlags,
|
||||
aContentPolicyType, aCookieJarSettings,
|
||||
@ -544,6 +551,26 @@ nsTArray<RefPtr<ThreadSafeRequestHandle>> WorkerScriptLoader::GetLoadingList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
nsContentPolicyType WorkerScriptLoader::GetContentPolicyType(
|
||||
ScriptLoadRequest* aRequest) {
|
||||
if (aRequest->GetWorkerLoadContext()->IsTopLevel()) {
|
||||
// Implements https://html.spec.whatwg.org/#worker-processing-model
|
||||
// Step 13: Let destination be "sharedworker" if is shared is true, and
|
||||
// "worker" otherwise.
|
||||
return mWorkerRef->Private()->ContentPolicyType();
|
||||
}
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
// Implements the destination for Step 14 in
|
||||
// https://html.spec.whatwg.org/#worker-processing-model
|
||||
//
|
||||
// We need a special subresource type in order to correctly implement
|
||||
// the graph fetch, where the destination is set to "worker" or
|
||||
// "sharedworker".
|
||||
return nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE;
|
||||
}
|
||||
return nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS;
|
||||
}
|
||||
|
||||
already_AddRefed<ScriptLoadRequest> WorkerScriptLoader::CreateScriptLoadRequest(
|
||||
const nsString& aScriptURL, const mozilla::Encoding* aDocumentEncoding,
|
||||
bool aIsMainScript) {
|
||||
@ -584,7 +611,7 @@ already_AddRefed<ScriptLoadRequest> WorkerScriptLoader::CreateScriptLoadRequest(
|
||||
} else {
|
||||
// Implements part of "To fetch a worklet/module worker script graph"
|
||||
// including, setting up the request with a credentials mode,
|
||||
// destination (CSP, TODO).
|
||||
// destination.
|
||||
|
||||
// Step 1. Let options be a script fetch options.
|
||||
// We currently don't track credentials in our ScriptFetchOptions
|
||||
@ -879,10 +906,7 @@ nsresult WorkerScriptLoader::LoadScript(
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsContentPolicyType contentPolicyType =
|
||||
loadContext->IsTopLevel()
|
||||
? mWorkerRef->Private()->ContentPolicyType()
|
||||
: nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS;
|
||||
nsContentPolicyType contentPolicyType = GetContentPolicyType(request);
|
||||
|
||||
rv = ChannelFromScriptURL(
|
||||
principal, parentDoc, mWorkerRef->Private(), loadGroup, ios, secMan,
|
||||
|
@ -245,6 +245,8 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
|
||||
|
||||
nsTArray<RefPtr<ThreadSafeRequestHandle>> GetLoadingList();
|
||||
|
||||
nsContentPolicyType GetContentPolicyType(ScriptLoadRequest* aRequest);
|
||||
|
||||
bool EvaluateScript(JSContext* aCx, ScriptLoadRequest* aRequest);
|
||||
|
||||
nsresult FillCompileOptionsForRequest(
|
||||
|
@ -34,6 +34,12 @@ WorkerModuleLoader::WorkerModuleLoader(WorkerScriptLoader* aScriptLoader,
|
||||
|
||||
already_AddRefed<ModuleLoadRequest> WorkerModuleLoader::CreateStaticImport(
|
||||
nsIURI* aURI, ModuleLoadRequest* aParent) {
|
||||
// We are intentionally deviating from the specification here and using the
|
||||
// worker's CSP rather than the document CSP. The spec otherwise requires our
|
||||
// service worker integration to be changed, and additionally the decision
|
||||
// here did not make sense as we are treating static imports as different from
|
||||
// other kinds of subresources.
|
||||
// See Discussion in https://github.com/w3c/webappsec-csp/issues/336
|
||||
Maybe<ClientInfo> clientInfo = GetGlobalObject()->GetClientInfo();
|
||||
|
||||
RefPtr<WorkerLoadContext> loadContext =
|
||||
|
@ -328,9 +328,9 @@ struct ParamTraits<nsID> {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<nsContentPolicyType>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
nsContentPolicyType, nsIContentPolicy::TYPE_INVALID,
|
||||
nsIContentPolicy::TYPE_WEB_IDENTITY> {};
|
||||
: public ContiguousEnumSerializer<nsContentPolicyType,
|
||||
nsIContentPolicy::TYPE_INVALID,
|
||||
nsIContentPolicy::TYPE_END> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::TimeDuration> {
|
||||
|
@ -171,7 +171,8 @@ interface nsIInterceptedChannel : nsISupports
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_MODULE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_MODULE_PRELOAD:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS: {
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE: {
|
||||
aKey = "subresource-script"_ns;
|
||||
break;
|
||||
}
|
||||
|
@ -338,7 +338,8 @@ void AssertLoadingPrincipalAndClientInfoMatch(
|
||||
(aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS)) {
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2806,6 +2806,7 @@ nsresult EnsureMIMEOfScript(HttpBaseChannel* aChannel, nsIURI* aURI,
|
||||
Telemetry::LABELS_SCRIPT_BLOCK_INCORRECT_MIME_3::script_load);
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
AccumulateCategorical(
|
||||
Telemetry::LABELS_SCRIPT_BLOCK_INCORRECT_MIME_3::worker_load);
|
||||
@ -2930,7 +2931,8 @@ nsresult EnsureMIMEOfScript(HttpBaseChannel* aChannel, nsIURI* aURI,
|
||||
|
||||
// We restrict importScripts() in worker code to JavaScript MIME types.
|
||||
nsContentPolicyType internalType = aLoadInfo->InternalContentPolicyType();
|
||||
if (internalType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS) {
|
||||
if (internalType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
|
||||
internalType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE) {
|
||||
ReportMimeTypeMismatch(aChannel, "BlockImportScriptsWithWrongMimeType",
|
||||
aURI, contentType, Report::Error);
|
||||
return NS_ERROR_CORRUPTED_CONTENT;
|
||||
|
@ -487,7 +487,9 @@ bool ChannelWrapper::IsServiceWorkerScript(const nsCOMPtr<nsIChannel>& chan) {
|
||||
|
||||
// Service worker import scripts load.
|
||||
if (loadInfo->InternalContentPolicyType() ==
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS) {
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
|
||||
loadInfo->InternalContentPolicyType() ==
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE) {
|
||||
nsLoadFlags loadFlags = 0;
|
||||
chan->GetLoadFlags(&loadFlags);
|
||||
return loadFlags & nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
|
||||
|
@ -116,8 +116,10 @@ function verifyRedirect(channel, redirectUri, finalUrl, addonId) {
|
||||
|
||||
if (
|
||||
isServiceWorkerScript &&
|
||||
channel.loadInfo?.internalContentPolicyType ===
|
||||
Ci.nsIContentPolicy.TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS &&
|
||||
(channel.loadInfo?.internalContentPolicyType ===
|
||||
Ci.nsIContentPolicy.TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
|
||||
channel.loadInfo?.internalContentPolicyType ===
|
||||
Ci.nsIContentPolicy.TYPE_INTERNAL_WORKER_STATIC_MODULE) &&
|
||||
!ALLOWED_SERVICEWORKER_SCHEMES.includes(redirectUri?.scheme)
|
||||
) {
|
||||
throw new Error(
|
||||
|
Loading…
Reference in New Issue
Block a user