blob: f9d6d7f935e50d0255017c7e2c568db8317eb30a [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(
lukaszabb2101b82016-06-17 16:52:2590 wc->GetFrameTree()->root()->current_frame_host(), extension_url, false,
91 nullptr, nullptr, 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:
naskoada75b22016-06-11 16:09:46198 // Tests that a given file path sent in a FrameHostMsg_RunFileChooser will
wfh815c4872015-02-25 21:01:31199 // 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
naskoada75b22016-06-11 16:09:46209 RenderFrameHost* compromised_renderer =
210 shell()->web_contents()->GetMainFrame();
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
naskoada75b22016-06-11 16:09:46218 FrameHostMsg_RunFileChooser evil(compromised_renderer->GetRoutingID(),
219 params);
wfh815c4872015-02-25 21:01:31220
221 IpcSecurityTestUtil::PwnMessageReceived(
222 compromised_renderer->GetProcess()->GetChannel(), evil);
223 terminated.Wait();
224}
225
[email protected]81374f22013-02-07 02:03:45226// Ensure that we kill the renderer process if we try to give it WebUI
227// properties and it doesn't have enabled WebUI bindings.
jaekyun37e572a32014-12-04 23:33:35228IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) {
nick4c8dfd42014-11-14 04:11:49229 GURL foo("http://foo.com/simple_page.html");
[email protected]81374f22013-02-07 02:03:45230
231 NavigateToURL(shell(), foo);
nick4c8dfd42014-11-14 04:11:49232 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
[email protected]81374f22013-02-07 02:03:45233 EXPECT_EQ(0,
234 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
235
creis3710b2382015-08-18 00:12:15236 RenderProcessHostWatcher terminated(
[email protected]8ffad4e2014-01-02 23:18:26237 shell()->web_contents(),
creis3710b2382015-08-18 00:12:15238 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
[email protected]81374f22013-02-07 02:03:45239 shell()->web_contents()->GetRenderViewHost()->SetWebUIProperty(
240 "toolkit", "views");
241 terminated.Wait();
242}
243
[email protected]04cbd3d2013-12-04 04:58:20244// This is a test for crbug.com/312016 attempting to create duplicate
245// RenderViewHosts. SetupForDuplicateHosts sets up this test case and leaves
246// it in a state with pending RenderViewHost. Before the commit of the new
247// pending RenderViewHost, this test case creates a new window through the new
248// process.
249IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
250 AttemptDuplicateRenderViewHost) {
dcheng3ce04b62015-10-26 23:30:55251 int32_t duplicate_routing_id = MSG_ROUTING_NONE;
[email protected]04cbd3d2013-12-04 04:58:20252 RenderViewHostImpl* pending_rvh =
253 PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
254 EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
255
256 // Since this test executes on the UI thread and hopping threads might cause
257 // different timing in the test, let's simulate a CreateNewWindow call coming
258 // from the IO thread.
259 ViewHostMsg_CreateWindow_Params params;
260 DOMStorageContextWrapper* dom_storage_context =
261 static_cast<DOMStorageContextWrapper*>(
262 BrowserContext::GetStoragePartition(
263 shell()->web_contents()->GetBrowserContext(),
264 pending_rvh->GetSiteInstance())->GetDOMStorageContext());
[email protected]4af624512013-12-13 14:58:43265 scoped_refptr<SessionStorageNamespaceImpl> session_storage(
266 new SessionStorageNamespaceImpl(dom_storage_context));
[email protected]04cbd3d2013-12-04 04:58:20267 // Cause a deliberate collision in routing ids.
dcheng3ce04b62015-10-26 23:30:55268 int32_t main_frame_routing_id = duplicate_routing_id + 1;
269 // TODO(avi): This should be made unique from the view routing ID once
270 // RenderViewHostImpl has-a RenderWidgetHostImpl. https://crbug.com/545684
271 int32_t main_frame_widget_routing_id = duplicate_routing_id;
272 pending_rvh->CreateNewWindow(duplicate_routing_id, main_frame_routing_id,
273 main_frame_widget_routing_id, params,
dcheng54c3719d2014-08-26 21:52:56274 session_storage.get());
[email protected]04cbd3d2013-12-04 04:58:20275
276 // If the above operation doesn't cause a crash, the test has succeeded!
[email protected]81374f22013-02-07 02:03:45277}
[email protected]04cbd3d2013-12-04 04:58:20278
[email protected]a8504022013-12-04 20:23:51279// This is a test for crbug.com/312016. It tries to create two RenderWidgetHosts
280// with the same process and routing ids, which causes a collision. It is almost
281// identical to the AttemptDuplicateRenderViewHost test case.
282IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
283 AttemptDuplicateRenderWidgetHost) {
284 int duplicate_routing_id = MSG_ROUTING_NONE;
285 RenderViewHostImpl* pending_rvh =
286 PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
287 EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
288
289 // Since this test executes on the UI thread and hopping threads might cause
290 // different timing in the test, let's simulate a CreateNewWidget call coming
291 // from the IO thread. Use the existing window routing id to cause a
292 // deliberate collision.
piman5d36dae2015-09-24 22:47:05293 pending_rvh->CreateNewWidget(duplicate_routing_id, blink::WebPopupTypePage);
[email protected]a8504022013-12-04 20:23:51294
295 // If the above operation doesn't crash, the test has succeeded!
296}
297
wfh815c4872015-02-25 21:01:31298// This is a test for crbug.com/444198. It tries to send a
naskoada75b22016-06-11 16:09:46299// FrameHostMsg_RunFileChooser containing an invalid path. The browser should
wfh815c4872015-02-25 21:01:31300// correctly terminate the renderer in these cases.
301IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, AttemptRunFileChoosers) {
302 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("../../*.txt")));
303 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("/etc/*.conf")));
304#if defined(OS_WIN)
305 TestFileChooserWithPath(
306 base::FilePath(FILE_PATH_LITERAL("\\\\evilserver\\evilshare\\*.txt")));
307 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("c:\\*.txt")));
308 TestFileChooserWithPath(base::FilePath(FILE_PATH_LITERAL("..\\..\\*.txt")));
309#endif
310}
311
nick4c8dfd42014-11-14 04:11:49312class SecurityExploitTestInterstitialPage : public InterstitialPageDelegate {
313 public:
314 explicit SecurityExploitTestInterstitialPage(WebContents* contents) {
315 InterstitialPage* interstitial = InterstitialPage::Create(
316 contents, true, contents->GetLastCommittedURL(), this);
317 interstitial->Show();
318 }
319
320 // InterstitialPageDelegate implementation.
321 void CommandReceived(const std::string& command) override {
322 last_command_ = command;
323 }
324
325 std::string GetHTMLContents() override {
326 return "<html><head><script>"
327 "window.domAutomationController.setAutomationId(1);"
328 "window.domAutomationController.send(\"okay\");"
329 "</script></head>"
330 "<body>this page is an interstitial</body></html>";
331 }
332
333 std::string last_command() { return last_command_; }
334
335 private:
336 std::string last_command_;
337 DISALLOW_COPY_AND_ASSIGN(SecurityExploitTestInterstitialPage);
338};
339
340// Fails due to InterstitialPage's reliance on PostNonNestableTask
341// http://crbug.com/432737
342#if defined(OS_ANDROID)
343#define MAYBE_InterstitialCommandFromUnderlyingContent \
344 DISABLED_InterstitialCommandFromUnderlyingContent
345#else
346#define MAYBE_InterstitialCommandFromUnderlyingContent \
347 InterstitialCommandFromUnderlyingContent
348#endif
349
350// The interstitial should not be controllable by the underlying content.
351IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
352 MAYBE_InterstitialCommandFromUnderlyingContent) {
353 // Start off with initial navigation, to allocate the process.
354 GURL foo("http://foo.com/simple_page.html");
355 NavigateToURL(shell(), foo);
356 EXPECT_EQ(base::ASCIIToUTF16("OK"), shell()->web_contents()->GetTitle());
357
358 DOMMessageQueue message_queue;
359
360 // Install and show an interstitial page.
361 SecurityExploitTestInterstitialPage* interstitial =
362 new SecurityExploitTestInterstitialPage(shell()->web_contents());
363
364 ASSERT_EQ("", interstitial->last_command());
creis3710b2382015-08-18 00:12:15365 WaitForInterstitialAttach(shell()->web_contents());
nick4c8dfd42014-11-14 04:11:49366
367 InterstitialPage* interstitial_page =
368 shell()->web_contents()->GetInterstitialPage();
369 ASSERT_TRUE(interstitial_page != NULL);
370 ASSERT_TRUE(shell()->web_contents()->ShowingInterstitialPage());
371 ASSERT_TRUE(interstitial_page->GetDelegateForTesting() == interstitial);
372
373 // The interstitial page ought to be able to send a message.
374 std::string message;
375 ASSERT_TRUE(message_queue.WaitForMessage(&message));
376 ASSERT_EQ("\"okay\"", message);
377 ASSERT_EQ("\"okay\"", interstitial->last_command());
378
379 // Send an automation message from the underlying content and wait for it to
380 // be dispatched on this thread. This message should not be received by the
381 // interstitial.
creis3710b2382015-08-18 00:12:15382 RenderFrameHost* compromised_renderer =
nick4c8dfd42014-11-14 04:11:49383 shell()->web_contents()->GetMainFrame();
384 FrameHostMsg_DomOperationResponse evil(compromised_renderer->GetRoutingID(),
avi60bd4902015-09-23 20:39:24385 "evil");
nick4c8dfd42014-11-14 04:11:49386 IpcSecurityTestUtil::PwnMessageReceived(
387 compromised_renderer->GetProcess()->GetChannel(), evil);
388
389 ASSERT_TRUE(message_queue.WaitForMessage(&message));
390 ASSERT_EQ("evil", message)
391 << "Automation message should be received by WebContents.";
392 ASSERT_EQ("\"okay\"", interstitial->last_command())
393 << "Interstitial should not be affected.";
394
395 // Send a second message from the interstitial page, and make sure that the
396 // "evil" message doesn't arrive in the intervening period.
creis3710b2382015-08-18 00:12:15397 ASSERT_TRUE(ExecuteScript(interstitial_page->GetMainFrame(),
398 "window.domAutomationController.send(\"okay2\");"));
nick4c8dfd42014-11-14 04:11:49399 ASSERT_TRUE(message_queue.WaitForMessage(&message));
400 ASSERT_EQ("\"okay2\"", message);
401 ASSERT_EQ("\"okay2\"", interstitial->last_command());
402}
403
creis3710b2382015-08-18 00:12:15404class IsolatedAppContentBrowserClient : public TestContentBrowserClient {
405 public:
406 bool IsIllegalOrigin(content::ResourceContext* resource_context,
407 int child_process_id,
408 const GURL& origin) override {
409 // Simulate a case where an app origin is not in an app process.
410 return true;
411 }
412};
413
414// Renderer processes should not be able to spoof Origin HTTP headers.
415IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
416 // Create a set of IPC messages with various Origin headers.
yhirano20c94ea9b2016-05-18 05:20:45417 ResourceRequest chrome_origin_msg(
creis3710b2382015-08-18 00:12:15418 CreateXHRRequestWithOrigin("chrome://settings"));
yhirano20c94ea9b2016-05-18 05:20:45419 ResourceRequest embedder_isolated_origin_msg(
creis3710b2382015-08-18 00:12:15420 CreateXHRRequestWithOrigin("https://isolated.bar.com"));
yhirano20c94ea9b2016-05-18 05:20:45421 ResourceRequest invalid_origin_msg(CreateXHRRequestWithOrigin("invalidurl"));
422 ResourceRequest invalid_scheme_origin_msg(
creis3710b2382015-08-18 00:12:15423 CreateXHRRequestWithOrigin("fake-scheme://foo"));
424
425 GURL web_url("http://foo.com/simple_page.html");
426 NavigateToURL(shell(), web_url);
427 RenderFrameHost* web_rfh = shell()->web_contents()->GetMainFrame();
428
429 // Web processes cannot make XHRs with chrome:// Origin headers.
430 {
431 RenderProcessHostWatcher web_process_killed(
432 web_rfh->GetProcess(),
433 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
434 IPC::IpcSecurityTestUtil::PwnMessageReceived(
435 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06436 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
437 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15438 chrome_origin_msg));
439 web_process_killed.Wait();
440 }
441
442 // Web processes cannot make XHRs with URLs that the content embedder expects
443 // to have process isolation. Ideally this would test chrome-extension://
444 // URLs for Chrome Apps, but those can't be tested inside content/ and the
yhirano20c94ea9b2016-05-18 05:20:45445 // ResourceRequest IPC can't be created in a test outside content/.
creis3710b2382015-08-18 00:12:15446 NavigateToURL(shell(), web_url);
447 {
448 // Set up a ContentBrowserClient that simulates an app URL in a non-app
449 // process.
450 IsolatedAppContentBrowserClient app_client;
451 ContentBrowserClient* old_client = SetBrowserClientForTesting(&app_client);
452 RenderProcessHostWatcher web_process_killed(
453 web_rfh->GetProcess(),
454 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
455 IPC::IpcSecurityTestUtil::PwnMessageReceived(
456 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06457 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
458 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15459 embedder_isolated_origin_msg));
460 web_process_killed.Wait();
461 SetBrowserClientForTesting(old_client);
462 }
463
464 // Web processes cannot make XHRs with invalid Origin headers.
465 NavigateToURL(shell(), web_url);
466 {
467 RenderProcessHostWatcher web_process_killed(
468 web_rfh->GetProcess(),
469 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
470 IPC::IpcSecurityTestUtil::PwnMessageReceived(
471 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06472 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
473 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15474 invalid_origin_msg));
475 web_process_killed.Wait();
476 }
477
478 // Web processes cannot make XHRs with invalid scheme Origin headers.
479 NavigateToURL(shell(), web_url);
480 {
481 RenderProcessHostWatcher web_process_killed(
482 web_rfh->GetProcess(),
483 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
484 IPC::IpcSecurityTestUtil::PwnMessageReceived(
485 web_rfh->GetProcess()->GetChannel(),
gzobqq1af4fad2016-01-30 13:07:06486 ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
487 kRequestIdNotPreviouslyUsed,
creis3710b2382015-08-18 00:12:15488 invalid_scheme_origin_msg));
489 web_process_killed.Wait();
490 }
491}
492
gzobqq1af4fad2016-01-30 13:07:06493// Renderer process should not be able to create multiple requests with the same
494// id.
495IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidRequestId) {
496 // Existing loader in pending_loaders_.
497 TryCreateDuplicateRequestIds(shell(), false);
498 // Existing loader in blocked_loaders_map_.
499 TryCreateDuplicateRequestIds(shell(), true);
500}
501
nasko402cc292016-03-11 09:16:11502// Test that receiving a commit with incorrect origin properly terminates the
503// renderer process.
504IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, MismatchedOriginOnCommit) {
505 GURL start_url(embedded_test_server()->GetURL("/title1.html"));
506 EXPECT_TRUE(NavigateToURL(shell(), start_url));
507
508 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
509 ->GetFrameTree()
510 ->root();
511
512 // Setup an URL which will never commit, allowing this test to send its own,
513 // malformed, commit message.
514 GURL url(embedded_test_server()->GetURL("/title2.html"));
515 NavigationStallDelegate stall_delegate(url);
516 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
517
518 // Use LoadURL, as the test shouldn't wait for navigation commit.
519 NavigationController& controller = shell()->web_contents()->GetController();
520 controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
521 EXPECT_NE(nullptr, controller.GetPendingEntry());
522 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
523
524 RenderProcessHostWatcher exit_observer(
525 root->current_frame_host()->GetProcess(),
526 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
527
528 // Create commit params with different origins in params.url and
529 // params.origin.
530 FrameHostMsg_DidCommitProvisionalLoad_Params params;
531 params.page_id = 0;
532 params.nav_entry_id = 0;
533 params.did_create_new_entry = false;
534 params.url = url;
535 params.transition = ui::PAGE_TRANSITION_LINK;
536 params.should_update_history = false;
537 params.gesture = NavigationGestureAuto;
538 params.was_within_same_page = false;
clamy432acb22016-04-15 19:41:43539 params.method = "GET";
nasko402cc292016-03-11 09:16:11540 params.page_state = PageState::CreateFromURL(url);
541 params.origin = url::Origin(GURL("http://bar.com/"));
542
543 FrameHostMsg_DidCommitProvisionalLoad msg(
544 root->current_frame_host()->routing_id(), params);
545 IPC::IpcSecurityTestUtil::PwnMessageReceived(
546 root->current_frame_host()->GetProcess()->GetChannel(), msg);
547
548 // When the IPC message is received and validation fails, the process is
549 // terminated. However, the notification for that should be processed in a
550 // separate task of the message loop, so ensure that the process is still
551 // considered alive.
552 EXPECT_TRUE(root->current_frame_host()->GetProcess()->HasConnection());
553
554 exit_observer.Wait();
555 EXPECT_FALSE(exit_observer.did_exit_normally());
clamyeeb96fd2016-03-23 12:31:47556 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
nasko402cc292016-03-11 09:16:11557}
558
[email protected]04cbd3d2013-12-04 04:58:20559} // namespace content