Disallow was_within_same_page = true for a cross-process navigation.

BUG=590284
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation

Review URL: https://codereview.chromium.org/1738233002

Cr-Commit-Position: refs/heads/master@{#378461}
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 5dad578..a176ebc 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -457,6 +457,19 @@
 
   bool is_navigation_within_page = controller_->IsURLInPageNavigation(
       params.url, params.was_within_same_page, render_frame_host);
+
+  // If a frame claims it navigated within page, it must be the current frame,
+  // not a pending one.
+  if (is_navigation_within_page &&
+      render_frame_host !=
+          render_frame_host->frame_tree_node()
+              ->render_manager()
+              ->current_frame_host()) {
+    bad_message::ReceivedBadMessage(render_frame_host->GetProcess(),
+                                    bad_message::NC_IN_PAGE_NAVIGATION);
+    is_navigation_within_page = false;
+  }
+
   if (ui::PageTransitionIsMainFrame(params.transition)) {
     if (delegate_) {
       // When overscroll navigation gesture is enabled, a screenshot of the page
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index 880e971..698ccde0 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -1191,4 +1191,34 @@
   }
 }
 
+namespace {
+void SetWithinPage(const GURL& url,
+                   FrameHostMsg_DidCommitProvisionalLoad_Params* params) {
+  params->was_within_same_page = true;
+  params->url = url;
+}
+}
+
+// A renderer process might try and claim that a cross site navigation was
+// within the same page by setting was_within_same_page = true for
+// FrameHostMsg_DidCommitProvisionalLoad. Such case should be detected on the
+// browser side and the renderer process should be killed.
+TEST_F(NavigatorTestWithBrowserSideNavigation, CrossSiteClaimWithinPage) {
+  const GURL kUrl1("http://www.chromium.org/");
+  const GURL kUrl2("http://www.google.com/");
+
+  contents()->NavigateAndCommit(kUrl1);
+  FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+  // Navigate to a different site.
+  int entry_id = RequestNavigation(node, kUrl2);
+  main_test_rfh()->PrepareForCommit();
+
+  // Claim that the navigation was within same page.
+  int bad_msg_count = process()->bad_msg_count();
+  GetSpeculativeRenderFrameHost(node)->SendNavigateWithModificationCallback(
+      0, entry_id, true, kUrl2, base::Bind(SetWithinPage, kUrl1));
+  EXPECT_EQ(process()->bad_msg_count(), bad_msg_count + 1);
+}
+
 }  // namespace content
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index f158dbc..d805f38 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -271,10 +271,12 @@
     ui::PageTransition transition,
     int response_code,
     const ModificationCallback& callback) {
+  if (!IsBrowserSideNavigationEnabled())
+    OnDidStartLoading(true);
+
   // DidStartProvisionalLoad may delete the pending entry that holds |url|,
   // so we keep a copy of it to use below.
   GURL url_copy(url);
-  OnDidStartLoading(true);
   OnDidStartProvisionalLoad(url_copy, base::TimeTicks::Now());
 
   FrameHostMsg_DidCommitProvisionalLoad_Params params;