Commit e5065d6e authored by Hiroki Nakagawa's avatar Hiroki Nakagawa Committed by Commit Bot

Worklet: Make WorkletGlobalScope a unique opaque origin

This CL does 2 things:

(1) The Worklet spec defines WorkletGlobalScope must have a unique opaque
origin:

"3. Let origin be a unique opaque origin."
https://drafts.css-houdini.org/worklets/#script-settings-for-worklets

However, our current impl doesn't obey this requirement. PaintWorklet inherits
its owner document's SecurityOrigin. AnimationWorklet and AudioWorklet create a
SecurityOrigin based on their script URL. This CL replaces them with
SecurityOrigin::CreateUnique().

(2) Our current impl checks CORS etc based on ExecutionContext's SecurityOrigin
associated with Modulator. For Worklets, these are WorkletGlobalScope and
WorkletModulatorImpl. However, Worklets need to fetch their scripts as
sub-resources of the owner Document, so the security checks are conducted based
on the owner Document's SecurityOrigin. After changes for (1), SecurityOrigin is
a unique opaque origin and it fails a bunch of tests because of CORS check
failures. To fix this, WorkletModulatorImpl overrides GetSecurityOrigin() to
provide the owner Document's SecurityOrigin for module fetch.

Bug: 773772, 773778
Change-Id: I451999ef09b943c480e907e6536ca8819f446d5b
Reviewed-on: https://chromium-review.googlesource.com/714499
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509328}
parent 450a7fbf
......@@ -17,6 +17,10 @@ ModulatorImplBase* WorkletModulatorImpl::Create(
WorkletModulatorImpl::WorkletModulatorImpl(RefPtr<ScriptState> script_state)
: ModulatorImplBase(std::move(script_state)) {}
SecurityOrigin* WorkletModulatorImpl::GetSecurityOriginForFetch() {
return ToWorkletGlobalScope(GetExecutionContext())->DocumentSecurityOrigin();
}
ModuleScriptFetcher* WorkletModulatorImpl::CreateModuleScriptFetcher() {
auto global_scope = ToWorkletGlobalScope(GetExecutionContext());
return new WorkletModuleScriptFetcher(
......
......@@ -22,6 +22,7 @@ class WorkletModulatorImpl final : public ModulatorImplBase {
static ModulatorImplBase* Create(RefPtr<ScriptState>);
// Implements Modulator.
SecurityOrigin* GetSecurityOriginForFetch() override;
ModuleScriptFetcher* CreateModuleScriptFetcher() override;
private:
......
......@@ -176,8 +176,7 @@ void ModuleScriptLoaderTest::InitializeForWorklet() {
WTF::MakeUnique<MainThreadWorkletReportingProxy>(&GetDocument());
global_scope_ = new MainThreadWorkletGlobalScope(
&GetFrame(), KURL(kParsedURLString, "https://example.test/worklet.js"),
"fake user agent", GetDocument().GetSecurityOrigin(),
ToIsolate(&GetDocument()), *reporting_proxy_);
"fake user agent", ToIsolate(&GetDocument()), *reporting_proxy_);
global_scope_->ScriptController()->InitializeContextIfNeeded("Dummy Context");
modulator_ = new ModuleScriptLoaderTestModulator(
global_scope_->ScriptController()->GetScriptState(),
......
......@@ -32,8 +32,7 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
cached_meta_data(std::move(cached_meta_data)),
start_mode(start_mode),
referrer_policy(referrer_policy.IsolatedCopy()),
starter_origin_privilege_data(
starter_origin ? starter_origin->CreatePrivilegeData() : nullptr),
starter_origin(starter_origin ? starter_origin->IsolatedCopy() : nullptr),
worker_clients(worker_clients),
address_space(address_space),
worker_settings(std::move(worker_settings)),
......
......@@ -67,16 +67,19 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
String referrer_policy;
std::unique_ptr<Vector<String>> origin_trial_tokens;
// The SecurityOrigin of the Document creating a Worker may have
// been configured with extra policy privileges when it was created
// (e.g., enforce path-based file:// origins.)
// To ensure that these are transferred to the origin of a new worker
// global scope, supply the Document's SecurityOrigin as the
// 'starter origin'.
// The SecurityOrigin of the Document creating a Worker/Worklet.
//
// See SecurityOrigin::transferPrivilegesFrom() for details on what
// privileges are transferred.
std::unique_ptr<SecurityOrigin::PrivilegeData> starter_origin_privilege_data;
// For Workers, the origin may have been configured with extra policy
// privileges when it was created (e.g., enforce path-based file:// origins.)
// To ensure that these are transferred to the origin of a new worker global
// scope, supply the Document's SecurityOrigin as the 'starter origin'. See
// SecurityOrigin::TransferPrivilegesFrom() for details on what privileges are
// transferred.
//
// For Worklets, the origin is used for fetching module scripts. Worklet
// scripts need to be fetched as sub-resources of the Document, and a module
// script loader uses Document's SecurityOrigin for security checks.
RefPtr<SecurityOrigin> starter_origin;
// This object is created and initialized on the thread creating
// a new worker context, but ownership of it and this
......
......@@ -17,12 +17,11 @@ MainThreadWorkletGlobalScope::MainThreadWorkletGlobalScope(
LocalFrame* frame,
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
v8::Isolate* isolate,
WorkerReportingProxy& reporting_proxy)
: WorkletGlobalScope(url,
user_agent,
std::move(security_origin),
frame->GetDocument()->GetSecurityOrigin(),
isolate,
nullptr /* worker_clients */,
reporting_proxy),
......
......@@ -25,7 +25,6 @@ class CORE_EXPORT MainThreadWorkletGlobalScope
MainThreadWorkletGlobalScope(LocalFrame*,
const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
v8::Isolate*,
WorkerReportingProxy&);
~MainThreadWorkletGlobalScope() override;
......
......@@ -41,25 +41,32 @@ class MainThreadWorkletReportingProxyForTest final
class MainThreadWorkletTest : public ::testing::Test {
public:
void SetUp() override {
KURL url(kParsedURLString, "https://example.com/");
page_ = DummyPageHolder::Create();
security_origin_ = SecurityOrigin::Create(url);
reporting_proxy_ = WTF::MakeUnique<MainThreadWorkletReportingProxyForTest>(
page_->GetFrame().GetDocument());
Document* document = page_->GetFrame().GetDocument();
document->SetURL(KURL(kParsedURLString, "https://example.com/"));
document->UpdateSecurityOrigin(SecurityOrigin::Create(document->Url()));
reporting_proxy_ =
std::make_unique<MainThreadWorkletReportingProxyForTest>(document);
global_scope_ = new MainThreadWorkletGlobalScope(
&page_->GetFrame(), url, "fake user agent", security_origin_.get(),
ToIsolate(page_->GetFrame().GetDocument()), *reporting_proxy_);
&page_->GetFrame(), document->Url(), "fake user agent",
ToIsolate(document), *reporting_proxy_);
}
void TearDown() override { global_scope_->Terminate(); }
protected:
RefPtr<SecurityOrigin> security_origin_;
std::unique_ptr<DummyPageHolder> page_;
std::unique_ptr<MainThreadWorkletReportingProxyForTest> reporting_proxy_;
Persistent<MainThreadWorkletGlobalScope> global_scope_;
};
TEST_F(MainThreadWorkletTest, SecurityOrigin) {
// The SecurityOrigin for a worklet should be a unique opaque origin, while
// the owner Document's SecurityOrigin shouldn't.
EXPECT_TRUE(global_scope_->GetSecurityOrigin()->IsUnique());
EXPECT_FALSE(global_scope_->DocumentSecurityOrigin()->IsUnique());
}
TEST_F(MainThreadWorkletTest, UseCounter) {
Document& document = *page_->GetFrame().GetDocument();
......
......@@ -20,13 +20,13 @@ namespace blink {
ThreadedWorkletGlobalScope::ThreadedWorkletGlobalScope(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerThread* thread,
WorkerClients* worker_clients)
: WorkletGlobalScope(url,
user_agent,
std::move(security_origin),
std::move(document_security_origin),
isolate,
worker_clients,
thread->GetWorkerReportingProxy()),
......
......@@ -28,7 +28,7 @@ class CORE_EXPORT ThreadedWorkletGlobalScope : public WorkletGlobalScope {
protected:
ThreadedWorkletGlobalScope(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
......
......@@ -76,6 +76,17 @@ class ThreadedWorkletThreadForTest : public WorkerThread {
WorkletThreadHolder<ThreadedWorkletThreadForTest>::ClearInstance();
}
void TestSecurityOrigin() {
WorkletGlobalScope* global_scope = ToWorkletGlobalScope(GlobalScope());
// The SecurityOrigin for a worklet should be a unique opaque origin, while
// the owner Document's SecurityOrigin shouldn't.
EXPECT_TRUE(global_scope->GetSecurityOrigin()->IsUnique());
EXPECT_FALSE(global_scope->DocumentSecurityOrigin()->IsUnique());
GetParentFrameTaskRunners()
->Get(TaskType::kUnspecedTimer)
->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
}
// Emulates API use on ThreadedWorkletGlobalScope.
void CountFeature(WebFeature feature) {
EXPECT_TRUE(IsCurrentThread());
......@@ -199,6 +210,17 @@ class ThreadedWorkletTest : public ::testing::Test {
Persistent<ThreadedWorkletMessagingProxyForTest> messaging_proxy_;
};
TEST_F(ThreadedWorkletTest, SecurityOrigin) {
MessagingProxy()->Start();
TaskRunnerHelper::Get(TaskType::kUnspecedTimer, GetWorkerThread())
->PostTask(
BLINK_FROM_HERE,
CrossThreadBind(&ThreadedWorkletThreadForTest::TestSecurityOrigin,
CrossThreadUnretained(GetWorkerThread())));
testing::EnterRunLoop();
}
TEST_F(ThreadedWorkletTest, UseCounter) {
MessagingProxy()->Start();
......
......@@ -385,9 +385,9 @@ WorkerGlobalScope::WorkerGlobalScope(
InstanceCounters::IncrementCounter(
InstanceCounters::kWorkerGlobalScopeCounter);
SetSecurityOrigin(SecurityOrigin::Create(url_));
if (creation_params->starter_origin_privilege_data) {
if (creation_params->starter_origin) {
GetSecurityOrigin()->TransferPrivilegesFrom(
std::move(creation_params->starter_origin_privilege_data));
creation_params->starter_origin->CreatePrivilegeData());
}
ApplyContentSecurityPolicyFromVector(
*creation_params->content_security_policy_parsed_headers);
......
......@@ -21,16 +21,28 @@
namespace blink {
WorkletGlobalScope::WorkletGlobalScope(const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
v8::Isolate* isolate,
WorkerClients* worker_clients,
WorkerReportingProxy& reporting_proxy)
// Partial implementation of the "set up a worklet environment settings object"
// algorithm:
// https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
WorkletGlobalScope::WorkletGlobalScope(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerClients* worker_clients,
WorkerReportingProxy& reporting_proxy)
: WorkerOrWorkletGlobalScope(isolate, worker_clients, reporting_proxy),
url_(url),
user_agent_(user_agent) {
SetSecurityOrigin(std::move(security_origin));
user_agent_(user_agent),
document_security_origin_(document_security_origin) {
// Step 2: "Let inheritedAPIBaseURL be outsideSettings's API base URL."
// |url_| is the inheritedAPIBaseURL passed from the parent Document.
// Step 3: "Let origin be a unique opaque origin."
SetSecurityOrigin(SecurityOrigin::CreateUnique());
// Step 5: "Let inheritedReferrerPolicy be outsideSettings's referrer policy."
// TODO(nhiroki): Set the referrer policy (https://crbug.com/773921).
}
WorkletGlobalScope::~WorkletGlobalScope() = default;
......
......@@ -102,15 +102,23 @@ class CORE_EXPORT WorkletGlobalScope
void SetModulator(Modulator*);
SecurityOrigin* DocumentSecurityOrigin() const {
return document_security_origin_.get();
}
DECLARE_VIRTUAL_TRACE();
DECLARE_VIRTUAL_TRACE_WRAPPERS();
protected:
// The url, userAgent and securityOrigin arguments are inherited from the
// parent ExecutionContext for Worklets.
// Partial implementation of the "set up a worklet environment settings
// object" algorithm:
// https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
//
// The url, user_agent and document_security_origin arguments are inherited
// from the parent Document.
WorkletGlobalScope(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerClients*,
WorkerReportingProxy&);
......@@ -121,6 +129,10 @@ class CORE_EXPORT WorkletGlobalScope
const KURL url_;
const String user_agent_;
// Used for module fetch.
const RefPtr<SecurityOrigin> document_security_origin_;
Member<WorkletModuleResponsesMapProxy> module_responses_map_proxy_;
// LocalDOMWindow::modulator_ workaround equivalent.
// TODO(kouhei): Remove this.
......
......@@ -21,25 +21,25 @@ namespace blink {
AnimationWorkletGlobalScope* AnimationWorkletGlobalScope::Create(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerThread* thread,
WorkerClients* worker_clients) {
return new AnimationWorkletGlobalScope(url, user_agent,
std::move(security_origin), isolate,
thread, worker_clients);
std::move(document_security_origin),
isolate, thread, worker_clients);
}
AnimationWorkletGlobalScope::AnimationWorkletGlobalScope(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerThread* thread,
WorkerClients* worker_clients)
: ThreadedWorkletGlobalScope(url,
user_agent,
std::move(security_origin),
std::move(document_security_origin),
isolate,
thread,
worker_clients) {
......
......@@ -31,12 +31,13 @@ class MODULES_EXPORT AnimationWorkletGlobalScope
DEFINE_WRAPPERTYPEINFO();
public:
static AnimationWorkletGlobalScope* Create(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
static AnimationWorkletGlobalScope* Create(
const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
~AnimationWorkletGlobalScope() override;
DECLARE_TRACE();
DECLARE_TRACE_WRAPPERS();
......@@ -58,7 +59,7 @@ class MODULES_EXPORT AnimationWorkletGlobalScope
private:
AnimationWorkletGlobalScope(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
......
......@@ -81,17 +81,9 @@ WorkerOrWorkletGlobalScope* AnimationWorkletThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"),
"AnimationWorkletThread::createWorkerGlobalScope");
RefPtr<SecurityOrigin> security_origin =
SecurityOrigin::Create(creation_params->script_url);
if (creation_params->starter_origin_privilege_data) {
security_origin->TransferPrivilegesFrom(
std::move(creation_params->starter_origin_privilege_data));
}
return AnimationWorkletGlobalScope::Create(
creation_params->script_url, creation_params->user_agent,
std::move(security_origin), this->GetIsolate(), this,
std::move(creation_params->starter_origin), this->GetIsolate(), this,
creation_params->worker_clients);
}
......
......@@ -171,38 +171,32 @@ PaintWorkletGlobalScope* PaintWorkletGlobalScope::Create(
LocalFrame* frame,
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
v8::Isolate* isolate,
WorkerReportingProxy& reporting_proxy,
PaintWorkletPendingGeneratorRegistry* pending_generator_registry,
size_t global_scope_number) {
PaintWorkletGlobalScope* paint_worklet_global_scope =
new PaintWorkletGlobalScope(frame, url, user_agent,
std::move(security_origin), isolate,
auto* global_scope =
new PaintWorkletGlobalScope(frame, url, user_agent, isolate,
reporting_proxy, pending_generator_registry);
String context_name("PaintWorklet #");
context_name.append(String::Number(global_scope_number));
paint_worklet_global_scope->ScriptController()->InitializeContextIfNeeded(
context_name);
global_scope->ScriptController()->InitializeContextIfNeeded(context_name);
MainThreadDebugger::Instance()->ContextCreated(
paint_worklet_global_scope->ScriptController()->GetScriptState(),
paint_worklet_global_scope->GetFrame(),
paint_worklet_global_scope->GetSecurityOrigin());
return paint_worklet_global_scope;
global_scope->ScriptController()->GetScriptState(),
global_scope->GetFrame(), global_scope->GetSecurityOrigin());
return global_scope;
}
PaintWorkletGlobalScope::PaintWorkletGlobalScope(
LocalFrame* frame,
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
v8::Isolate* isolate,
WorkerReportingProxy& reporting_proxy,
PaintWorkletPendingGeneratorRegistry* pending_generator_registry)
: MainThreadWorkletGlobalScope(frame,
url,
user_agent,
std::move(security_origin),
isolate,
reporting_proxy),
pending_generator_registry_(pending_generator_registry) {}
......
......@@ -28,7 +28,6 @@ class MODULES_EXPORT PaintWorkletGlobalScope final
static PaintWorkletGlobalScope* Create(LocalFrame*,
const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
v8::Isolate*,
WorkerReportingProxy&,
PaintWorkletPendingGeneratorRegistry*,
......@@ -51,7 +50,6 @@ class MODULES_EXPORT PaintWorkletGlobalScope final
PaintWorkletGlobalScope(LocalFrame*,
const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
v8::Isolate*,
WorkerReportingProxy&,
PaintWorkletPendingGeneratorRegistry*);
......
......@@ -26,9 +26,8 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
Document* document = frame->GetDocument();
reporting_proxy_ = WTF::MakeUnique<MainThreadWorkletReportingProxy>(document);
global_scope_ = PaintWorkletGlobalScope::Create(
frame, document->Url(), document->UserAgent(),
document->GetSecurityOrigin(), ToIsolate(document), *reporting_proxy_,
pending_generator_registry, global_scope_number);
frame, document->Url(), document->UserAgent(), ToIsolate(document),
*reporting_proxy_, pending_generator_registry, global_scope_number);
}
void PaintWorkletGlobalScopeProxy::FetchAndInvokeScript(
......
......@@ -29,25 +29,25 @@ namespace blink {
AudioWorkletGlobalScope* AudioWorkletGlobalScope::Create(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerThread* thread,
WorkerClients* worker_clients) {
return new AudioWorkletGlobalScope(url, user_agent,
std::move(security_origin), isolate,
thread, worker_clients);
std::move(document_security_origin),
isolate, thread, worker_clients);
}
AudioWorkletGlobalScope::AudioWorkletGlobalScope(
const KURL& url,
const String& user_agent,
RefPtr<SecurityOrigin> security_origin,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate* isolate,
WorkerThread* thread,
WorkerClients* worker_clients)
: ThreadedWorkletGlobalScope(url,
user_agent,
std::move(security_origin),
std::move(document_security_origin),
isolate,
thread,
worker_clients) {}
......
......@@ -28,12 +28,13 @@ class MODULES_EXPORT AudioWorkletGlobalScope final
DEFINE_WRAPPERTYPEINFO();
public:
static AudioWorkletGlobalScope* Create(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
static AudioWorkletGlobalScope* Create(
const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
~AudioWorkletGlobalScope() override;
bool IsAudioWorkletGlobalScope() const final { return true; }
void registerProcessor(const String& name,
......@@ -71,7 +72,7 @@ class MODULES_EXPORT AudioWorkletGlobalScope final
private:
AudioWorkletGlobalScope(const KURL&,
const String& user_agent,
RefPtr<SecurityOrigin>,
RefPtr<SecurityOrigin> document_security_origin,
v8::Isolate*,
WorkerThread*,
WorkerClients*);
......
......@@ -105,17 +105,9 @@ WorkerOrWorkletGlobalScope* AudioWorkletThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
"AudioWorkletThread::createWorkerGlobalScope");
RefPtr<SecurityOrigin> security_origin =
SecurityOrigin::Create(creation_params->script_url);
if (creation_params->starter_origin_privilege_data) {
security_origin->TransferPrivilegesFrom(
std::move(creation_params->starter_origin_privilege_data));
}
return AudioWorkletGlobalScope::Create(
creation_params->script_url, creation_params->user_agent,
std::move(security_origin), this->GetIsolate(), this,
std::move(creation_params->starter_origin), this->GetIsolate(), this,
creation_params->worker_clients);
}
......
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