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; |
| 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, |
| 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 |
| 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. Ideally this would test chrome-extension:// |
| 390 // URLs for Chrome Apps, but those can't be tested inside content/ and the |
| 391 // ResourceHostMsg_Request IPC can't be created in a test outside content/. |
| 392 NavigateToURL(shell(), web_url); |
| 393 { |
| 394 // Set up a ContentBrowserClient that simulates an app URL in a non-app |
| 395 // process. |
| 396 IsolatedAppContentBrowserClient app_client; |
| 397 ContentBrowserClient* old_client = SetBrowserClientForTesting(&app_client); |
| 398 RenderProcessHostWatcher web_process_killed( |
| 399 web_rfh->GetProcess(), |
| 400 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 401 IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| 402 web_rfh->GetProcess()->GetChannel(), |
| 403 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, |
| 404 embedder_isolated_origin_msg)); |
| 405 web_process_killed.Wait(); |
| 406 SetBrowserClientForTesting(old_client); |
| 407 } |
| 408 |
| 409 // Web processes cannot make XHRs with invalid Origin headers. |
| 410 NavigateToURL(shell(), web_url); |
| 411 { |
| 412 RenderProcessHostWatcher web_process_killed( |
| 413 web_rfh->GetProcess(), |
| 414 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 415 IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| 416 web_rfh->GetProcess()->GetChannel(), |
| 417 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, |
| 418 invalid_origin_msg)); |
| 419 web_process_killed.Wait(); |
| 420 } |
| 421 |
| 422 // Web processes cannot make XHRs with invalid scheme Origin headers. |
| 423 NavigateToURL(shell(), web_url); |
| 424 { |
| 425 RenderProcessHostWatcher web_process_killed( |
| 426 web_rfh->GetProcess(), |
| 427 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 428 IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| 429 web_rfh->GetProcess()->GetChannel(), |
| 430 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1, |
| 431 invalid_scheme_origin_msg)); |
| 432 web_process_killed.Wait(); |
| 433 } |
| 434 } |
| 435 |
324 } // namespace content | 436 } // namespace content |
OLD | NEW |