| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/command_line.h" |
| #include "base/macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/singleton_tabs.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "content/common/fileapi/webblob_messages.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/resource_request_details.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "ipc/ipc_security_test_util.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| |
| // The goal of these tests is to "simulate" exploited renderer processes, which |
| // can send arbitrary IPC messages and confuse browser process internal state, |
| // leading to security bugs. We are trying to verify that the browser doesn't |
| // perform any dangerous operations in such cases. |
| // This is similar to the security_exploit_browsertest.cc tests, but also |
| // includes chrome/ layer concepts such as extensions. |
| class ChromeSecurityExploitBrowserTest : public InProcessBrowserTest { |
| public: |
| ChromeSecurityExploitBrowserTest() {} |
| ~ChromeSecurityExploitBrowserTest() override {} |
| |
| void SetUpOnMainThread() override { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // Since we assume exploited renderer process, it can bypass the same origin |
| // policy at will. Simulate that by passing the disable-web-security flag. |
| command_line->AppendSwitch(switches::kDisableWebSecurity); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ChromeSecurityExploitBrowserTest); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTest, |
| ChromeExtensionResources) { |
| // Load a page that requests a chrome-extension:// image through XHR. We |
| // expect this load to fail, as it is an illegal request. |
| GURL foo = embedded_test_server()->GetURL("foo.com", |
| "/chrome_extension_resource.html"); |
| |
| content::DOMMessageQueue msg_queue; |
| |
| ui_test_utils::NavigateToURL(browser(), foo); |
| |
| std::string status; |
| std::string expected_status("0"); |
| EXPECT_TRUE(msg_queue.WaitForMessage(&status)); |
| EXPECT_STREQ(status.c_str(), expected_status.c_str()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTest, |
| CreateBlobInExtensionOrigin) { |
| ui_test_utils::NavigateToURL( |
| browser(), |
| embedded_test_server()->GetURL("a.root-servers.net", "/title1.html")); |
| |
| content::RenderFrameHost* rfh = |
| browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); |
| |
| // All these are attacker controlled values. The UUID is arbitrary. |
| std::string blob_id = "2ce53a26-0409-45a3-86e5-f8fb9f5566d8"; |
| std::string blob_type = "text/html"; |
| std::string blob_contents = "<script>chrome.extensions</script>"; |
| std::string blob_path = "5881f76e-10d2-410d-8c61-ef210502acfd"; |
| |
| // Target the bookmark manager extension. |
| std::string target_origin = |
| "chrome-extension://eemcgdkfndhakfknompkggombfjjjeno"; |
| |
| std::vector<storage::DataElement> data_elements(1); |
| data_elements[0].SetToBytes(blob_contents.c_str(), blob_contents.size()); |
| |
| // Set up a blob ID and populate it with attacker-controlled value. These two |
| // messages are allowed, because this data is not in any origin. |
| IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| rfh->GetProcess()->GetChannel(), |
| BlobStorageMsg_RegisterBlobUUID(blob_id, blob_type, "", |
| std::set<std::string>())); |
| |
| IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| rfh->GetProcess()->GetChannel(), |
| BlobStorageMsg_StartBuildingBlob(blob_id, data_elements)); |
| |
| // This IPC should result in a kill because |target_origin| is not commitable |
| // in |rfh->GetProcess()|. |
| content::RenderProcessHostWatcher crash_observer( |
| rfh->GetProcess(), |
| content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| rfh->GetProcess()->GetChannel(), |
| BlobHostMsg_RegisterPublicURL( |
| GURL("blob:" + target_origin + "/" + blob_path), blob_id)); |
| crash_observer.Wait(); // If the process is killed, this test passes. |
| } |