summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-05-15 13:56:58 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2017-07-11 13:20:14 +0000
commitc99afcd115268e2b864cc9f2be0a25e84c6565ca (patch)
treef09b676286170641e29d6dad8b1989d301dad69d
parent2d14bca522d164901e316b8a39c5e4f999cf2ea3 (diff)
[Backport] Fix of CVE-2017-5061 and CVE-2017-5067
(Reland) Discard compositor frames from unloaded web content This is a reland of https://codereview.chromium.org/2707243005/ with a small change to fix an uninitialized memory error that fails on MSAN bots. BUG=672847,648117 TBR=danakj@chromium.org, creis@chromium.org CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_site_isolation Review-Url: https://codereview.chromium.org/2731283003 Cr-Commit-Position: refs/heads/master@{#454954} (cherry picked from commit 5d78b84d39bd34bc9fce9d01c0dcd5a22a330d34) Change-Id: I5552a8bd1af7581b695abeddc94b2e13f9015069 Review-Url: https://codereview.chromium.org/2793013002 . Cr-Commit-Position: refs/branch-heads/3029@{#547} Cr-Branched-From: 939b32ee5ba05c396eef3fd992822fcca9a2e262-refs/heads/master@{#454471} Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--chromium/cc/output/compositor_frame_metadata.h6
-rw-r--r--chromium/cc/trees/layer_tree_host.cc12
-rw-r--r--chromium/cc/trees/layer_tree_host.h5
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc1
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc3
-rw-r--r--chromium/cc/trees/layer_tree_impl.h5
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.cc2
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.cc12
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.h15
-rw-r--r--chromium/content/common/cc_messages.h1
-rw-r--r--chromium/content/common/frame_messages.h5
-rw-r--r--chromium/content/renderer/gpu/render_widget_compositor.cc4
-rw-r--r--chromium/content/renderer/gpu/render_widget_compositor.h1
-rw-r--r--chromium/content/renderer/render_frame_impl.cc4
-rw-r--r--chromium/content/renderer/render_widget.cc13
-rw-r--r--chromium/content/renderer/render_widget.h16
16 files changed, 98 insertions, 7 deletions
diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h
index ad3cdd8d428..97d6862546c 100644
--- a/chromium/cc/output/compositor_frame_metadata.h
+++ b/chromium/cc/output/compositor_frame_metadata.h
@@ -63,6 +63,12 @@ class CC_EXPORT CompositorFrameMetadata {
// This is the set of Surfaces that are referenced by this frame.
std::vector<SurfaceId> referenced_surfaces;
+
+ // This is a value that allows the browser to associate compositor frames
+ // with the content that they represent -- typically top-level page loads.
+ // TODO(kenrb, fsamuel): This should eventually by SurfaceID, when they
+ // become available in all renderer processes. See https://crbug.com/695579.
+ uint32_t content_source_id = 0;
};
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index cb9619b1eba..686a1bb7424 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -133,6 +133,7 @@ LayerTreeHost::LayerTreeHost(InitParams* params, CompositorMode mode)
device_scale_factor_(1.f),
painted_device_scale_factor_(1.f),
visible_(false),
+ content_source_id_(0),
page_scale_factor_(1.f),
min_page_scale_factor_(1.f),
max_page_scale_factor_(1.f),
@@ -363,6 +364,9 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->SetDeviceScaleFactor(device_scale_factor_);
sync_tree->set_painted_device_scale_factor(painted_device_scale_factor_);
host_impl->SetDebugState(debug_state_);
+
+ sync_tree->set_content_source_id(content_source_id_);
+
if (pending_page_scale_animation_) {
sync_tree->SetPendingPageScaleAnimation(
std::move(pending_page_scale_animation_));
@@ -516,6 +520,14 @@ void LayerTreeHost::SetNeedsDisplayOnAllLayers() {
}
}
+void LayerTreeHost::SetContentSourceId(uint32_t id) {
+ if (content_source_id_ == id)
+ return;
+ content_source_id_ = id;
+ SetNeedsCommit();
+}
+
+
const RendererCapabilities& LayerTreeHost::GetRendererCapabilities() const {
return proxy_->GetRendererCapabilities();
}
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index d8eba8d1073..554146fa07a 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -253,6 +253,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void SetDeviceScaleFactor(float device_scale_factor);
void SetPaintedDeviceScaleFactor(float painted_device_scale_factor);
+ void SetContentSourceId(uint32_t);
+ uint32_t content_source_id() const { return content_source_id_; }
+
float device_scale_factor() const { return device_scale_factor_; }
void UpdateTopControlsState(TopControlsState constraints,
@@ -492,6 +495,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
bool visible_;
+ uint32_t content_source_id_;
+
float page_scale_factor_;
float min_page_scale_factor_;
float max_page_scale_factor_;
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 7446a69daa5..cbab911e4f5 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -1620,6 +1620,7 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const {
metadata.location_bar_content_translation =
gfx::Vector2dF(0.f, top_controls_manager_->ContentTopOffset());
metadata.root_background_color = active_tree_->background_color();
+ metadata.content_source_id = active_tree_->content_source_id();
active_tree_->GetViewportSelection(&metadata.selection);
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index c16792c1b2f..7ffc22a3460 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -78,6 +78,7 @@ LayerTreeImpl::LayerTreeImpl(
max_page_scale_factor_(0),
device_scale_factor_(1.f),
painted_device_scale_factor_(1.f),
+ content_source_id_(0),
elastic_overscroll_(elastic_overscroll),
viewport_size_invalid_(false),
needs_update_draw_properties_(true),
@@ -340,6 +341,8 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->set_painted_device_scale_factor(painted_device_scale_factor());
target_tree->elastic_overscroll()->PushPendingToActive();
+ target_tree->set_content_source_id(content_source_id());
+
target_tree->pending_page_scale_animation_ =
std::move(pending_page_scale_animation_);
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 91e346686d1..ffbe6736838 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -229,6 +229,9 @@ class CC_EXPORT LayerTreeImpl {
return painted_device_scale_factor_;
}
+ void set_content_source_id(uint32_t id) { content_source_id_ = id; }
+ uint32_t content_source_id() { return content_source_id_; }
+
SyncedElasticOverscroll* elastic_overscroll() {
return elastic_overscroll_.get();
}
@@ -480,6 +483,8 @@ class CC_EXPORT LayerTreeImpl {
float device_scale_factor_;
float painted_device_scale_factor_;
+ uint32_t content_source_id_;
+
scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_;
typedef base::hash_map<int, LayerImpl*> LayerIdMap;
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc
index e88b0855231..fb433833520 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc
@@ -1019,7 +1019,7 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
if (frame_tree_node_->IsMainFrame() && GetView() &&
!validated_params.was_within_same_page) {
RenderWidgetHostImpl::From(GetView()->GetRenderWidgetHost())
- ->StartNewContentRenderingTimeout();
+ ->StartNewContentRenderingTimeout(validated_params.content_source_id);
}
// PlzNavigate
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.cc b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
index 6516e5ec903..4690ff25e65 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
@@ -215,6 +215,7 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
new_content_rendering_delay_(
base::TimeDelta::FromMilliseconds(kNewContentRenderingDelayMs)),
+ current_content_source_id_(0),
mouse_wheel_coalesce_timer_(new base::ElapsedTimer()),
weak_factory_(this) {
CHECK(delegate_);
@@ -943,7 +944,8 @@ void RenderWidgetHostImpl::StopHangMonitorTimeout() {
RendererIsResponsive();
}
-void RenderWidgetHostImpl::StartNewContentRenderingTimeout() {
+void RenderWidgetHostImpl::StartNewContentRenderingTimeout(uint32_t next_source_id) {
+ current_content_source_id_ = next_source_id;
// It is possible for a compositor frame to arrive before the browser is
// notified about the page being committed, in which case no timer is
// necessary.
@@ -1592,7 +1594,13 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame(
if (touch_emulator_)
touch_emulator_->SetDoubleTapSupportForPageEnabled(!is_mobile_optimized);
- if (view_) {
+ // Ignore this frame if its content has already been unloaded. Source ID
+ // is always zero for an OOPIF because we are only concerned with displaying
+ // stale graphics on top-level frames. We accept frames that have a source ID
+ // greater than |current_content_source_id_| because in some cases the first
+ // compositor frame can arrive before the navigation commit message that
+ // updates that value.
+ if (view_ && frame->metadata.content_source_id >= current_content_source_id_) {
view_->OnSwapCompositorFrame(output_surface_id, std::move(frame));
view_->DidReceiveRendererFrame();
} else {
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.h b/chromium/content/browser/renderer_host/render_widget_host_impl.h
index d5d9d5ad654..0ad1e005df8 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h
@@ -275,9 +275,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// responsive.
void StopHangMonitorTimeout();
- // Starts the rendering timeout, which will clear displayed graphics if
- // a new compositor frame is not received before it expires.
- void StartNewContentRenderingTimeout();
+ // a new compositor frame is not received before it expires. This also causes
+ // any new compositor frames received with content_source_id less than
+ // |next_source_id| to be discarded.
+ void StartNewContentRenderingTimeout(uint32_t next_source_id);
// Notification that a new compositor frame has been generated following
// a page load. This stops |new_content_rendering_timeout_|, or prevents
@@ -819,6 +820,14 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// renderer process before clearing any previously displayed content.
base::TimeDelta new_content_rendering_delay_;
+ // This identifier tags compositor frames according to the page load with
+ // which they are associated, to prevent an unloaded web page from being
+ // drawn after a navigation to a new page has already committed. This is
+ // a no-op for non-top-level RenderWidgets, as that should always be zero.
+ // TODO(kenrb, fsamuel): We should use SurfaceIDs for this purpose when they
+ // are available in the renderer process. See https://crbug.com/695579.
+ uint32_t current_content_source_id_;
+
// Timer used to batch together mouse wheel events for the delegate
// OnUserInteraction method. A wheel event is only dispatched when a wheel
// event has not been seen for kMouseWheelCoalesceInterval seconds prior.
diff --git a/chromium/content/common/cc_messages.h b/chromium/content/common/cc_messages.h
index 9f2e84ece39..e61f265650e 100644
--- a/chromium/content/common/cc_messages.h
+++ b/chromium/content/common/cc_messages.h
@@ -319,6 +319,7 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
IPC_STRUCT_TRAITS_MEMBER(latency_info)
IPC_STRUCT_TRAITS_MEMBER(satisfies_sequences)
IPC_STRUCT_TRAITS_MEMBER(referenced_surfaces)
+ IPC_STRUCT_TRAITS_MEMBER(content_source_id)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::GLFrameData)
diff --git a/chromium/content/common/frame_messages.h b/chromium/content/common/frame_messages.h
index 6fcad1a90df..2722b9905a9 100644
--- a/chromium/content/common/frame_messages.h
+++ b/chromium/content/common/frame_messages.h
@@ -276,6 +276,11 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params,
// True if the document for the load is enforcing strict mixed content
// checking.
IPC_STRUCT_MEMBER(bool, should_enforce_strict_mixed_content_checking)
+
+ // This is a non-decreasing value that the browser process can use to
+ // identify and discard compositor frames that correspond to now-unloaded
+ // web content.
+ IPC_STRUCT_MEMBER(uint32_t, content_source_id)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(FrameMsg_PostMessage_Params)
diff --git a/chromium/content/renderer/gpu/render_widget_compositor.cc b/chromium/content/renderer/gpu/render_widget_compositor.cc
index 4048e3b6ffd..fde8cd57515 100644
--- a/chromium/content/renderer/gpu/render_widget_compositor.cc
+++ b/chromium/content/renderer/gpu/render_widget_compositor.cc
@@ -1135,4 +1135,8 @@ void RenderWidgetCompositor::SetPaintedDeviceScaleFactor(
layer_tree_host_->SetPaintedDeviceScaleFactor(device_scale);
}
+void RenderWidgetCompositor::SetContentSourceId(uint32_t id) {
+ layer_tree_host_->SetContentSourceId(id);
+}
+
} // namespace content
diff --git a/chromium/content/renderer/gpu/render_widget_compositor.h b/chromium/content/renderer/gpu/render_widget_compositor.h
index 0eac7cd9739..7f4be57a7c2 100644
--- a/chromium/content/renderer/gpu/render_widget_compositor.h
+++ b/chromium/content/renderer/gpu/render_widget_compositor.h
@@ -92,6 +92,7 @@ class CONTENT_EXPORT RenderWidgetCompositor
cc::ManagedMemoryPolicy GetGpuMemoryPolicy(
const cc::ManagedMemoryPolicy& policy);
void SetPaintedDeviceScaleFactor(float device_scale);
+ void SetContentSourceId(uint32_t);
// WebLayerTreeView implementation.
void setRootLayer(const blink::WebLayer& layer) override;
diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc
index 56e1adc3bf1..2daa02a6da1 100644
--- a/chromium/content/renderer/render_frame_impl.cc
+++ b/chromium/content/renderer/render_frame_impl.cc
@@ -3157,6 +3157,7 @@ void RenderFrameImpl::didCommitProvisionalLoad(
// For new page navigations, the browser process needs to be notified of the
// first paint of that page, so it can cancel the timer that waits for it.
if (is_main_frame_ && !navigation_state->WasWithinSamePage()) {
+ GetRenderWidget()->IncrementContentSourceId();
render_view_->QueueMessage(
new ViewHostMsg_DidFirstPaintAfterLoad(render_view_->routing_id_),
MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE);
@@ -4498,6 +4499,9 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad(
params.page_state = SingleHistoryItemToPageState(item);
post_id = ExtractPostId(item);
}
+
+ params.content_source_id = GetRenderWidget()->GetContentSourceId();
+
params.frame_unique_name = item.target().utf8();
params.item_sequence_number = item.itemSequenceNumber();
params.document_sequence_number = item.documentSequenceNumber();
diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc
index 0ddaf21eee1..a5a93d209c3 100644
--- a/chromium/content/renderer/render_widget.cc
+++ b/chromium/content/renderer/render_widget.cc
@@ -477,7 +477,8 @@ RenderWidget::RenderWidget(CompositorDependencies* compositor_deps,
popup_origin_scale_for_emulation_(0.f),
frame_swap_message_queue_(new FrameSwapMessageQueue()),
resizing_mode_selector_(new ResizingModeSelector()),
- has_host_context_menu_location_(false) {
+ has_host_context_menu_location_(false),
+ current_content_source_id_(0) {
if (!swapped_out)
RenderProcess::current()->AddRefProcess();
DCHECK(RenderThread::Get());
@@ -1251,6 +1252,7 @@ void RenderWidget::initializeLayerTreeView() {
compositor_ = RenderWidgetCompositor::Create(this, compositor_deps_);
compositor_->setViewportSize(physical_backing_size_);
OnDeviceScaleFactorChanged();
+ compositor_->SetContentSourceId(current_content_source_id_);
// For background pages and certain tests, we don't want to trigger
// OutputSurface creation.
if (compositor_never_visible_ || !RenderThreadImpl::current())
@@ -2117,6 +2119,15 @@ void RenderWidget::didUpdateTextOfFocusedElementByNonUserInput() {
#endif
}
+uint32_t RenderWidget::GetContentSourceId() {
+ return current_content_source_id_;
+}
+
+void RenderWidget::IncrementContentSourceId() {
+ if (compositor_)
+ compositor_->SetContentSourceId(++current_content_source_id_);
+}
+
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
RenderWidget::CreateGraphicsContext3D(GpuChannelHost* gpu_channel_host) {
// Explicitly disable antialiasing for the compositor. As of the time of
diff --git a/chromium/content/renderer/render_widget.h b/chromium/content/renderer/render_widget.h
index 20d98e87de2..20e5a41ca99 100644
--- a/chromium/content/renderer/render_widget.h
+++ b/chromium/content/renderer/render_widget.h
@@ -342,6 +342,9 @@ class CONTENT_EXPORT RenderWidget
bool host_closing() const { return host_closing_; }
+ uint32_t GetContentSourceId();
+ void IncrementContentSourceId();
+
protected:
// Friend RefCounted so that the dtor can be non-public. Using this class
// without ref-counting is an error.
@@ -755,6 +758,19 @@ class CONTENT_EXPORT RenderWidget
scoped_ptr<scheduler::RenderWidgetSchedulingState>
render_widget_scheduling_state_;
+ // This is initialized to zero and is incremented on each non-same-page
+ // navigation commit by RenderFrameImpl. At that time it is sent to the
+ // compositor so that it can tag compositor frames, and RenderFrameImpl is
+ // responsible for sending it to the browser process to be used to match
+ // each compositor frame to the most recent page navigation before it was
+ // generated.
+ // This only applies to main frames, and is not touched for subframe
+ // RenderWidgets, where there is no concern around displaying unloaded
+ // content.
+ // TODO(kenrb, fsamuel): This should be removed when SurfaceIDs can be used
+ // to replace it. See https://crbug.com/695579.
+ uint32_t current_content_source_id_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidget);
};