Commit 0f6edddc authored by creis's avatar creis Committed by Commit bot

OOPIF: Remove the FrameTreeNode when a RemoteFrame is detached.

This ensures that subframe processes aren't left around if a parent page
removes an out-of-process iframes.

TBR=jam@chromium.org
BUG=471346, 474772
TEST=See bug for repro steps.
Credit to nick@ for TaskManagerOOPIFBrowserTest.LeavePageWithCrossSiteIframes

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

Cr-Commit-Position: refs/heads/master@{#324160}
parent d102cfd5
......@@ -1094,3 +1094,53 @@ IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest,
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab()));
}
// Tests what happens when a tab does a same-site navigation away from a page
// with cross-site iframes.
IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest,
LeavePageWithCrossSiteIframes) {
ShowTaskManager();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
content::SetupCrossSiteRedirector(embedded_test_server());
// Navigate the tab to a page on a.com with cross-process subframes.
GURL a_dotcom_with_iframes(embedded_test_server()->GetURL(
"/cross-site/a.com/iframe_cross_site.html"));
browser()->OpenURL(content::OpenURLParams(a_dotcom_with_iframes,
content::Referrer(), CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchTab("cross-site iframe test")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab()));
if (!ShouldExpectSubframes()) {
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe()));
} else {
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://b.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://c.com/")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe()));
}
// Navigate the tab to a page on a.com without cross-process subframes, and
// the subframe processes should disappear.
GURL a_dotcom_simple(
embedded_test_server()->GetURL("/cross-site/a.com/title2.html"));
browser()->OpenURL(content::OpenURLParams(a_dotcom_simple,
content::Referrer(), CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe()));
HideTaskManager();
ShowTaskManager();
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe()));
}
......@@ -37,6 +37,7 @@ enum BadMessageReason {
SERVICE_WORKER_BAD_URL,
WC_INVALID_FRAME_SOURCE,
RWHVM_UNEXPECTED_FRAME_TYPE,
RFPH_DETACH,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
// reason.
......
......@@ -5,6 +5,7 @@
#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "base/lazy_instance.h"
#include "content/browser/bad_message.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
......@@ -116,6 +117,7 @@ bool RenderFrameProxyHost::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderFrameProxyHost, msg)
IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
......@@ -157,8 +159,22 @@ void RenderFrameProxyHost::DisownOpener() {
Send(new FrameMsg_DisownOpener(GetRoutingID()));
}
void RenderFrameProxyHost::OnDetach() {
// This message should only be received for subframes. Note that we can't
// restrict it to just the current SiteInstances of the ancestors of this
// frame, because another frame in the tree may be able to detach this frame
// by navigating its parent.
if (frame_tree_node_->IsMainFrame()) {
bad_message::ReceivedBadMessage(GetProcess(), bad_message::RFPH_DETACH);
return;
}
frame_tree_node_->frame_tree()->RemoveFrame(frame_tree_node_);
}
void RenderFrameProxyHost::OnOpenURL(
const FrameHostMsg_OpenURL_Params& params) {
// TODO(creis): Verify that we are in the same BrowsingInstance as the current
// RenderFrameHost. See NavigatorImpl::RequestOpenURL.
frame_tree_node_->current_frame_host()->OpenURL(params, site_instance_.get());
}
......
......@@ -115,6 +115,7 @@ class RenderFrameProxyHost
private:
// IPC Message handlers.
void OnDetach();
void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
// This RenderFrameProxyHost's routing id.
......
......@@ -14,6 +14,7 @@
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
......@@ -25,6 +26,7 @@
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/test_frame_navigation_observer.h"
#include "ipc/ipc_security_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
......@@ -321,6 +323,94 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
}
}
// Ensure that OOPIFs are deleted after navigating to a new main frame.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
// It is safe to obtain the root frame tree node here, as it doesn't change.
FrameTreeNode* root =
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
TestNavigationObserver observer(shell()->web_contents());
// Load a cross-site page into both iframes.
GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
NavigateFrameToURL(root->child_at(0), foo_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
NavigateFrameToURL(root->child_at(1), foo_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
// Ensure that we have created a new process for the subframes.
ASSERT_EQ(2U, root->child_count());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
EXPECT_EQ(root->child_at(0)->current_frame_host()->GetSiteInstance(),
root->child_at(1)->current_frame_host()->GetSiteInstance());
// Use Javascript in the parent to remove one of the frames and ensure that
// the subframe goes away.
EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
"document.body.removeChild("
"document.querySelectorAll('iframe')[0])"));
ASSERT_EQ(1U, root->child_count());
// Load a new same-site page in the top-level frame and ensure the other
// subframe goes away.
GURL new_url(embedded_test_server()->GetURL("/title1.html"));
NavigateToURL(shell(), new_url);
ASSERT_EQ(0U, root->child_count());
}
// Ensure that root frames cannot be detached.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
// It is safe to obtain the root frame tree node here, as it doesn't change.
FrameTreeNode* root =
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
TestNavigationObserver observer(shell()->web_contents());
// Load cross-site pages into both iframes.
GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
NavigateFrameToURL(root->child_at(0), foo_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
NavigateFrameToURL(root->child_at(1), bar_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(bar_url, observer.last_navigation_url());
// Ensure that we have created new processes for the subframes.
ASSERT_EQ(2U, root->child_count());
FrameTreeNode* foo_child = root->child_at(0);
SiteInstance* foo_site_instance =
foo_child->current_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
FrameTreeNode* bar_child = root->child_at(1);
SiteInstance* bar_site_instance =
bar_child->current_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
// Simulate an attempt to detach the root frame from foo_site_instance. This
// should kill foo_site_instance's process.
RenderFrameProxyHost* foo_mainframe_rfph =
root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
content::RenderProcessHostWatcher foo_terminated(
foo_mainframe_rfph->GetProcess(),
content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
IPC::IpcSecurityTestUtil::PwnMessageReceived(
foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
foo_terminated.Wait();
}
// Disabled for flaky crashing: crbug.com/446575
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
NavigateRemoteFrame) {
......
......@@ -304,9 +304,14 @@ void RenderFrameProxy::OnDidUpdateName(const std::string& name) {
}
void RenderFrameProxy::frameDetached() {
if (web_frame_->parent())
if (web_frame_->parent()) {
web_frame_->parent()->removeChild(web_frame_);
// Let the browser process know this subframe is removed, so that it is
// destroyed in its current process.
Send(new FrameHostMsg_Detach(routing_id_));
}
web_frame_->close();
delete this;
}
......
......@@ -2279,7 +2279,7 @@
{
"args": [
"--site-per-process",
"--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:ExternallyConnectableMessagingTest.*:HistoryBrowserTest.*:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
"--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:ExternallyConnectableMessagingTest.*:HistoryBrowserTest.*:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
],
"test": "browser_tests"
},
......@@ -2309,7 +2309,7 @@
{
"args": [
"--site-per-process",
"--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:ExternallyConnectableMessagingTest.*:HistoryBrowserTest.*:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
"--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:ExternallyConnectableMessagingTest.*:HistoryBrowserTest.*:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
],
"test": "browser_tests"
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment