Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "base/containers/hash_tables.h" | 6 #include "base/containers/hash_tables.h" |
| 7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
| 8 #include "content/browser/dom_storage/dom_storage_context_wrapper.h" | 8 #include "content/browser/dom_storage/dom_storage_context_wrapper.h" |
| 9 #include "content/browser/dom_storage/session_storage_namespace_impl.h" | 9 #include "content/browser/dom_storage/session_storage_namespace_impl.h" |
| 10 #include "content/browser/frame_host/navigator.h" | 10 #include "content/browser/frame_host/navigator.h" |
| 11 #include "content/browser/frame_host/render_frame_host_impl.h" | |
| 11 #include "content/browser/renderer_host/render_view_host_factory.h" | 12 #include "content/browser/renderer_host/render_view_host_factory.h" |
| 12 #include "content/browser/renderer_host/render_view_host_impl.h" | 13 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 13 #include "content/browser/web_contents/web_contents_impl.h" | 14 #include "content/browser/web_contents/web_contents_impl.h" |
| 14 #include "content/common/frame_messages.h" | 15 #include "content/common/frame_messages.h" |
| 16 #include "content/common/resource_messages.h" | |
| 15 #include "content/common/view_messages.h" | 17 #include "content/common/view_messages.h" |
| 16 #include "content/public/browser/browser_context.h" | 18 #include "content/public/browser/browser_context.h" |
| 19 #include "content/public/browser/content_browser_client.h" | |
| 17 #include "content/public/browser/interstitial_page.h" | 20 #include "content/public/browser/interstitial_page.h" |
| 18 #include "content/public/browser/interstitial_page_delegate.h" | 21 #include "content/public/browser/interstitial_page_delegate.h" |
| 19 #include "content/public/browser/storage_partition.h" | 22 #include "content/public/browser/storage_partition.h" |
| 23 #include "content/public/common/appcache_info.h" | |
| 20 #include "content/public/common/content_switches.h" | 24 #include "content/public/common/content_switches.h" |
| 21 #include "content/public/common/file_chooser_params.h" | 25 #include "content/public/common/file_chooser_params.h" |
| 22 #include "content/public/test/browser_test_utils.h" | 26 #include "content/public/test/browser_test_utils.h" |
| 23 #include "content/public/test/content_browser_test.h" | 27 #include "content/public/test/content_browser_test.h" |
| 24 #include "content/public/test/content_browser_test_utils.h" | 28 #include "content/public/test/content_browser_test_utils.h" |
| 25 #include "content/public/test/test_utils.h" | 29 #include "content/public/test/test_utils.h" |
| 26 #include "content/shell/browser/shell.h" | 30 #include "content/shell/browser/shell.h" |
| 31 #include "content/test/test_content_browser_client.h" | |
| 27 #include "ipc/ipc_security_test_util.h" | 32 #include "ipc/ipc_security_test_util.h" |
| 28 #include "net/dns/mock_host_resolver.h" | 33 #include "net/dns/mock_host_resolver.h" |
| 29 #include "net/test/embedded_test_server/embedded_test_server.h" | 34 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 30 | 35 |
| 31 using IPC::IpcSecurityTestUtil; | 36 using IPC::IpcSecurityTestUtil; |
| 32 | 37 |
| 33 namespace content { | 38 namespace content { |
| 34 | 39 |
| 35 namespace { | 40 namespace { |
| 36 | 41 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 next_rfh = wc->GetRenderManagerForTesting()->pending_frame_host(); | 89 next_rfh = wc->GetRenderManagerForTesting()->pending_frame_host(); |
| 85 } | 90 } |
| 86 | 91 |
| 87 EXPECT_TRUE(next_rfh); | 92 EXPECT_TRUE(next_rfh); |
| 88 EXPECT_NE(shell->web_contents()->GetRenderProcessHost()->GetID(), | 93 EXPECT_NE(shell->web_contents()->GetRenderProcessHost()->GetID(), |
| 89 next_rfh->GetProcess()->GetID()); | 94 next_rfh->GetProcess()->GetID()); |
| 90 | 95 |
| 91 return next_rfh->render_view_host(); | 96 return next_rfh->render_view_host(); |
| 92 } | 97 } |
| 93 | 98 |
| 99 ResourceHostMsg_Request CreateXHRRequestWithOrigin(const char* origin) { | |
| 100 ResourceHostMsg_Request request; | |
| 101 request.method = "GET"; | |
| 102 request.url = GURL("http://bar.com/simple_page.html"); | |
| 103 request.first_party_for_cookies = GURL(origin); | |
| 104 request.referrer_policy = blink::WebReferrerPolicyDefault; | |
| 105 request.headers = base::StringPrintf("Origin: %s\r\n", origin); | |
| 106 request.load_flags = 0; | |
| 107 request.origin_pid = 0; | |
| 108 request.resource_type = RESOURCE_TYPE_XHR; | |
| 109 request.request_context = 0; | |
| 110 request.appcache_host_id = kAppCacheNoHostId; | |
| 111 request.download_to_file = false; | |
| 112 request.should_reset_appcache = false; | |
| 113 request.is_main_frame = true; | |
| 114 request.parent_is_main_frame = false; | |
| 115 request.parent_render_frame_id = -1; | |
|
nasko
2015/08/14 22:14:43
MSG_ROUTING_NONE?
Charlie Reis
2015/08/14 23:23:32
The docs say to use -1:
https://code.google.com/p/
nasko
2015/08/14 23:36:41
Acknowledged.
| |
| 116 request.transition_type = ui::PAGE_TRANSITION_LINK; | |
| 117 request.allow_download = true; | |
| 118 return request; | |
| 119 } | |
| 120 | |
| 94 } // namespace | 121 } // namespace |
| 95 | 122 |
| 96 | 123 |
| 97 // The goal of these tests will be to "simulate" exploited renderer processes, | 124 // The goal of these tests will be to "simulate" exploited renderer processes, |
| 98 // which can send arbitrary IPC messages and confuse browser process internal | 125 // which can send arbitrary IPC messages and confuse browser process internal |
| 99 // state, leading to security bugs. We are trying to verify that the browser | 126 // state, leading to security bugs. We are trying to verify that the browser |
| 100 // doesn't perform any dangerous operations in such cases. | 127 // doesn't perform any dangerous operations in such cases. |
| 101 class SecurityExploitBrowserTest : public ContentBrowserTest { | 128 class SecurityExploitBrowserTest : public ContentBrowserTest { |
| 102 public: | 129 public: |
| 103 SecurityExploitBrowserTest() {} | 130 SecurityExploitBrowserTest() {} |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 121 // cause renderer to be killed. | 148 // cause renderer to be killed. |
| 122 void TestFileChooserWithPath(const base::FilePath& path); | 149 void TestFileChooserWithPath(const base::FilePath& path); |
| 123 }; | 150 }; |
| 124 | 151 |
| 125 void SecurityExploitBrowserTest::TestFileChooserWithPath( | 152 void SecurityExploitBrowserTest::TestFileChooserWithPath( |
| 126 const base::FilePath& path) { | 153 const base::FilePath& path) { |
| 127 GURL foo("http://foo.com/simple_page.html"); | 154 GURL foo("http://foo.com/simple_page.html"); |
| 128 NavigateToURL(shell(), foo); | 155 NavigateToURL(shell(), foo); |
| 129 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); | 156 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); |
| 130 | 157 |
| 131 content::RenderViewHost* compromised_renderer = | 158 RenderViewHost* compromised_renderer = |
| 132 shell()->web_contents()->GetRenderViewHost(); | 159 shell()->web_contents()->GetRenderViewHost(); |
| 133 content::RenderProcessHostWatcher terminated( | 160 RenderProcessHostWatcher terminated( |
| 134 shell()->web_contents(), | 161 shell()->web_contents(), |
| 135 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | 162 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 136 | 163 |
| 137 FileChooserParams params; | 164 FileChooserParams params; |
| 138 params.default_file_name = path; | 165 params.default_file_name = path; |
| 139 | 166 |
| 140 ViewHostMsg_RunFileChooser evil(compromised_renderer->GetRoutingID(), params); | 167 ViewHostMsg_RunFileChooser evil(compromised_renderer->GetRoutingID(), params); |
| 141 | 168 |
| 142 IpcSecurityTestUtil::PwnMessageReceived( | 169 IpcSecurityTestUtil::PwnMessageReceived( |
| 143 compromised_renderer->GetProcess()->GetChannel(), evil); | 170 compromised_renderer->GetProcess()->GetChannel(), evil); |
| 144 terminated.Wait(); | 171 terminated.Wait(); |
| 145 } | 172 } |
| 146 | 173 |
| 147 // Ensure that we kill the renderer process if we try to give it WebUI | 174 // Ensure that we kill the renderer process if we try to give it WebUI |
| 148 // properties and it doesn't have enabled WebUI bindings. | 175 // properties and it doesn't have enabled WebUI bindings. |
| 149 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) { | 176 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) { |
| 150 GURL foo("http://foo.com/simple_page.html"); | 177 GURL foo("http://foo.com/simple_page.html"); |
| 151 | 178 |
| 152 NavigateToURL(shell(), foo); | 179 NavigateToURL(shell(), foo); |
| 153 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); | 180 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); |
| 154 EXPECT_EQ(0, | 181 EXPECT_EQ(0, |
| 155 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings()); | 182 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings()); |
| 156 | 183 |
| 157 content::RenderProcessHostWatcher terminated( | 184 RenderProcessHostWatcher terminated( |
| 158 shell()->web_contents(), | 185 shell()->web_contents(), |
| 159 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | 186 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 160 shell()->web_contents()->GetRenderViewHost()->SetWebUIProperty( | 187 shell()->web_contents()->GetRenderViewHost()->SetWebUIProperty( |
| 161 "toolkit", "views"); | 188 "toolkit", "views"); |
| 162 terminated.Wait(); | 189 terminated.Wait(); |
| 163 } | 190 } |
| 164 | 191 |
| 165 // This is a test for crbug.com/312016 attempting to create duplicate | 192 // This is a test for crbug.com/312016 attempting to create duplicate |
| 166 // RenderViewHosts. SetupForDuplicateHosts sets up this test case and leaves | 193 // RenderViewHosts. SetupForDuplicateHosts sets up this test case and leaves |
| 167 // it in a state with pending RenderViewHost. Before the commit of the new | 194 // it in a state with pending RenderViewHost. Before the commit of the new |
| 168 // pending RenderViewHost, this test case creates a new window through the new | 195 // pending RenderViewHost, this test case creates a new window through the new |
| 169 // process. | 196 // process. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 NavigateToURL(shell(), foo); | 301 NavigateToURL(shell(), foo); |
| 275 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); | 302 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle()); |
| 276 | 303 |
| 277 DOMMessageQueue message_queue; | 304 DOMMessageQueue message_queue; |
| 278 | 305 |
| 279 // Install and show an interstitial page. | 306 // Install and show an interstitial page. |
| 280 SecurityExploitTestInterstitialPage* interstitial = | 307 SecurityExploitTestInterstitialPage* interstitial = |
| 281 new SecurityExploitTestInterstitialPage(shell()->web_contents()); | 308 new SecurityExploitTestInterstitialPage(shell()->web_contents()); |
| 282 | 309 |
| 283 ASSERT_EQ("", interstitial->last_command()); | 310 ASSERT_EQ("", interstitial->last_command()); |
| 284 content::WaitForInterstitialAttach(shell()->web_contents()); | 311 WaitForInterstitialAttach(shell()->web_contents()); |
| 285 | 312 |
| 286 InterstitialPage* interstitial_page = | 313 InterstitialPage* interstitial_page = |
| 287 shell()->web_contents()->GetInterstitialPage(); | 314 shell()->web_contents()->GetInterstitialPage(); |
| 288 ASSERT_TRUE(interstitial_page != NULL); | 315 ASSERT_TRUE(interstitial_page != NULL); |
| 289 ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage()); | 316 ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage()); |
| 290 ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial); | 317 ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial); |
| 291 | 318 |
| 292 // The interstitial page ought to be able to send a message. | 319 // The interstitial page ought to be able to send a message. |
| 293 std::string message; | 320 std::string message; |
| 294 ASSERT_TRUE(message_queue.WaitForMessage(&message)); | 321 ASSERT_TRUE(message_queue.WaitForMessage(&message)); |
| 295 ASSERT_EQ("\"okay\"", message); | 322 ASSERT_EQ("\"okay\"", message); |
| 296 ASSERT_EQ("\"okay\"", interstitial->last_command()); | 323 ASSERT_EQ("\"okay\"", interstitial->last_command()); |
| 297 | 324 |
| 298 // Send an automation message from the underlying content and wait for it to | 325 // Send an automation message from the underlying content and wait for it to |
| 299 // be dispatched on this thread. This message should not be received by the | 326 // be dispatched on this thread. This message should not be received by the |
| 300 // interstitial. | 327 // interstitial. |
| 301 content::RenderFrameHost* compromised_renderer = | 328 RenderFrameHost* compromised_renderer = |
| 302 shell()->web_contents()->GetMainFrame(); | 329 shell()->web_contents()->GetMainFrame(); |
| 303 FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(), | 330 FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(), |
| 304 "evil", MSG_ROUTING_NONE); | 331 "evil", MSG_ROUTING_NONE); |
| 305 IpcSecurityTestUtil::PwnMessageReceived( | 332 IpcSecurityTestUtil::PwnMessageReceived( |
| 306 compromised_renderer->GetProcess()->GetChannel(), evil); | 333 compromised_renderer->GetProcess()->GetChannel(), evil); |
| 307 | 334 |
| 308 ASSERT_TRUE(message_queue.WaitForMessage(&message)); | 335 ASSERT_TRUE(message_queue.WaitForMessage(&message)); |
| 309 ASSERT_EQ("evil", message) | 336 ASSERT_EQ("evil", message) |
| 310 << "Automation message should be received by WebContents."; | 337 << "Automation message should be received by WebContents."; |
| 311 ASSERT_EQ("\"okay\"", interstitial->last_command()) | 338 ASSERT_EQ("\"okay\"", interstitial->last_command()) |
| 312 << "Interstitial should not be affected."; | 339 << "Interstitial should not be affected."; |
| 313 | 340 |
| 314 // Send a second message from the interstitial page, and make sure that the | 341 // Send a second message from the interstitial page, and make sure that the |
| 315 // "evil" message doesn't arrive in the intervening period. | 342 // "evil" message doesn't arrive in the intervening period. |
| 316 ASSERT_TRUE(content::ExecuteScript( | 343 ASSERT_TRUE(ExecuteScript(interstitial_page->GetMainFrame(), |
| 317 interstitial_page->GetMainFrame(), | 344 "window.domAutomationController.send(\"okay2\");")); |
| 318 "window.domAutomationController.send(\"okay2\");")); | |
| 319 ASSERT_TRUE(message_queue.WaitForMessage(&message)); | 345 ASSERT_TRUE(message_queue.WaitForMessage(&message)); |
| 320 ASSERT_EQ("\"okay2\"", message); | 346 ASSERT_EQ("\"okay2\"", message); |
| 321 ASSERT_EQ("\"okay2\"", interstitial->last_command()); | 347 ASSERT_EQ("\"okay2\"", interstitial->last_command()); |
| 322 } | 348 } |
| 323 | 349 |
| 350 class IsolatedAppContentBrowserClient : public TestContentBrowserClient { | |
| 351 public: | |
| 352 bool IsIllegalOrigin(content::ResourceContext* resource_context, | |
|
Charlie Reis
2015/08/14 20:25:59
I wanted to test this in chrome/ with an actual ap
| |
| 353 int child_process_id, | |
| 354 const GURL& origin) override { | |
| 355 // Simulate a case where an app origin is not in an app process. | |
| 356 return true; | |
| 357 } | |
| 358 }; | |
| 359 | |
| 360 // Renderer processes should not be able to spoof Origin HTTP headers. | |
| 361 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) { | |
| 362 // Create a set of IPC messages with various Origin headers. | |
| 363 ResourceHostMsg_Request chrome_origin_msg( | |
| 364 CreateXHRRequestWithOrigin("chrome://settings")); | |
| 365 ResourceHostMsg_Request embedder_isolated_origin_msg( | |
| 366 CreateXHRRequestWithOrigin("https://isolated.bar.com")); | |
| 367 ResourceHostMsg_Request invalid_origin_msg( | |
| 368 CreateXHRRequestWithOrigin("invalidurl")); | |
| 369 ResourceHostMsg_Request invalid_scheme_origin_msg( | |
| 370 CreateXHRRequestWithOrigin("fake-scheme://foo")); | |
| 371 | |
|
nasko
2015/08/14 22:14:43
Shouldn't a test case exist for chrome-extension:/
Charlie Reis
2015/08/14 23:23:32
Sadly I can't, since chrome-extension:// doesn't e
nasko
2015/08/14 23:36:41
Might be useful to put that/similar comment in the
Charlie Reis
2015/08/17 18:32:21
Done.
| |
| 372 GURL web_url("http://foo.com/simple_page.html"); | |
| 373 NavigateToURL(shell(), web_url); | |
| 374 RenderFrameHost* web_rfh = shell()->web_contents()->GetMainFrame(); | |
| 375 | |
| 376 // Web processes cannot make XHRs with chrome:// Origin headers. | |
| 377 { | |
| 378 RenderProcessHostWatcher web_process_killed( | |
| 379 web_rfh->GetProcess(), | |
| 380 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
| 381 IPC::IpcSecurityTestUtil::PwnMessageReceived( | |
| 382 web_rfh->GetProcess()->GetChannel(), | |
| 383 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, | |
| 384 chrome_origin_msg)); | |
| 385 web_process_killed.Wait(); | |
| 386 } | |
| 387 | |
| 388 // Web processes cannot make XHRs with URLs that the content embedder expects | |
| 389 // to have process isolation. | |
| 390 NavigateToURL(shell(), web_url); | |
| 391 { | |
| 392 // Set up a ContentBrowserClient that simulates an app URL in a non-app | |
| 393 // process. | |
| 394 IsolatedAppContentBrowserClient app_client; | |
| 395 ContentBrowserClient* old_client = SetBrowserClientForTesting(&app_client); | |
| 396 RenderProcessHostWatcher web_process_killed( | |
| 397 web_rfh->GetProcess(), | |
| 398 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
| 399 IPC::IpcSecurityTestUtil::PwnMessageReceived( | |
| 400 web_rfh->GetProcess()->GetChannel(), | |
| 401 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, | |
| 402 embedder_isolated_origin_msg)); | |
| 403 web_process_killed.Wait(); | |
| 404 SetBrowserClientForTesting(old_client); | |
| 405 } | |
| 406 | |
| 407 // Web processes cannot make XHRs with invalid Origin headers. | |
| 408 NavigateToURL(shell(), web_url); | |
| 409 { | |
| 410 RenderProcessHostWatcher web_process_killed( | |
| 411 web_rfh->GetProcess(), | |
| 412 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
| 413 IPC::IpcSecurityTestUtil::PwnMessageReceived( | |
| 414 web_rfh->GetProcess()->GetChannel(), | |
| 415 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, | |
| 416 invalid_origin_msg)); | |
| 417 web_process_killed.Wait(); | |
| 418 } | |
| 419 | |
| 420 // Web processes cannot make XHRs with invalid scheme Origin headers. | |
| 421 NavigateToURL(shell(), web_url); | |
| 422 { | |
| 423 RenderProcessHostWatcher web_process_killed( | |
| 424 web_rfh->GetProcess(), | |
| 425 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
| 426 IPC::IpcSecurityTestUtil::PwnMessageReceived( | |
| 427 web_rfh->GetProcess()->GetChannel(), | |
| 428 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, | |
| 429 invalid_scheme_origin_msg)); | |
| 430 web_process_killed.Wait(); | |
| 431 } | |
| 432 } | |
| 433 | |
| 324 } // namespace content | 434 } // namespace content |
| OLD | NEW |