blob: a7ba3d7eb8505f8a181cf266839e11dfee5201a8 [file] [log] [blame]
[email protected]81374f22013-02-07 02:03:451// 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
3// found in the LICENSE file.
4
avib7348942015-12-25 20:57:105#include <stdint.h>
6
[email protected]81374f22013-02-07 02:03:457#include "base/command_line.h"
[email protected]04cbd3d2013-12-04 04:58:208#include "base/containers/hash_tables.h"
avib7348942015-12-25 20:57:109#include "base/macros.h"
nick4c8dfd42014-11-14 04:11:4910#include "base/strings/utf_string_conversions.h"
avib7348942015-12-25 20:57:1011#include "build/build_config.h"
[email protected]04cbd3d2013-12-04 04:58:2012#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
13#include "content/browser/dom_storage/session_storage_namespace_impl.h"
[email protected]65920f332014-03-04 21:14:1814#include "content/browser/frame_host/navigator.h"
creis3710b2382015-08-18 00:12:1515#include "content/browser/frame_host/render_frame_host_impl.h"
[email protected]04cbd3d2013-12-04 04:58:2016#include "content/browser/renderer_host/render_view_host_factory.h"
[email protected]81374f22013-02-07 02:03:4517#include "content/browser/renderer_host/render_view_host_impl.h"
18#include "content/browser/web_contents/web_contents_impl.h"
nick4c8dfd42014-11-14 04:11:4919#include "content/common/frame_messages.h"
creis3710b2382015-08-18 00:12:1520#include "content/common/resource_messages.h"
yhirano20c94ea9b2016-05-18 05:20:4521#include "content/common/resource_request.h"
[email protected]04cbd3d2013-12-04 04:58:2022#include "content/common/view_messages.h"
23#include "content/public/browser/browser_context.h"
creis3710b2382015-08-18 00:12:1524#include "content/public/browser/content_browser_client.h"
nick4c8dfd42014-11-14 04:11:4925#include "content/public/browser/interstitial_page.h"
26#include "content/public/browser/interstitial_page_delegate.h"
gzobqq1af4fad2016-01-30 13:07:0627#include "content/public/browser/resource_dispatcher_host.h"
[email protected]04cbd3d2013-12-04 04:58:2028#include "content/public/browser/storage_partition.h"
creis3710b2382015-08-18 00:12:1529#include "content/public/common/appcache_info.h"
carloskd80262f52015-12-16 14:40:3530#include "content/public/common/browser_side_navigation_policy.h"
[email protected]81374f22013-02-07 02:03:4531#include "content/public/common/content_switches.h"
wfh815c4872015-02-25 21:01:3132#include "content/public/common/file_chooser_params.h"
[email protected]04cbd3d2013-12-04 04:58:2033#include "content/public/test/browser_test_utils.h"
[email protected]6e9def12014-03-27 20:23:2834#include "content/public/test/content_browser_test.h"
35#include "content/public/test/content_browser_test_utils.h"
[email protected]81374f22013-02-07 02:03:4536#include "content/public/test/test_utils.h"
[email protected]de7d61ff2013-08-20 11:30:4137#include "content/shell/browser/shell.h"
nasko402cc292016-03-11 09:16:1138#include "content/test/content_browser_test_utils_internal.h"
creis3710b2382015-08-18 00:12:1539#include "content/test/test_content_browser_client.h"
nick4c8dfd42014-11-14 04:11:4940#include "ipc/ipc_security_test_util.h"
41#include "net/dns/mock_host_resolver.h"
42#include "net/test/embedded_test_server/embedded_test_server.h"
gzobqq1af4fad2016-01-30 13:07:0643#include "net/test/url_request/url_request_slow_download_job.h"
nick4c8dfd42014-11-14 04:11:4944
45using IPC::IpcSecurityTestUtil;
[email protected]81374f22013-02-07 02:03:4546
47namespace content {
48
[email protected]04cbd3d2013-12-04 04:58:2049namespace {
50
gzobqq1af4fad2016-01-30 13:07:0651// This request id is used by tests that craft a
52// ResourceHostMsg_RequestResource. The id is sufficiently large that it doesn't
53// collide with ids used by previous navigation requests.
54const int kRequestIdNotPreviouslyUsed = 10000;
55
[email protected]04cbd3d2013-12-04 04:58:2056// This is a helper function for the tests which attempt to create a
57// duplicate RenderViewHost or RenderWidgetHost. It tries to create two objects
58// with the same process and routing ids, which causes a collision.
59// It creates a couple of windows in process 1, which causes a few routing ids
60// to be allocated. Then a cross-process navigation is initiated, which causes a
61// new process 2 to be created and have a pending RenderViewHost for it. The
62// routing id of the RenderViewHost which is target for a duplicate is set
63// into |target_routing_id| and the pending RenderViewHost which is used for
64// the attempt is the return value.
65RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
66 int* target_routing_id) {
nick4c8dfd42014-11-14 04:11:4967 GURL foo("http://foo.com/simple_page.html");
[email protected]04cbd3d2013-12-04 04:58:2068
69 // Start off with initial navigation, so we get the first process allocated.
70 NavigateToURL(shell, foo);
nick4c8dfd42014-11-14 04:11:4971 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell->web_contents()->GetTitle());
[email protected]04cbd3d2013-12-04 04:58:2072
73 // Open another window, so we generate some more routing ids.
74 ShellAddedObserver shell2_observer;
nickadef4a52016-06-09 18:45:5475 EXPECT_TRUE(ExecuteScript(shell, "window.open(document.URL + '#2');"));
[email protected]04cbd3d2013-12-04 04:58:2076 Shell* shell2 = shell2_observer.GetShell();
77
78 // The new window must be in the same process, but have a new routing id.
79 EXPECT_EQ(shell->web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
80 shell2->web_contents()->GetRenderViewHost()->GetProcess()->GetID());
81 *target_routing_id =
82 shell2->web_contents()->GetRenderViewHost()->GetRoutingID();
83 EXPECT_NE(*target_routing_id,
84 shell->web_contents()->GetRenderViewHost()->GetRoutingID());
85
86 // Now, simulate a link click coming from the renderer.
nick4c8dfd42014-11-14 04:11:4987 GURL extension_url("https://bar.com/simple_page.html");
[email protected]04cbd3d2013-12-04 04:58:2088 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents());
[email protected]65920f332014-03-04 21:14:1889 wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
lfg9ef7d2d2014-12-15 22:32:3090 wc->GetFrameTree()->root()->current_frame_host(), extension_url, nullptr,
nick94144d42015-04-27 19:21:4091 Referrer(), CURRENT_TAB, false, true);
[email protected]04cbd3d2013-12-04 04:58:2092
93 // Since the navigation above requires a cross-process swap, there will be a
carloskc49005eb2015-06-16 11:25:0794 // speculative/pending RenderFrameHost. Ensure it exists and is in a different
95 // process than the initial page.
96 RenderFrameHostImpl* next_rfh;
carloskd80262f52015-12-16 14:40:3597 if (IsBrowserSideNavigationEnabled())
98 next_rfh = wc->GetRenderManagerForTesting()->speculative_frame_host();
99 else
carloskc49005eb2015-06-16 11:25:07100 next_rfh = wc->GetRenderManagerForTesting()->pending_frame_host();
[email protected]04cbd3d2013-12-04 04:58:20101
carloskc49005eb2015-06-16 11:25:07102 EXPECT_TRUE(next_rfh);
103 EXPECT_NE(shell->web_contents()->GetRenderProcessHost()->GetID(),
104 next_rfh->GetProcess()->GetID());
105
106 return next_rfh->render_view_host();
[email protected]04cbd3d2013-12-04 04:58:20107}
108
yhirano20c94ea9b2016-05-18 05:20:45109ResourceRequest CreateXHRRequest(const char* url) {
110 ResourceRequest request;
creis3710b2382015-08-18 00:12:15111 request.method = "GET";
gzobqq1af4fad2016-01-30 13:07:06112 request.url = GURL(url);
creis3710b2382015-08-18 00:12:15113 request.referrer_policy = blink::WebReferrerPolicyDefault;
creis3710b2382015-08-18 00:12:15114 request.load_flags = 0;
115 request.origin_pid = 0;
116 request.resource_type = RESOURCE_TYPE_XHR;
117 request.request_context = 0;
118 request.appcache_host_id = kAppCacheNoHostId;
119 request.download_to_file = false;
120 request.should_reset_appcache = false;
121 request.is_main_frame = true;
122 request.parent_is_main_frame = false;
123 request.parent_render_frame_id = -1;
124 request.transition_type = ui::PAGE_TRANSITION_LINK;
125 request.allow_download = true;
126 return request;
127}
128
yhirano20c94ea9b2016-05-18 05:20:45129ResourceRequest CreateXHRRequestWithOrigin(const char* origin) {
130 ResourceRequest request = CreateXHRRequest("http://bar.com/simple_page.html");
gzobqq1af4fad2016-01-30 13:07:06131 request.first_party_for_cookies = GURL(origin);
132 request.headers = base::StringPrintf("Origin: %s\r\n", origin);
133 return request;
134}
135
136void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
137 NavigateToURL(shell, GURL("http://foo.com/simple_page.html"));
138 RenderFrameHost* rfh = shell->web_contents()->GetMainFrame();
139
140 if (block_loaders) {
141 // Test the case where loaders are placed into blocked_loaders_map_.
csharrisona2280cd2016-02-03 23:21:15142 ResourceDispatcherHost::BlockRequestsForFrameFromUI(rfh);
gzobqq1af4fad2016-01-30 13:07:06143 }
144
145 // URLRequestSlowDownloadJob waits for another request to kFinishDownloadUrl
146 // to finish all pending requests. It is never sent, so the following URL
147 // blocks indefinitely, which is good because the request stays alive and the
148 // test can try to reuse the request id without a race.
149 const char* blocking_url = net::URLRequestSlowDownloadJob::kUnknownSizeUrl;
yhirano20c94ea9b2016-05-18 05:20:45150 ResourceRequest request(CreateXHRRequest(blocking_url));
gzobqq1af4fad2016-01-30 13:07:06151
152 // Use the same request id twice.
153 RenderProcessHostWatcher process_killed(
154 rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
155 IPC::IpcSecurityTestUtil::PwnMessageReceived(
156 rfh->GetProcess()->GetChannel(),
157 ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
158 kRequestIdNotPreviouslyUsed, request));
159 IPC::IpcSecurityTestUtil::PwnMessageReceived(
160 rfh->GetProcess()->GetChannel(),
161 ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
162 kRequestIdNotPreviouslyUsed, request));
163 process_killed.Wait();
164}
165
[email protected]04cbd3d2013-12-04 04:58:20166} // namespace
167
168
[email protected]81374f22013-02-07 02:03:45169// The goal of these tests will be to "simulate" exploited renderer processes,
170// which can send arbitrary IPC messages and confuse browser process internal
171// state, leading to security bugs. We are trying to verify that the browser
172// doesn't perform any dangerous operations in such cases.
173class SecurityExploitBrowserTest : public ContentBrowserTest {
174 public:
175 SecurityExploitBrowserTest() {}
nick4c8dfd42014-11-14 04:11:49176
avi83883c82014-12-23 00:08:49177 void SetUpCommandLine(base::CommandLine* command_line) override {
svaldezc3a9a172015-11-03 22:01:33178 ASSERT_TRUE(embedded_test_server()->Start());
[email protected]81374f22013-02-07 02:03:45179
180 // Add a host resolver rule to map all outgoing requests to the test server.
181 // This allows us to use "real" hostnames in URLs, which we can use to
182 // create arbitrary SiteInstances.
183 command_line->AppendSwitchASCII(
184 switches::kHostResolverRules,
nick4c8dfd42014-11-14 04:11:49185 "MAP * " +
186 net::HostPortPair::FromURL(embedded_test_server()->base_url())
187 .ToString() +
[email protected]81374f22013-02-07 02:03:45188 ",EXCLUDE localhost");
189 }
wfh815c4872015-02-25 21:01:31190
gzobqq1af4fad2016-01-30 13:07:06191 void SetUpOnMainThread() override {
192 BrowserThread::PostTask(
193 BrowserThread::IO, FROM_HERE,
194 base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler));
195 }
196
wfh815c4872015-02-25 21:01:31197 protected:
198 // Tests that a given file path sent in a ViewHostMsg_RunFileChooser will
199 // cause renderer to be killed.
200 void TestFileChooserWithPath(const base::FilePath& path);
[email protected]81374f22013-02-07 02:03:45201};
202
wfh815c4872015-02-25 21:01:31203void SecurityExploitBrowserTest::TestFileChooserWithPath(
204 const base::FilePath& path) {
205 GURL foo("http://foo.com/simple_page.html");
206 NavigateToURL(shell(), foo);
207 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
208
creis3710b2382015-08-18 00:12:15209 RenderViewHost* compromised_renderer =
wfh815c4872015-02-25 21:01:31210 shell()->web_contents()->GetRenderViewHost();
creis3710b2382015-08-18 00:12:15211 RenderProcessHostWatcher terminated(
wfh815c4872015-02-25 21:01:31212 shell()->web_contents(),
creis3710b2382015-08-18 00:12:15213 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
wfh815c4872015-02-25 21:01:31214
215 FileChooserParams params;
216 params.default_file_name = path;
217
218 ViewHostMsg_RunFileChooser evil(compromised_renderer->GetRoutingID(), params);
219
220 IpcSecurityTestUtil::PwnMessageReceived(
221 compromised_renderer->GetProcess()->GetChannel(), evil);
222 terminated.Wait();
223}
224
[email protected]81374f22013-02-07 02:03:45225// Ensure that we kill the renderer process if we try to give it WebUI
226// properties and it doesn't have enabled WebUI bindings.
jaekyun37e572a32014-12-04 23:33:35227IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) {
nick4c8dfd42014-11-14 04:11:49228 GURL foo("http://foo.com/simple_page.html");
[email protected]81374f22013-02-07 02:03:45229
230 NavigateToURL(shell(), foo);
nick4c8dfd42014-11-14 04:11:49231 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
[email protected]81374f22013-02-07 02:03:45232 EXPECT_EQ(0,
233 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
234
creis3710b2382015-08-18 00:12:15235 RenderProcessHostWatcher terminated(
[email protected]8ffad4e2014-01-02 23:18:26236 shell()->web_contents(),
creis3710b2382015-08-18 00:12:15237 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
[email protected]81374f22013-02-07 02:03:45238 shell()->web_contents()->GetRenderViewHost()->SetWebUIProperty(
239 "toolkit", "views");
240 terminated.Wait();
241}
242
[email protected]04cbd3d2013-12-04 04:58:20243// This is a test for crbug.com/312016 attempting to create duplicate
244// RenderViewHosts. SetupForDuplicateHosts sets up this test case and leaves
245// it in a state with pending RenderViewHost. Before the commit of the new
246// pending RenderViewHost, this test case creates a new window through the new
247// process.
248IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
249 AttemptDuplicateRenderViewHost) {
dcheng3ce04b62015-10-26 23:30:55250 int32_t duplicate_routing_id = MSG_ROUTING_NONE;
[email protected]04cbd3d2013-12-04 04:58:20251 RenderViewHostImpl* pending_rvh =
252 PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
253 EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
254
255 // Since this test executes on the UI thread and hopping threads might cause
256 // different timing in the test, let's simulate a CreateNewWindow call coming
257 // from the IO thread.
258 ViewHostMsg_CreateWindow_Params params;
259 DOMStorageContextWrapper* dom_storage_context =
260 static_cast<DOMStorageContextWrapper*>(
261 BrowserContext::GetStoragePartition(
262 shell()->web_contents()->GetBrowserContext(),
263 pending_rvh->GetSiteInstance())->GetDOMStorageContext());
[email protected]4af624512013-12-13 14:58:43264 scoped_refptr<SessionStorageNamespaceImpl> session_storage(
265 new SessionStorageNamespaceImpl(dom_storage_context));
[email protected]04cbd3d2013-12-04 04:58:20266 // Cause a deliberate collision in routing ids.
dcheng3ce04b62015-10-26 23:30:55267 int32_t main_frame_routing_id = duplicate_routing_id + 1;
268 // TODO(avi): This should be made unique from the view routing ID once
269 // RenderViewHostImpl has-a RenderWidgetHostImpl. https://crbug.com/545684
270 int32_t main_frame_widget_routing_id = duplicate_routing_id;
271 pending_rvh->CreateNewWindow(duplicate_routing_id, main_frame_routing_id,
272 main_frame_widget_routing_id, params,
dcheng54c3719d2014-08-26 21:52:56273 session_storage.get());
[email protected]04cbd3d2013-12-04 04:58:20274
275 // If the above operation doesn't cause a crash, the test has succeeded!
[email protected]81374f22013-02-07 02:03:45276}
[email protected]04cbd3d2013-12-04 04:58:20277
[email protected]a8504022013-12-04 20:23:51278// This is a test for crbug.com/312016. It tries to create two RenderWidgetHosts
279// with the same process and routing ids, which causes a collision. It is almost
280// identical to the AttemptDuplicateRenderViewHost test case.
281IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
282 AttemptDuplicateRenderWidgetHost) {
283 int duplicate_routing_id = MSG_ROUTING_NONE;
284 RenderViewHostImpl* pending_rvh =
285 PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
286 EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
287
288 // Since this test executes on the UI thread and hopping threads might cause
289 // different timing in the test, let's simulate a CreateNewWidget call coming
290 // from the IO thread. Use the existing window routing id to cause a
291 // deliberate collision.
piman5d36dae2015-09-24 22:47:05292 pending_rvh->CreateNewWidget(duplicate_routing_id, blink::WebPopupTypePage);
[email protected]a8504022013-12-04 20:23:51293
294 // If the above operation doesn't crash, the test has succeeded!
295}
296
wfh815c4872015-02-25 21:01:31297// This is a test for crbug.com/444198. It tries to send a
298// ViewHostMsg_RunFileChooser containing an invalid path. The browser should
299// correctly terminate the renderer in these cases.
300IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, AttemptRunFileChoosers) {
301 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("../../*.txt")));
302 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("/etc/*.conf")));
303#if defined(OS_WIN)
304 TestFileChooserWithPath(
305 base::FilePath(FILE_PATH_LITERAL("\\\\evilserver\\evilshare\\*.txt")));
306 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("c:\\*.txt")));
307 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("..\\..\\*.txt")));
308#endif
309}
310
nick4c8dfd42014-11-14 04:11:49311class SecurityExploitTestInterstitialPage : public InterstitialPageDelegate {
312 public:
313 explicit SecurityExploitTestInterstitialPage(WebContents* contents) {
314 InterstitialPage* interstitial = InterstitialPage::Create(
315 contents, true, contents->GetLastCommittedURL(), this);
316 interstitial->Show();
317 }
318
319 // InterstitialPageDelegate implementation.
320 void CommandReceived(const std::string& command) override {
321 last_command_ = command;
322 }
323
324 std::string GetHTMLContents() override {
325 return "<html><head><script>"
326 "window.domAutomationController.setAutomationId(1);"
327 "window.domAutomationController.send(\"okay\");"
328 "</script></head>"
329 "<body>this page is an interstitial</body></html>";
330 }
331
332 std::string last_command() { return last_command_; }
333
334 private:
335 std::string last_command_;
336 DISALLOW_COPY_AND_ASSIGN(SecurityExploitTestInterstitialPage);
337};
338
339// Fails due to InterstitialPage's reliance on PostNonNestableTask
340// http://crbug.com/432737
341#if defined(OS_ANDROID)
342#define MAYBE_InterstitialCommandFromUnderlyingContent \
343 DISABLED_InterstitialCommandFromUnderlyingContent
344#else
345#define MAYBE_InterstitialCommandFromUnderlyingContent \
346 InterstitialCommandFromUnderlyingContent
347#endif
348
349// The interstitial should not be controllable by the underlying content.
350IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
351 MAYBE_InterstitialCommandFromUnderlyingContent) {
352 // Start off with initial navigation, to allocate the process.
353 GURL foo("http://foo.com/simple_page.html");
354 NavigateToURL(shell(), foo);
355 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
356
357 DOMMessageQueue message_queue;
358
359 // Install and show an interstitial page.
360 SecurityExploitTestInterstitialPage* interstitial =
361 new SecurityExploitTestInterstitialPage(shell()->web_contents());
362
363 ASSERT_EQ("", interstitial->last_command());
creis3710b2382015-08-18 00:12:15364 WaitForInterstitialAttach(shell()->web_contents());
nick4c8dfd42014-11-14 04:11:49365
366 InterstitialPage* interstitial_page =
367 shell()->web_contents()->GetInterstitialPage();
368 ASSERT_TRUE(interstitial_page != NULL);
369 ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage());
370 ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial);
371
372 // The interstitial page ought to be able to send a message.
373 std::string message;
374 ASSERT_TRUE(message_queue.WaitForMessage(&message));
375 ASSERT_EQ("\"okay\"", message);
376 ASSERT_EQ("\"okay\"", interstitial->last_command());
377
378 // Send an automation message from the underlying content and wait for it to
379 // be dispatched on this thread. This message should not be received by the
380 // interstitial.
creis3710b2382015-08-18 00:12:15381 RenderFrameHost* compromised_renderer =
nick4c8dfd42014-11-14 04:11:49382 shell()->web_contents()->GetMainFrame();
383 FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(),
avi60bd4902015-09-23 20:39:24384 "evil");
nick4c8dfd42014-11-14 04:11:49385 IpcSecurityTestUtil::PwnMessageReceived(
386 compromised_renderer->GetProcess()->GetChannel(), evil);
387
388 ASSERT_TRUE(message_queue.WaitForMessage(&message));
389 ASSERT_EQ("evil", message)
390 << "Automation message should be received by WebContents.";
391 ASSERT_EQ("\"okay\"", interstitial->last_command())
392 << "Interstitial should not be affected.";
393
394 // Send a second message from the interstitial page, and make sure that the
395 // "evil" message doesn't arrive in the intervening period.
creis3710b2382015-08-18 00:12:15396 ASSERT_TRUE(ExecuteScript(interstitial_page->GetMainFrame(),
397 "window.domAutomationController.send(\"okay2\");"));
nick4c8dfd42014-11-14 04:11:49398 ASSERT_TRUE(message_queue.WaitForMessage(&message));
399 ASSERT_EQ("\"okay2\"", message);
400 ASSERT_EQ("\"okay2\"", interstitial->last_command());
401}
402
creis3710b2382015-08-18 00:12:15403class IsolatedAppContentBrowserClient : public TestContentBrowserClient {
404 public:
405 bool IsIllegalOrigin(content::ResourceContext* resource_context,
406 int child_process_id,
407 const GURL& origin) override {
408 // Simulate a case where an app origin is not in an app process.
409 return true;
410 }
411};
412
413// Renderer processes should not be able to spoof Origin HTTP headers.
414IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
415 // Create a set of IPC messages with various Origin headers.
yhirano20c94ea9b2016-05-18 05:20:45416 ResourceRequest chrome_origin_msg(
creis3710b2382015-08-18 00:12:15417 CreateXHRRequestWithOrigin("chrome://settings"));
yhirano20c94ea9b2016-05-18 05:20:45418 ResourceRequest embedder_isolated_origin_msg(
creis3710b2382015-08-18 00:12:15419 CreateXHRRequestWithOrigin("https://isolated.bar.com"));
yhirano20c94ea9b2016-05-18 05:20:45420 ResourceRequest invalid_origin_msg(CreateXHRRequestWithOrigin("invalidurl"));
421 ResourceRequest invalid_scheme_origin_msg(
creis3710b2382015-08-18 00:12:15422 CreateXHRRequestWithOrigin("fake-scheme://foo"));
423
424 GURL web_url("http://foo.com/simple_page.html");
425 NavigateToURL(shell(), web_url);
426 RenderFrameHost* web_rfh = shell()->web_contents()->GetMainFrame();
427
428 // Web processes cannot make XHRs with chrome:// Origin headers.
429 {
430 RenderProcessHostWatcher web_process_killed(
431 web_rfh->GetProcess(),
432 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
433 IPC::IpcSecurityTestUtil::PwnMessageReceived(
434 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06435 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
436 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15437 chrome_origin_msg));
438 web_process_killed.Wait();
439 }
440
441 // Web processes cannot make XHRs with URLs that the content embedder expects
442 // to have process isolation. Ideally this would test chrome-extension://
443 // URLs for Chrome Apps, but those can't be tested inside content/ and the
yhirano20c94ea9b2016-05-18 05:20:45444 // ResourceRequest IPC can't be created in a test outside content/.
creis3710b2382015-08-18 00:12:15445 NavigateToURL(shell(), web_url);
446 {
447 // Set up a ContentBrowserClient that simulates an app URL in a non-app
448 // process.
449 IsolatedAppContentBrowserClient app_client;
450 ContentBrowserClient* old_client = SetBrowserClientForTesting(&app_client);
451 RenderProcessHostWatcher web_process_killed(
452 web_rfh->GetProcess(),
453 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
454 IPC::IpcSecurityTestUtil::PwnMessageReceived(
455 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06456 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
457 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15458 embedder_isolated_origin_msg));
459 web_process_killed.Wait();
460 SetBrowserClientForTesting(old_client);
461 }
462
463 // Web processes cannot make XHRs with invalid Origin headers.
464 NavigateToURL(shell(), web_url);
465 {
466 RenderProcessHostWatcher web_process_killed(
467 web_rfh->GetProcess(),
468 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
469 IPC::IpcSecurityTestUtil::PwnMessageReceived(
470 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06471 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
472 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15473 invalid_origin_msg));
474 web_process_killed.Wait();
475 }
476
477 // Web processes cannot make XHRs with invalid scheme Origin headers.
478 NavigateToURL(shell(), web_url);
479 {
480 RenderProcessHostWatcher web_process_killed(
481 web_rfh->GetProcess(),
482 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
483 IPC::IpcSecurityTestUtil::PwnMessageReceived(
484 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06485 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
486 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15487 invalid_scheme_origin_msg));
488 web_process_killed.Wait();
489 }
490}
491
gzobqq1af4fad2016-01-30 13:07:06492// Renderer process should not be able to create multiple requests with the same
493// id.
494IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidRequestId) {
495 // Existing loader in pending_loaders_.
496 TryCreateDuplicateRequestIds(shell(), false);
497 // Existing loader in blocked_loaders_map_.
498 TryCreateDuplicateRequestIds(shell(), true);
499}
500
nasko402cc292016-03-11 09:16:11501// Test that receiving a commit with incorrect origin properly terminates the
502// renderer process.
503IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, MismatchedOriginOnCommit) {
504 GURL start_url(embedded_test_server()->GetURL("/title1.html"));
505 EXPECT_TRUE(NavigateToURL(shell(), start_url));
506
507 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
508 ->GetFrameTree()
509 ->root();
510
511 // Setup an URL which will never commit, allowing this test to send its own,
512 // malformed, commit message.
513 GURL url(embedded_test_server()->GetURL("/title2.html"));
514 NavigationStallDelegate stall_delegate(url);
515 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
516
517 // Use LoadURL, as the test shouldn't wait for navigation commit.
518 NavigationController& controller = shell()->web_contents()->GetController();
519 controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
520 EXPECT_NE(nullptr, controller.GetPendingEntry());
521 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
522
523 RenderProcessHostWatcher exit_observer(
524 root->current_frame_host()->GetProcess(),
525 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
526
527 // Create commit params with different origins in params.url and
528 // params.origin.
529 FrameHostMsg_DidCommitProvisionalLoad_Params params;
530 params.page_id = 0;
531 params.nav_entry_id = 0;
532 params.did_create_new_entry = false;
533 params.url = url;
534 params.transition = ui::PAGE_TRANSITION_LINK;
535 params.should_update_history = false;
536 params.gesture = NavigationGestureAuto;
537 params.was_within_same_page = false;
clamy432acb22016-04-15 19:41:43538 params.method = "GET";
nasko402cc292016-03-11 09:16:11539 params.page_state = PageState::CreateFromURL(url);
540 params.origin = url::Origin(GURL("http://bar.com/"));
541
542 FrameHostMsg_DidCommitProvisionalLoad msg(
543 root->current_frame_host()->routing_id(), params);
544 IPC::IpcSecurityTestUtil::PwnMessageReceived(
545 root->current_frame_host()->GetProcess()->GetChannel(), msg);
546
547 // When the IPC message is received and validation fails, the process is
548 // terminated. However, the notification for that should be processed in a
549 // separate task of the message loop, so ensure that the process is still
550 // considered alive.
551 EXPECT_TRUE(root->current_frame_host()->GetProcess()->HasConnection());
552
553 exit_observer.Wait();
554 EXPECT_FALSE(exit_observer.did_exit_normally());
clamyeeb96fd2016-03-23 12:31:47555 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
nasko402cc292016-03-11 09:16:11556}
557
[email protected]04cbd3d2013-12-04 04:58:20558} // namespace content