summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-10-24 15:49:33 +0200
committerMichael Brüning <michael.bruning@qt.io>2018-11-01 15:30:01 +0000
commite467d563636dc3ee01f2485bab871fb7405b7bab (patch)
treeafc53c7a5a0cbc65f9a1c69abeb8ef470907c414
parent37b5fe3597c6f0912e7fd6b2d6ab17a0ab2cbc30 (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>
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.cc24
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.h7
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_browsertest.cc68
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;