Commit 4bbdddfb authored by dominicc@chromium.org's avatar dominicc@chromium.org

Kill renderers which try to register Service Workers across domains.

There is a same-origin check in
ServiceWorkerContainer::registerServiceWorker, so this code should
only be reachable if something has gone wrong.

BUG=394213

Review URL: https://codereview.chromium.org/397913003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283707 0039d316-1c4b-4281-b951-d872f2087c98
parent 789a56aa
...@@ -28,14 +28,15 @@ namespace { ...@@ -28,14 +28,15 @@ namespace {
const char kShutdownErrorMessage[] = const char kShutdownErrorMessage[] =
"The Service Worker system has shutdown."; "The Service Worker system has shutdown.";
const char kDomainMismatchErrorMessage[] =
"Scope and scripts do not have the same origin";
const uint32 kFilteredMessageClasses[] = { const uint32 kFilteredMessageClasses[] = {
ServiceWorkerMsgStart, ServiceWorkerMsgStart,
EmbeddedWorkerMsgStart, EmbeddedWorkerMsgStart,
}; };
// TODO(dominicc): When crbug.com/362214 is fixed, make
// Can(R|Unr)egisterServiceWorker also check that these are secure
// origins to defend against compromised renderers.
bool CanRegisterServiceWorker(const GURL& document_url, bool CanRegisterServiceWorker(const GURL& document_url,
const GURL& pattern, const GURL& pattern,
const GURL& script_url) { const GURL& script_url) {
...@@ -196,11 +197,7 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker( ...@@ -196,11 +197,7 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
if (!CanRegisterServiceWorker( if (!CanRegisterServiceWorker(
provider_host->document_url(), pattern, script_url)) { provider_host->document_url(), pattern, script_url)) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( BadMessageReceived();
thread_id,
request_id,
WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
return; return;
} }
GetContext()->RegisterServiceWorker( GetContext()->RegisterServiceWorker(
...@@ -244,11 +241,7 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker( ...@@ -244,11 +241,7 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
} }
if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) { if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( BadMessageReceived();
thread_id,
request_id,
WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
return; return;
} }
......
...@@ -72,24 +72,32 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { ...@@ -72,24 +72,32 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
return helper_->context_wrapper(); return helper_->context_wrapper();
} }
void Register(int64 provider_id, void SendRegister(int64 provider_id, GURL pattern, GURL worker_url) {
GURL pattern,
GURL worker_url,
uint32 expected_message) {
dispatcher_host_->OnMessageReceived( dispatcher_host_->OnMessageReceived(
ServiceWorkerHostMsg_RegisterServiceWorker( ServiceWorkerHostMsg_RegisterServiceWorker(
-1, -1, provider_id, pattern, worker_url)); -1, -1, provider_id, pattern, worker_url));
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
}
void Register(int64 provider_id,
GURL pattern,
GURL worker_url,
uint32 expected_message) {
SendRegister(provider_id, pattern, worker_url);
EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
expected_message)); expected_message));
dispatcher_host_->ipc_sink()->ClearMessages(); dispatcher_host_->ipc_sink()->ClearMessages();
} }
void Unregister(int64 provider_id, GURL pattern, uint32 expected_message) { void SendUnregister(int64 provider_id, GURL pattern) {
dispatcher_host_->OnMessageReceived( dispatcher_host_->OnMessageReceived(
ServiceWorkerHostMsg_UnregisterServiceWorker( ServiceWorkerHostMsg_UnregisterServiceWorker(
-1, -1, provider_id, pattern)); -1, -1, provider_id, pattern));
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
}
void Unregister(int64 provider_id, GURL pattern, uint32 expected_message) {
SendUnregister(provider_id, pattern);
EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
expected_message)); expected_message));
dispatcher_host_->ipc_sink()->ClearMessages(); dispatcher_host_->ipc_sink()->ClearMessages();
...@@ -100,33 +108,66 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { ...@@ -100,33 +108,66 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
}; };
TEST_F(ServiceWorkerDispatcherHostTest, RegisterSameOrigin) { TEST_F(ServiceWorkerDispatcherHostTest, Register_SameOrigin) {
const int64 kProviderId = 99; // Dummy value const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo")); host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass()); context()->AddProviderHost(host.Pass());
Register(kProviderId, Register(kProviderId,
GURL("http://www.example.com/*"), GURL("https://www.example.com/*"),
GURL("http://foo.example.com/bar"), GURL("https://www.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
Register(kProviderId,
GURL("http://foo.example.com/*"),
GURL("http://www.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
Register(kProviderId,
GURL("http://foo.example.com/*"),
GURL("http://foo.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
Register(kProviderId,
GURL("http://www.example.com/*"),
GURL("http://www.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistered::ID); ServiceWorkerMsg_ServiceWorkerRegistered::ID);
} }
TEST_F(ServiceWorkerDispatcherHostTest, UnregisterSameOrigin) { TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOrigin) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
// Script has a different host
SendRegister(kProviderId,
GURL("https://www.example.com/*"),
GURL("https://foo.example.com/bar"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
// Scope has a different host
SendRegister(kProviderId,
GURL("https://foo.example.com/*"),
GURL("https://www.example.com/bar"));
EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_);
// Script has a different port
SendRegister(kProviderId,
GURL("https://www.example.com/*"),
GURL("https://www.example.com:8080/bar"));
EXPECT_EQ(3, dispatcher_host_->bad_messages_received_count_);
// Scope has a different transport
SendRegister(kProviderId,
GURL("wss://www.example.com/*"),
GURL("https://www.example.com/bar"));
EXPECT_EQ(4, dispatcher_host_->bad_messages_received_count_);
// Script and scope have different hosts
SendRegister(kProviderId,
GURL("https://foo.example.com/*"),
GURL("https://foo.example.com/bar"));
EXPECT_EQ(5, dispatcher_host_->bad_messages_received_count_);
// Script and scope URLs are invalid
SendRegister(kProviderId,
GURL(),
GURL("h@ttps://@"));
EXPECT_EQ(6, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_SameOrigin) {
const int64 kProviderId = 99; // Dummy value const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
...@@ -134,27 +175,33 @@ TEST_F(ServiceWorkerDispatcherHostTest, UnregisterSameOrigin) { ...@@ -134,27 +175,33 @@ TEST_F(ServiceWorkerDispatcherHostTest, UnregisterSameOrigin) {
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass()); context()->AddProviderHost(host.Pass());
Unregister(kProviderId,
GURL("http://foo.example.com/*"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
Unregister(kProviderId, Unregister(kProviderId,
GURL("http://www.example.com/*"), GURL("http://www.example.com/*"),
ServiceWorkerMsg_ServiceWorkerUnregistered::ID); ServiceWorkerMsg_ServiceWorkerUnregistered::ID);
} }
TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOrigin) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
SendUnregister(kProviderId, GURL("http://foo.example.com/*"));
EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) { TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
helper_->ShutdownContext(); helper_->ShutdownContext();
// Let the shutdown reach the simulated IO thread. // Let the shutdown reach the simulated IO thread.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
dispatcher_host_->OnMessageReceived( Register(-1,
ServiceWorkerHostMsg_RegisterServiceWorker(-1, -1, -1, GURL(), GURL())); GURL(),
GURL(),
// TODO(alecflett): Pump the message loop when this becomes async. ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
ASSERT_EQ(1UL, dispatcher_host_->ipc_sink()->message_count());
EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID));
} }
TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) { TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
......
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