diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-10-24 15:49:33 +0200 |
---|---|---|
committer | Michael Brüning <michael.bruning@qt.io> | 2018-11-01 15:30:01 +0000 |
commit | e467d563636dc3ee01f2485bab871fb7405b7bab (patch) | |
tree | afc53c7a5a0cbc65f9a1c69abeb8ef470907c414 | |
parent | 37b5fe3597c6f0912e7fd6b2d6ab17a0ab2cbc30 (diff) |
[Backport] Fix for CVE-2018-17471
Security drop fullscreen for any nested WebContents level.
This relands 3dcaec6e30feebefc11e with a fix to the test.
BUG=873080
TEST=as in bug
Change-Id: Ifb23677fc981e8c821c0e985b99c856a22a19f2c
Reviewed-on: https://chromium-review.googlesource.com/1175925
Reviewed-by: Sidney San Martín <sdy@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583335}
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
3 files changed, 84 insertions, 15 deletions
diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc index 8b7b8c79634..05a6efa2535 100644 --- a/chromium/content/browser/web_contents/web_contents_impl.cc +++ b/chromium/content/browser/web_contents/web_contents_impl.cc @@ -2400,8 +2400,7 @@ void WebContentsImpl::CreateNewWindow( // Any new WebContents opened while this WebContents is in fullscreen can be // used to confuse the user, so drop fullscreen. - if (IsFullscreenForCurrentTab()) - ExitFullscreen(true); + ForSecurityDropFullscreen(); if (params.opener_suppressed) { // When the opener is suppressed, the original renderer cannot access the @@ -3959,8 +3958,7 @@ void WebContentsImpl::ViewSource(RenderFrameHostImpl* frame) { // Any new WebContents opened while this WebContents is in fullscreen can be // used to confuse the user, so drop fullscreen. - if (IsFullscreenForCurrentTab()) - ExitFullscreen(true); + ForSecurityDropFullscreen(); // We intentionally don't share the SiteInstance with the original frame so // that view source has a consistent process model and always ends up in a new @@ -4639,8 +4637,7 @@ void WebContentsImpl::RunJavaScriptDialog(RenderFrameHost* render_frame_host, // Running a dialog causes an exit to webpage-initiated fullscreen. // http://crbug.com/728276 - if (IsFullscreenForCurrentTab()) - ExitFullscreen(true); + ForSecurityDropFullscreen(); auto callback = base::BindOnce(&WebContentsImpl::OnDialogClosed, base::Unretained(this), @@ -4707,8 +4704,7 @@ void WebContentsImpl::RunBeforeUnloadConfirm( // Running a dialog causes an exit to webpage-initiated fullscreen. // http://crbug.com/728276 - if (IsFullscreenForCurrentTab()) - ExitFullscreen(true); + ForSecurityDropFullscreen(); RenderFrameHostImpl* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host); @@ -5286,6 +5282,15 @@ void WebContentsImpl::EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) { } } +void WebContentsImpl::ForSecurityDropFullscreen() { + WebContentsImpl* web_contents = this; + while (web_contents) { + if (web_contents->IsFullscreenForCurrentTab()) + web_contents->ExitFullscreen(true); + web_contents = web_contents->GetOuterWebContents(); + } +} + void WebContentsImpl::SetAsFocusedWebContentsIfNecessary() { // Only change focus if we are not currently focused. WebContentsImpl* old_contents = GetFocusedWebContents(); @@ -5353,8 +5358,7 @@ void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node, void WebContentsImpl::DidCallFocus() { // Any explicit focusing of another window while this WebContents is in // fullscreen can be used to confuse the user, so drop fullscreen. - if (IsFullscreenForCurrentTab()) - ExitFullscreen(true); + ForSecurityDropFullscreen(); } RenderFrameHost* WebContentsImpl::GetFocusedFrameIncludingInnerWebContents() { diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h index b5768e75188..a22ae338156 100644 --- a/chromium/content/browser/web_contents/web_contents_impl.h +++ b/chromium/content/browser/web_contents/web_contents_impl.h @@ -906,6 +906,11 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, // |IsFullscreen| must return |true| when this method is called. bool HasActiveEffectivelyFullscreenVideo() const; + // The WebContents is trying to take some action that would cause user + // confusion if taken while in fullscreen. If this WebContents or any outer + // WebContents is in fullscreen, drop it. + void ForSecurityDropFullscreen(); + // When inner or outer WebContents are present, become the focused // WebContentsImpl. This will activate this content's main frame RenderWidget // and indirectly all its subframe widgets. GetFocusedRenderWidgetHost will @@ -960,6 +965,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, DialogsFromJavaScriptEndFullscreen); FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, + DialogsFromJavaScriptEndFullscreenEvenInInnerWC); + FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, PopupsFromJavaScriptEndFullscreen); FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, FocusFromJavaScriptEndsFullscreen); diff --git a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc index ca594cb6266..be1c7378a03 100644 --- a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc @@ -1055,8 +1055,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager, void ExitFullscreenModeForTab(WebContents*) override { is_fullscreen_ = false; - if (waiting_for_ == kFullscreenExit) + if (waiting_for_ == kFullscreenExit) { + waiting_for_ = kNothing; run_loop_->Quit(); + } } bool IsFullscreenForTabOrPending( @@ -1072,8 +1074,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager, bool* was_blocked) override { popup_.reset(new_contents); - if (waiting_for_ == kNewContents) + if (waiting_for_ == kNewContents) { + waiting_for_ = kNothing; run_loop_->Quit(); + } } // JavaScriptDialogManager @@ -1088,8 +1092,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager, last_message_ = base::UTF16ToUTF8(message_text); *did_suppress_message = true; - if (waiting_for_ == kDialog) + if (waiting_for_ == kDialog) { + waiting_for_ = kNothing; run_loop_->Quit(); + } } void RunBeforeUnloadDialog(WebContents* web_contents, @@ -1098,8 +1104,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager, DialogClosedCallback callback) override { std::move(callback).Run(true, base::string16()); - if (waiting_for_ == kDialog) + if (waiting_for_ == kDialog) { + waiting_for_ = kNothing; run_loop_->Quit(); + } } bool HandleJavaScriptDialog(WebContents* web_contents, @@ -1112,7 +1120,12 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager, bool reset_state) override {} private: - enum { kDialog, kNewContents, kFullscreenExit } waiting_for_; + enum { + kNothing, + kDialog, + kNewContents, + kFullscreenExit + } waiting_for_ = kNothing; std::string last_message_; @@ -1587,6 +1600,51 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, } IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, + DialogsFromJavaScriptEndFullscreenEvenInInnerWC) { + WebContentsImpl* top_contents = + static_cast<WebContentsImpl*>(shell()->web_contents()); + TestWCDelegateForDialogsAndFullscreen top_test_delegate; + top_contents->SetDelegate(&top_test_delegate); + + GURL url("about:blank"); + EXPECT_TRUE(NavigateToURL(shell(), url)); + + FrameTreeNode* root = top_contents->GetFrameTree()->root(); + ASSERT_EQ(0U, root->child_count()); + + std::string script = + "var iframe = document.createElement('iframe');" + "document.body.appendChild(iframe);"; + EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script)); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + + ASSERT_EQ(1U, root->child_count()); + RenderFrameHost* frame = root->child_at(0)->current_frame_host(); + ASSERT_NE(nullptr, frame); + + WebContentsImpl* inner_contents = + static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(frame)); + TestWCDelegateForDialogsAndFullscreen inner_test_delegate; + inner_contents->SetDelegate(&inner_test_delegate); + + // A dialog from the inner WebContents should make the outer contents lose + // fullscreen. + top_contents->EnterFullscreenMode(url, blink::WebFullscreenOptions()); + EXPECT_TRUE(top_contents->IsFullscreenForCurrentTab()); + script = "alert('hi')"; + inner_test_delegate.WillWaitForDialog(); + EXPECT_TRUE(content::ExecuteScript(inner_contents, script)); + inner_test_delegate.Wait(); + EXPECT_FALSE(top_contents->IsFullscreenForCurrentTab()); + + inner_contents->SetDelegate(nullptr); + inner_contents->SetJavaScriptDialogManagerForTesting(nullptr); + + top_contents->SetDelegate(nullptr); + top_contents->SetJavaScriptDialogManagerForTesting(nullptr); +} + +IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, PopupsFromJavaScriptEndFullscreen) { WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); TestWCDelegateForDialogsAndFullscreen test_delegate; |