diff options
author | nick <nick@chromium.org> | 2014-11-13 20:11:49 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-14 04:13:06 +0000 |
commit | 4c8dfd482ad484f2402a5d9bea921870f3ea5d89 (patch) | |
tree | 539588cc49bc86d99d61391c3ac468c41eb55bda /content/browser/security_exploit_browsertest.cc | |
parent | f0ba8deca9141fc42e0a9746395f6843541bcde0 (diff) | |
download | chromium_src-4c8dfd482ad484f2402a5d9bea921870f3ea5d89.zip chromium_src-4c8dfd482ad484f2402a5d9bea921870f3ea5d89.tar.gz chromium_src-4c8dfd482ad484f2402a5d9bea921870f3ea5d89.tar.bz2 |
IPC: a way for security exploit browsertests to simulate the appearance of a malicious IPC.
Use this to add a SecurityExploitBrowserTest for http://crbug.com/429922
Fix SecurityExploitBrowserTests on Android. Re-enable SecurityExploitBrowserTests on Android, except for two issues (1) the new test, which is actually disabled because of http://crbug.com/432737, discovered while developing this CL and (2) SetWebUIProperty, which is disabled because of http://crbug.com/433068, also discovered while developing this CL. Moral of the story being: never try.
BUG=429922,432737,338023,433068
TEST=content_browsertests
Review URL: https://codereview.chromium.org/712713002
Cr-Commit-Position: refs/heads/master@{#304170}
Diffstat (limited to 'content/browser/security_exploit_browsertest.cc')
-rw-r--r-- | content/browser/security_exploit_browsertest.cc | 127 |
1 files changed, 121 insertions, 6 deletions
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 2a1be07..68430ad 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc @@ -4,14 +4,18 @@ #include "base/command_line.h" #include "base/containers/hash_tables.h" +#include "base/strings/utf_string_conversions.h" #include "content/browser/dom_storage/dom_storage_context_wrapper.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" #include "content/browser/frame_host/navigator.h" #include "content/browser/renderer_host/render_view_host_factory.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/frame_messages.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/interstitial_page.h" +#include "content/public/browser/interstitial_page_delegate.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" @@ -19,6 +23,11 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.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" + +using IPC::IpcSecurityTestUtil; namespace content { @@ -35,10 +44,11 @@ namespace { // the attempt is the return value. RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell, int* target_routing_id) { - GURL foo("http://foo.com/files/simple_page.html"); + GURL foo("http://foo.com/simple_page.html"); // Start off with initial navigation, so we get the first process allocated. NavigateToURL(shell, foo); + EXPECT_EQ(base::ASCIIToUTF16("OK"), shell->web_contents()->GetTitle()); // Open another window, so we generate some more routing ids. ShellAddedObserver shell2_observer; @@ -55,7 +65,7 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell, shell->web_contents()->GetRenderViewHost()->GetRoutingID()); // Now, simulate a link click coming from the renderer. - GURL extension_url("https://bar.com/files/simple_page.html"); + GURL extension_url("https://bar.com/simple_page.html"); WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents()); wc->GetFrameTree()->root()->navigator()->RequestOpenURL( wc->GetFrameTree()->root()->current_frame_host(), extension_url, @@ -84,25 +94,37 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell, class SecurityExploitBrowserTest : public ContentBrowserTest { public: SecurityExploitBrowserTest() {} + void SetUpCommandLine(CommandLine* command_line) override { - ASSERT_TRUE(test_server()->Start()); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); // Add a host resolver rule to map all outgoing requests to the test server. // This allows us to use "real" hostnames in URLs, which we can use to // create arbitrary SiteInstances. command_line->AppendSwitchASCII( switches::kHostResolverRules, - "MAP * " + test_server()->host_port_pair().ToString() + + "MAP * " + + net::HostPortPair::FromURL(embedded_test_server()->base_url()) + .ToString() + ",EXCLUDE localhost"); } }; +// Fails because the process kill on Android does not succeed. +// http://crbug.com/433068 +#if defined(OS_ANDROID) +#define MAYBE_SetWebUIProperty DISABLED_SetWebUIProperty +#else +#define MAYBE_SetWebUIProperty SetWebUIProperty +#endif + // Ensure that we kill the renderer process if we try to give it WebUI // properties and it doesn't have enabled WebUI bindings. -IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) { - GURL foo("http://foo.com/files/simple_page.html"); +IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, MAYBE_SetWebUIProperty) { + GURL foo("http://foo.com/simple_page.html"); NavigateToURL(shell(), foo); + EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); EXPECT_EQ(0, shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings()); @@ -166,4 +188,97 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, // If the above operation doesn't crash, the test has succeeded! } +class SecurityExploitTestInterstitialPage : public InterstitialPageDelegate { + public: + explicit SecurityExploitTestInterstitialPage(WebContents* contents) { + InterstitialPage* interstitial = InterstitialPage::Create( + contents, true, contents->GetLastCommittedURL(), this); + interstitial->Show(); + } + + // InterstitialPageDelegate implementation. + void CommandReceived(const std::string& command) override { + last_command_ = command; + } + + std::string GetHTMLContents() override { + return "<html><head><script>" + "window.domAutomationController.setAutomationId(1);" + "window.domAutomationController.send(\"okay\");" + "</script></head>" + "<body>this page is an interstitial</body></html>"; + } + + std::string last_command() { return last_command_; } + + private: + std::string last_command_; + DISALLOW_COPY_AND_ASSIGN(SecurityExploitTestInterstitialPage); +}; + +// Fails due to InterstitialPage's reliance on PostNonNestableTask +// http://crbug.com/432737 +#if defined(OS_ANDROID) +#define MAYBE_InterstitialCommandFromUnderlyingContent \ + DISABLED_InterstitialCommandFromUnderlyingContent +#else +#define MAYBE_InterstitialCommandFromUnderlyingContent \ + InterstitialCommandFromUnderlyingContent +#endif + +// The interstitial should not be controllable by the underlying content. +IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, + MAYBE_InterstitialCommandFromUnderlyingContent) { + // Start off with initial navigation, to allocate the process. + GURL foo("http://foo.com/simple_page.html"); + NavigateToURL(shell(), foo); + EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); + + DOMMessageQueue message_queue; + + // Install and show an interstitial page. + SecurityExploitTestInterstitialPage* interstitial = + new SecurityExploitTestInterstitialPage(shell()->web_contents()); + + ASSERT_EQ("", interstitial->last_command()); + content::WaitForInterstitialAttach(shell()->web_contents()); + + InterstitialPage* interstitial_page = + shell()->web_contents()->GetInterstitialPage(); + ASSERT_TRUE(interstitial_page != NULL); + ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage()); + ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial); + + // The interstitial page ought to be able to send a message. + std::string message; + ASSERT_TRUE(message_queue.WaitForMessage(&message)); + ASSERT_EQ("\"okay\"", message); + ASSERT_EQ("\"okay\"", interstitial->last_command()); + + // Send an automation message from the underlying content and wait for it to + // be dispatched on this thread. This message should not be received by the + // interstitial. + content::RenderFrameHost* compromised_renderer = + shell()->web_contents()->GetMainFrame(); + FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(), + "evil", MSG_ROUTING_NONE); + IpcSecurityTestUtil::PwnMessageReceived( + compromised_renderer->GetProcess()->GetChannel(), evil); + + ASSERT_TRUE(message_queue.WaitForMessage(&message)); + ASSERT_EQ("evil", message) + << "Automation message should be received by WebContents."; + ASSERT_EQ("\"okay\"", interstitial->last_command()) + << "Interstitial should not be affected."; + + // Send a second message from the interstitial page, and make sure that the + // "evil" message doesn't arrive in the intervening period. + ASSERT_TRUE(content::ExecuteScript( + interstitial_page->GetRenderViewHostForTesting(), + "window.domAutomationController.send(\"okay2\");")); + ASSERT_TRUE(message_queue.WaitForMessage(&message)); + ASSERT_EQ("\"okay2\"", message); + ASSERT_EQ("\"okay2\"", interstitial->last_command()); +} + } // namespace content |