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 |