Commit 362fee3f authored by Jason Chase's avatar Jason Chase Committed by Commit Bot

Allow origin trials to be enabled in worklets

As first seen in bug 799092, the AudioWorklet trial uncovered problems where
[OriginTrialEnabled] interfaces were not being exposed for module scripts in
worklets.

The root cause is that WorkletGlobalScopes are defined to have a unique, opaque
origin. This defeats the trial token validation which requires both a secure
context, and that the origin for the context matches the origin in the token.

For the purposes of origin trials, we believe it is sufficient to consider the
context of the document that created the worklet. If the document is secure, and
has valid token(s), the origin trial should be enabled. Analogous to this thread:
https://github.com/whatwg/fetch/pull/527#issuecomment-335677387

This CL changes so that any tokens from the document are passed along to the
worklet, and the origin of the document is used to validate any tokens. This
applies to all types of worklets, although the problem was initially found for
AudioWorklet.

As well the AudioWorkletProcessor interface has the [OriginTrialEnabled]
attribute reinstated (was removed in a previous CL as a short-term workaround).

Bug: 799960
Change-Id: I98cca05a7710e463a10dcd8c17f302f311f531b3
Reviewed-on: https://chromium-review.googlesource.com/862257
Commit-Queue: Jason Chase <chasej@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarIan Clelland <iclelland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#533035}
parent e8e55812
......@@ -265,6 +265,7 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
// via WebPreference by embedders. (crbug.com/254993)
Document* document = shadow_page_->GetDocument();
const SecurityOrigin* starter_origin = document->GetSecurityOrigin();
bool starter_secure_context = document->IsSecureContext();
WorkerClients* worker_clients = WorkerClients::Create();
CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker(
......@@ -303,8 +304,8 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
url_, document->UserAgent(),
content_security_policy ? content_security_policy->Headers().get()
: nullptr,
referrer_policy, starter_origin, worker_clients,
main_script_loader_->ResponseAddressSpace(),
referrer_policy, starter_origin, starter_secure_context,
worker_clients, main_script_loader_->ResponseAddressSpace(),
main_script_loader_->OriginTrialTokens(), std::move(worker_settings),
kV8CacheOptionsDefault, std::move(pending_interface_provider_));
String source_code = main_script_loader_->SourceText();
......
......@@ -32,8 +32,8 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
document->Url(), document->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
nullptr /* worker_clients */, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
document->IsSecureContext(), nullptr /* worker_clients */,
document->AddressSpace(), OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault);
global_scope_ =
LayoutWorkletGlobalScope::Create(frame, std::move(creation_params),
......
......@@ -178,7 +178,8 @@ void ModuleScriptLoaderTest::InitializeForWorklet() {
GetDocument().Url(), GetDocument().UserAgent(),
nullptr /* content_security_policy_parsed_headers */,
GetDocument().GetReferrerPolicy(), GetDocument().GetSecurityOrigin(),
nullptr /* worker_clients */, GetDocument().AddressSpace(),
GetDocument().IsSecureContext(), nullptr /* worker_clients */,
GetDocument().AddressSpace(),
OriginTrialContext::GetTokens(&GetDocument()).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault);
global_scope_ = new MainThreadWorkletGlobalScope(
......
......@@ -13,7 +13,7 @@
#include "core/dom/Document.h"
#include "core/dom/ExecutionContext.h"
#include "core/frame/LocalFrame.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkletGlobalScope.h"
#include "platform/Histogram.h"
#include "platform/bindings/OriginTrialFeatures.h"
#include "platform/runtime_enabled_features.h"
......@@ -229,7 +229,20 @@ bool OriginTrialContext::EnableTrialFromToken(const String& token) {
DCHECK(!token.IsEmpty());
// Origin trials are only enabled for secure origins
if (!GetSupplementable()->IsSecureContext()) {
// - For worklets, they are currently spec'd to not be secure, given their
// scope has unique origin:
// https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
// - For the purpose of origin trials, we consider worklets as running in the
// same context as the originating document. Thus, the special logic here
// to validate the token against the document context.
bool is_secure = false;
ExecutionContext* context = GetSupplementable();
if (context->IsWorkletGlobalScope()) {
is_secure = ToWorkletGlobalScope(context)->DocumentSecureContext();
} else {
is_secure = context->IsSecureContext();
}
if (!is_secure) {
TokenValidationResultHistogram().Count(
static_cast<int>(OriginTrialTokenStatus::kInsecure));
return false;
......@@ -241,7 +254,14 @@ bool OriginTrialContext::EnableTrialFromToken(const String& token) {
return false;
}
WebSecurityOrigin origin(GetSupplementable()->GetSecurityOrigin());
WebSecurityOrigin origin;
if (context->IsWorkletGlobalScope()) {
origin = WebSecurityOrigin(
ToWorkletGlobalScope(context)->DocumentSecurityOrigin());
} else {
origin = WebSecurityOrigin(context->GetSecurityOrigin());
}
WebString trial_name;
bool valid = false;
OriginTrialTokenStatus token_result =
......
......@@ -219,8 +219,9 @@ DedicatedWorker::CreateGlobalScopeCreationParams() {
return std::make_unique<GlobalScopeCreationParams>(
script_url_, GetExecutionContext()->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
kReferrerPolicyDefault, starter_origin, CreateWorkerClients(),
document->AddressSpace(), OriginTrialContext::GetTokens(document).get(),
kReferrerPolicyDefault, starter_origin, document->IsSecureContext(),
CreateWorkerClients(), document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
std::make_unique<WorkerSettings>(document->GetSettings()),
kV8CacheOptionsDefault,
ConnectToWorkerInterfaceProvider(document,
......
......@@ -132,9 +132,9 @@ class DedicatedWorkerMessagingProxyForTest
std::make_unique<GlobalScopeCreationParams>(
script_url, "fake user agent", headers.get(),
kReferrerPolicyDefault, security_origin_.get(),
nullptr /* worker_clients */, mojom::IPAddressSpace::kLocal,
nullptr /* origin_trial_tokens */, std::move(worker_settings),
kV8CacheOptionsDefault),
false /* starter_secure_context */, nullptr /* worker_clients */,
mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_tokens */,
std::move(worker_settings), kV8CacheOptionsDefault),
WorkerBackingThreadStartupData(
WorkerBackingThreadStartupData::HeapLimitMode::kDefault,
WorkerBackingThreadStartupData::AtomicsWaitMode::kAllow));
......
......@@ -16,6 +16,7 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
const Vector<CSPHeaderAndType>* content_security_policy_parsed_headers,
ReferrerPolicy referrer_policy,
const SecurityOrigin* starter_origin,
bool starter_secure_context,
WorkerClients* worker_clients,
mojom::IPAddressSpace address_space,
const Vector<String>* origin_trial_tokens,
......@@ -27,6 +28,7 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
user_agent(user_agent.IsolatedCopy()),
referrer_policy(referrer_policy),
starter_origin(starter_origin ? starter_origin->IsolatedCopy() : nullptr),
starter_secure_context(starter_secure_context),
worker_clients(worker_clients),
address_space(address_space),
worker_settings(std::move(worker_settings)),
......
......@@ -38,6 +38,7 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
const Vector<CSPHeaderAndType>* content_security_policy_parsed_headers,
ReferrerPolicy referrer_policy,
const SecurityOrigin*,
bool starter_secure_context,
WorkerClients*,
mojom::IPAddressSpace,
const Vector<String>* origin_trial_tokens,
......@@ -76,6 +77,15 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
// script loader uses Document's SecurityOrigin for security checks.
scoped_refptr<const SecurityOrigin> starter_origin;
// Indicates if the Document creating a Worker/Worklet is a secure context.
//
// Worklets are defined to have a unique, opaque origin, so are not secure:
// https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
// Origin trials are only enabled in secure contexts, and the trial tokens are
// inherited from the document, so also consider the context of the document.
// The value should be supplied as the result of Document.IsSecureContext().
bool starter_secure_context;
// This object is created and initialized on the thread creating
// a new worker context, but ownership of it and this
// GlobalScopeCreationParams structure is passed along to the new worker
......
......@@ -62,8 +62,8 @@ class MainThreadWorkletTest : public ::testing::Test {
document->Url(), document->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
nullptr /* worker_clients */, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
document->IsSecureContext(), nullptr /* worker_clients */,
document->AddressSpace(), OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault);
global_scope_ = new MainThreadWorkletGlobalScope(
&page_->GetFrame(), std::move(creation_params), *reporting_proxy_);
......
......@@ -41,7 +41,7 @@ void ThreadedWorkletMessagingProxy::Initialize(WorkerClients* worker_clients) {
std::make_unique<GlobalScopeCreationParams>(
document->Url(), document->UserAgent(), csp->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
worker_clients, document->AddressSpace(),
document->IsSecureContext(), worker_clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
std::make_unique<WorkerSettings>(document->GetSettings()),
kV8CacheOptionsDefault);
......
......@@ -182,7 +182,8 @@ class ThreadedWorkletMessagingProxyForTest
document->Url(), document->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
worker_clients, document->AddressSpace(),
document->IsSecureContext(), worker_clients,
document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
std::move(worker_settings), kV8CacheOptionsDefault),
WTF::nullopt);
......
......@@ -300,8 +300,8 @@ TEST_F(WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunningOnInitialization) {
std::make_unique<GlobalScopeCreationParams>(
KURL("http://fake.url/"), "fake user agent", headers.get(),
kReferrerPolicyDefault, security_origin_.get(),
nullptr /* workerClients */, mojom::IPAddressSpace::kLocal,
nullptr /* originTrialToken */,
false /* starter_secure_context */, nullptr /* workerClients */,
mojom::IPAddressSpace::kLocal, nullptr /* originTrialToken */,
std::make_unique<WorkerSettings>(Settings::Create().get()),
kV8CacheOptionsDefault);
......
......@@ -102,7 +102,8 @@ class WorkerThreadForTest : public WorkerThread {
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
script_url, "fake user agent", headers.get(), kReferrerPolicyDefault,
security_origin, worker_clients, mojom::IPAddressSpace::kLocal, nullptr,
security_origin, false /* starter_secure_context */, worker_clients,
mojom::IPAddressSpace::kLocal, nullptr,
std::make_unique<WorkerSettings>(Settings::Create().get()),
kV8CacheOptionsDefault);
......
......@@ -9,6 +9,7 @@
#include "bindings/core/v8/SourceLocation.h"
#include "bindings/core/v8/WorkerOrWorkletScriptController.h"
#include "core/inspector/MainThreadDebugger.h"
#include "core/origin_trials/OriginTrialContext.h"
#include "core/probe/CoreProbes.h"
#include "core/script/Modulator.h"
#include "core/workers/GlobalScopeCreationParams.h"
......@@ -33,7 +34,8 @@ WorkletGlobalScope::WorkletGlobalScope(
reporting_proxy),
url_(creation_params->script_url),
user_agent_(creation_params->user_agent),
document_security_origin_(creation_params->starter_origin) {
document_security_origin_(creation_params->starter_origin),
document_secure_context_(creation_params->starter_secure_context) {
// Step 2: "Let inheritedAPIBaseURL be outsideSettings's API base URL."
// |url_| is the inheritedAPIBaseURL passed from the parent Document.
......@@ -48,6 +50,9 @@ WorkletGlobalScope::WorkletGlobalScope(
// workletGlobalScope."
ApplyContentSecurityPolicyFromVector(
*creation_params->content_security_policy_parsed_headers);
OriginTrialContext::AddTokens(this,
creation_params->origin_trial_tokens.get());
}
WorkletGlobalScope::~WorkletGlobalScope() = default;
......
......@@ -76,6 +76,15 @@ class CORE_EXPORT WorkletGlobalScope
return document_security_origin_.get();
}
// Customize the security context used for origin trials.
// Origin trials are only enabled in secure contexts, but WorkletGlobalScopes
// are defined to have a unique, opaque origin, so are not secure:
// https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
// For origin trials, instead consider the context of the document which
// created the worklet, since the origin trial tokens are inherited from the
// document.
bool DocumentSecureContext() const { return document_secure_context_; }
void Trace(blink::Visitor*) override;
void TraceWrappers(const ScriptWrappableVisitor*) const override;
......@@ -94,9 +103,13 @@ class CORE_EXPORT WorkletGlobalScope
const KURL url_;
const String user_agent_;
// Used for module fetch.
// Used for module fetch and origin trials, inherited from the parent
// Document.
const scoped_refptr<const SecurityOrigin> document_security_origin_;
// Used for origin trials, inherited from the parent Document.
const bool document_secure_context_;
Member<WorkletModuleResponsesMapProxy> module_responses_map_proxy_;
};
......
......@@ -61,7 +61,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
document->Url(), document->UserAgent(),
nullptr /* content_security_policy_parsed_headers */,
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
clients, document->AddressSpace(),
document->IsSecureContext(), clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault),
WTF::nullopt, WorkerInspectorProxy::PauseOnWorkerStart::kDontPause,
......
......@@ -94,7 +94,7 @@ class AnimationWorkletThreadTest : public PageTestBase {
document->Url(), document->UserAgent(),
nullptr /* content_security_policy_parsed_headers */,
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
clients, document->AddressSpace(),
document->IsSecureContext(), clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault),
WTF::nullopt, WorkerInspectorProxy::PauseOnWorkerStart::kDontPause,
......
......@@ -33,8 +33,8 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
document->Url(), document->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
nullptr /* worker_clients */, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
document->IsSecureContext(), nullptr /* worker_clients */,
document->AddressSpace(), OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault);
global_scope_ = PaintWorkletGlobalScope::Create(
frame, std::move(creation_params), *reporting_proxy_,
......
......@@ -319,6 +319,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
// FIXME: this document's origin is pristine and without any extra privileges.
// (crbug.com/254993)
const SecurityOrigin* starter_origin = document->GetSecurityOrigin();
bool starter_secure_context = document->IsSecureContext();
WorkerClients* worker_clients = WorkerClients::Create();
ProvideIndexedDBClientToWorker(worker_clients,
......@@ -358,8 +359,8 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
global_scope_creation_params = std::make_unique<GlobalScopeCreationParams>(
worker_start_data_.script_url, worker_start_data_.user_agent,
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), starter_origin, worker_clients,
main_script_loader_->ResponseAddressSpace(),
document->GetReferrerPolicy(), starter_origin, starter_secure_context,
worker_clients, main_script_loader_->ResponseAddressSpace(),
main_script_loader_->OriginTrialTokens(), std::move(worker_settings),
static_cast<V8CacheOptions>(worker_start_data_.v8_cache_options),
std::move(interface_provider_info_));
......@@ -373,8 +374,9 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
global_scope_creation_params = std::make_unique<GlobalScopeCreationParams>(
worker_start_data_.script_url, worker_start_data_.user_agent,
nullptr /* ContentSecurityPolicy */, kReferrerPolicyDefault,
starter_origin, worker_clients, worker_start_data_.address_space,
nullptr /* OriginTrialTokens */, std::move(worker_settings),
starter_origin, starter_secure_context, worker_clients,
worker_start_data_.address_space, nullptr /* OriginTrialTokens */,
std::move(worker_settings),
static_cast<V8CacheOptions>(worker_start_data_.v8_cache_options),
std::move(interface_provider_info_));
}
......
......@@ -72,7 +72,8 @@ class AudioWorkletGlobalScopeTest : public PageTestBase {
document->Url(), document->UserAgent(),
nullptr /* content_security_policy_parsed_headers */,
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
nullptr /* worker_clients */, document->AddressSpace(),
document->IsSecureContext(), nullptr /* worker_clients */,
document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault),
WTF::nullopt, WorkerInspectorProxy::PauseOnWorkerStart::kDontPause,
......
......@@ -8,7 +8,8 @@
Constructor,
ConstructorCallWith=ExecutionContext,
Exposed=AudioWorklet,
Global=(Worklet,AudioWorklet)
Global=(Worklet,AudioWorklet),
OriginTrialEnabled=AudioWorklet
] interface AudioWorkletProcessor {
readonly attribute MessagePort port;
};
......@@ -54,7 +54,8 @@ class AudioWorkletThreadTest : public PageTestBase {
document->Url(), document->UserAgent(),
nullptr /* content_security_policy_parsed_headers */,
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
nullptr /* worker_clients */, document->AddressSpace(),
document->IsSecureContext(), nullptr /* worker_clients */,
document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
nullptr /* worker_settings */, kV8CacheOptionsDefault),
WTF::nullopt, WorkerInspectorProxy::PauseOnWorkerStart::kDontPause,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment