summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Tanzer <gtanzer@chromium.org>2022-03-02 18:33:42 +0000
committerMichael BrĂ¼ning <michael.bruning@qt.io>2022-05-20 14:44:13 +0000
commite749ff3b639a693f217de338f6283a0f555f7bfe (patch)
treef29c2a846cc79078ea1a47c1b0bc046a996a0228
parent0d154ed1e4b696678784ce6ba0c2d80507e59eb7 (diff)
downloadqtwebengine-chromium-e749ff3b639a693f217de338f6283a0f555f7bfe.tar.gz
[Backport] CVE-2022-1497: Inappropriate implementation in Input
Manual cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/3481666: Reland "Fix noopener case for user activation consumption" This is a reland of e9828a82b5c182dc9a7fb0ae7226c35ba1726e7d The MSAN error is from checking status before err in content/renderer/render_view_impl.cc . https://ci.chromium.org/ui/p/chromium/builders/ci/Linux%20ChromiumOS%20MSan%20Tests/b8821495655905086193/overview The fix is to split the check for err and kIgnore into two checks, and put the err check before kBlocked. It is probably possible for the browser to consume user activation but then eventually mojo returns an error and the renderer doesn't consume activation, but that seems pretty marginal. Original change's description: > Fix noopener case for user activation consumption > > > The flow for user activation consumption in window.open was as follows: > > Renderer: ask the browser to create a new window > Browser: consume transient user activation (in the browser, and via RPC > to remote frames only) > Browser: return success for opener, return ignore for noopener > Renderer: consume transient user activation upon success > > So in the noopener case, the renderer with the local frame where the > window.open originated didn't have its transient user activation > consumed. > > > The new behavior is to consume user activation in the calling renderer > whenever it is consumed in the browser. We accomplish this by returning > a distinct value kBlocked to represent failure before the browser > consumes user activation. > > Bug: 1264543, 1291210 > Change-Id: Iffb6e3fd772bef625d3d28e600e6fb73d70ab29f > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3468171 > Reviewed-by: Dominic Farolino <dom@chromium.org> > Reviewed-by: Ken Buchanan <kenrb@chromium.org> > Reviewed-by: Mustaq Ahmed <mustaq@chromium.org> > Reviewed-by: Charles Reis <creis@chromium.org> > Reviewed-by: Jonathan Ross <jonross@chromium.org> > Reviewed-by: Daniel Cheng <dcheng@chromium.org> > Commit-Queue: Garrett Tanzer <gtanzer@chromium.org> > Cr-Commit-Position: refs/heads/main@{#973876} Bug: 1264543, 1291210 Change-Id: Ie27c4d68db34dfd98adee7cc5c743953dad59834 Reviewed-by: Jonathan Ross <jonross@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Mustaq Ahmed <mustaq@chromium.org> Reviewed-by: Ken Buchanan <kenrb@chromium.org> Reviewed-by: Charles Reis <creis@chromium.org> Commit-Queue: Garrett Tanzer <gtanzer@chromium.org> Cr-Commit-Position: refs/heads/main@{#976745} Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r--chromium/content/browser/renderer_host/render_frame_host_impl.cc27
-rw-r--r--chromium/content/common/frame.mojom6
-rw-r--r--chromium/content/renderer/render_view_impl.cc28
3 files changed, 41 insertions, 20 deletions
diff --git a/chromium/content/browser/renderer_host/render_frame_host_impl.cc b/chromium/content/browser/renderer_host/render_frame_host_impl.cc
index 6c3b61e8580..47cb4f5ec27 100644
--- a/chromium/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_frame_host_impl.cc
@@ -5295,17 +5295,22 @@ void RenderFrameHostImpl::CreateNewWindow(
can_create_window = false;
}
- bool was_consumed = false;
- if (can_create_window) {
- // Consume activation even w/o User Activation v2, to sync other renderers
- // with calling renderer.
- was_consumed = frame_tree_node_->UpdateUserActivationState(
- blink::mojom::UserActivationUpdateType::kConsumeTransientActivation,
- blink::mojom::UserActivationNotificationType::kNone);
- } else {
- std::move(callback).Run(mojom::CreateNewWindowStatus::kIgnore, nullptr);
- return;
- }
+ // If this frame isn't allowed to create a window, return early (before we
+ // consume transient user activation).
+ if (!can_create_window) {
+ std::move(callback).Run(mojom::CreateNewWindowStatus::kBlocked, nullptr);
+ return;
+ }
+
+ // Otherwise, consume user activation before we proceed. In particular, it is
+ // important to do this before we return from the |opener_suppressed| case
+ // below.
+ // NB: This call will consume activations in the browser and the remote frame
+ // proxies for this frame. The initiating renderer will consume its view of
+ // the activations after we return.
+ bool was_consumed = frame_tree_node_->UpdateUserActivationState(
+ blink::mojom::UserActivationUpdateType::kConsumeTransientActivation,
+ blink::mojom::UserActivationNotificationType::kNone);
// For Android WebView, we support a pop-up like behavior for window.open()
// even if the embedding app doesn't support multiple windows. In this case,
diff --git a/chromium/content/common/frame.mojom b/chromium/content/common/frame.mojom
index b2f13658455..87276f2295e 100644
--- a/chromium/content/common/frame.mojom
+++ b/chromium/content/common/frame.mojom
@@ -532,8 +532,10 @@ struct CreateNewWindowParams {
// Operation result when the renderer asks the browser to create a new window.
enum CreateNewWindowStatus {
- // Ignore creation of the new window. This can happen because creation is
- // blocked or because the new window should have no opener relationship.
+ // Creation of the new window was blocked, e.g. because the source frame
+ // doesn't have user activation.
+ kBlocked,
+ // Ignore creation of the new window, e.g. because noopener is in effect.
kIgnore,
// Reuse the current window rather than creating a new window.
kReuse,
diff --git a/chromium/content/renderer/render_view_impl.cc b/chromium/content/renderer/render_view_impl.cc
index 68838d79e17..1aacbc56300 100644
--- a/chromium/content/renderer/render_view_impl.cc
+++ b/chromium/content/renderer/render_view_impl.cc
@@ -352,8 +352,27 @@ WebView* RenderViewImpl::CreateView(
mojom::CreateNewWindowStatus status;
mojom::CreateNewWindowReplyPtr reply;
auto* frame_host = creator_frame->GetFrameHost();
- bool err = !frame_host->CreateNewWindow(std::move(params), &status, &reply);
- if (err || status == mojom::CreateNewWindowStatus::kIgnore)
+ if (!frame_host->CreateNewWindow(std::move(params), &status, &reply)) {
+ // The sync IPC failed, e.g. maybe the render process is in the middle of
+ // shutting down. Can't create a new window without the browser process,
+ // so just bail out.
+ return nullptr;
+ }
+
+ // If creation of the window was blocked (e.g. because this frame doesn't
+ // have user activation), return before consuming user activation. A frame
+ // that isn't allowed to open a window shouldn't be able to consume the
+ // activation for the rest of the frame tree.
+ if (status == mojom::CreateNewWindowStatus::kBlocked)
+ return nullptr;
+
+ // Consume the transient user activation in the current renderer.
+ consumed_user_gesture = creator->ConsumeTransientUserActivation(
+ blink::UserActivationUpdateSource::kBrowser);
+
+ // If we should ignore the new window (e.g. because of `noopener`), return
+ // now that user activation was consumed.
+ if (status == mojom::CreateNewWindowStatus::kIgnore)
return nullptr;
// For Android WebView, we support a pop-up like behavior for window.open()
@@ -373,11 +392,6 @@ WebView* RenderViewImpl::CreateView(
DCHECK_NE(MSG_ROUTING_NONE, reply->main_frame_route_id);
DCHECK_NE(MSG_ROUTING_NONE, reply->widget_params->routing_id);
- // The browser allowed creation of a new window and consumed the user
- // activation.
- consumed_user_gesture = creator->ConsumeTransientUserActivation(
- blink::UserActivationUpdateSource::kBrowser);
-
// While this view may be a background extension page, it can spawn a visible
// render view. So we just assume that the new one is not another background
// page instead of passing on our own value.