Skip to content

Commit

Permalink
Change StartDragging IPC to be per-frame.
Browse files Browse the repository at this point in the history
This allows per-frame info, such as origin, to be attributed to drags.

Bug: 1346429
Change-Id: Ia0b947bb0062458071ca07616f8dd741689b5b9c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4828259
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1191144}
  • Loading branch information
zetafunction authored and pull[bot] committed Feb 28, 2024
1 parent 7ce8b28 commit 1427674
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 146 deletions.
12 changes: 12 additions & 0 deletions content/browser/renderer_host/render_frame_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8885,6 +8885,18 @@ void RenderFrameHostImpl::OnViewTransitionOptInChanged(
->set_same_origin_opt_in(view_transition_opt_in);
}

void RenderFrameHostImpl::StartDragging(
blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask drag_operations_mask,
const SkBitmap& unsafe_bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) {
GetRenderWidgetHost()->StartDragging(
std::move(drag_data), drag_operations_mask, unsafe_bitmap,
cursor_offset_in_dip, drag_obj_rect_in_dip, std::move(event_info));
}

void RenderFrameHostImpl::CreateNewPopupWidget(
mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost>
blink_popup_widget_host,
Expand Down
6 changes: 6 additions & 0 deletions content/browser/renderer_host/render_frame_host_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,12 @@ class CONTENT_EXPORT RenderFrameHostImpl
const base::UnguessableToken& devtools_frame_token) override;
void OnViewTransitionOptInChanged(blink::mojom::ViewTransitionSameOriginOptIn
view_transition_opt_in) override;
void StartDragging(blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask drag_operations_mask,
const SkBitmap& unsafe_bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) override;

// blink::mojom::BackForwardCacheControllerHost:
void EvictFromBackForwardCache(blink::mojom::RendererEvictionReason) override;
Expand Down
182 changes: 91 additions & 91 deletions content/browser/renderer_host/render_widget_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2694,6 +2694,97 @@ void RenderWidgetHostImpl::UpdateBrowserControlsState(
animate);
}

void RenderWidgetHostImpl::StartDragging(
blink::mojom::DragDataPtr drag_data,
DragOperationsMask drag_operations_mask,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) {
DropData drop_data = DragDataToDropData(*drag_data);
DropData filtered_data(drop_data);
RenderProcessHost* process = GetProcess();
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();

// Allow drag of Javascript URLs to enable bookmarklet drag to bookmark bar.
if (!filtered_data.url.SchemeIs(url::kJavaScriptScheme)) {
process->FilterURL(true, &filtered_data.url);
}
process->FilterURL(false, &filtered_data.html_base_url);
// Filter out any paths that the renderer didn't have access to. This prevents
// the following attack on a malicious renderer:
// 1. StartDragging IPC sent with renderer-specified filesystem paths that it
// doesn't have read permissions for.
// 2. We initiate a native DnD operation.
// 3. DnD operation immediately ends since mouse is not held down. DnD events
// still fire though, which causes read permissions to be granted to the
// renderer for any file paths in the drop.
filtered_data.filenames.clear();
for (const auto& file_info : drop_data.filenames) {
if (policy->CanReadFile(GetProcess()->GetID(), file_info.path)) {
filtered_data.filenames.push_back(file_info);
}
}

storage::FileSystemContext* file_system_context =
GetProcess()->GetStoragePartition()->GetFileSystemContext();
filtered_data.file_system_files.clear();

for (const auto& file_system_file : drop_data.file_system_files) {
storage::FileSystemURL file_system_url =
file_system_context->CrackURLInFirstPartyContext(file_system_file.url);

// Sandboxed filesystem files should never be handled via this path, so
// skip any that are sent from the renderer. In all other cases, it should
// be safe to use the FileSystemURL returned from calling
// CrackURLInFirstPartyContext as long as CanReadFileSystemFile only
// performs checks on the origin and doesn't use more of the StorageKey.
if (file_system_url.type() == storage::kFileSystemTypePersistent ||
file_system_url.type() == storage::kFileSystemTypeTemporary) {
continue;
}

if (policy->CanReadFileSystemFile(GetProcess()->GetID(), file_system_url)) {
filtered_data.file_system_files.push_back(file_system_file);
}
}

if (frame_tree_) {
bool intercepted = false;
devtools_instrumentation::WillStartDragging(
frame_tree_->root(), filtered_data, std::move(drag_data),
drag_operations_mask, &intercepted);
if (intercepted) {
return;
}
}

RenderViewHostDelegateView* view = delegate_->GetDelegateView();
if (!view || !GetView()) {
// Need to clear drag and drop state in blink.
DragSourceSystemDragEnded();
return;
}
float scale = GetScaleFactorForView(GetView());
gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(bitmap, scale);
gfx::Vector2d offset = cursor_offset_in_dip;
gfx::Rect rect = drag_obj_rect_in_dip;
#if BUILDFLAG(IS_WIN)
// Scale the offset by device scale factor, otherwise the drag
// image location doesn't line up with the drop location (drag destination).
// TODO(crbug.com/1354831): this conversion should not be necessary.
gfx::Vector2dF scaled_offset = static_cast<gfx::Vector2dF>(offset);
scaled_offset.Scale(scale);
offset = gfx::ToRoundedVector2d(scaled_offset);
gfx::RectF scaled_rect = static_cast<gfx::RectF>(rect);
scaled_rect.Scale(scale);
rect = gfx::ToRoundedRect(scaled_rect);
#endif
view->StartDragging(filtered_data, drag_operations_mask, image, offset, rect,
*event_info, this);
}

// static
bool RenderWidgetHostImpl::DidVisualPropertiesSizeChange(
const blink::VisualProperties& old_visual_properties,
Expand Down Expand Up @@ -2849,97 +2940,6 @@ void RenderWidgetHostImpl::AutoscrollEnd() {
cancel_event, ui::LatencyInfo(ui::SourceEventType::OTHER));
}

void RenderWidgetHostImpl::StartDragging(
blink::mojom::DragDataPtr drag_data,
DragOperationsMask drag_operations_mask,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) {
DropData drop_data = DragDataToDropData(*drag_data);
DropData filtered_data(drop_data);
RenderProcessHost* process = GetProcess();
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();

// Allow drag of Javascript URLs to enable bookmarklet drag to bookmark bar.
if (!filtered_data.url.SchemeIs(url::kJavaScriptScheme)) {
process->FilterURL(true, &filtered_data.url);
}
process->FilterURL(false, &filtered_data.html_base_url);
// Filter out any paths that the renderer didn't have access to. This prevents
// the following attack on a malicious renderer:
// 1. StartDragging IPC sent with renderer-specified filesystem paths that it
// doesn't have read permissions for.
// 2. We initiate a native DnD operation.
// 3. DnD operation immediately ends since mouse is not held down. DnD events
// still fire though, which causes read permissions to be granted to the
// renderer for any file paths in the drop.
filtered_data.filenames.clear();
for (const auto& file_info : drop_data.filenames) {
if (policy->CanReadFile(GetProcess()->GetID(), file_info.path)) {
filtered_data.filenames.push_back(file_info);
}
}

storage::FileSystemContext* file_system_context =
GetProcess()->GetStoragePartition()->GetFileSystemContext();
filtered_data.file_system_files.clear();

for (const auto& file_system_file : drop_data.file_system_files) {
storage::FileSystemURL file_system_url =
file_system_context->CrackURLInFirstPartyContext(file_system_file.url);

// Sandboxed filesystem files should never be handled via this path, so
// skip any that are sent from the renderer. In all other cases, it should
// be safe to use the FileSystemURL returned from calling
// CrackURLInFirstPartyContext as long as CanReadFileSystemFile only
// performs checks on the origin and doesn't use more of the StorageKey.
if (file_system_url.type() == storage::kFileSystemTypePersistent ||
file_system_url.type() == storage::kFileSystemTypeTemporary) {
continue;
}

if (policy->CanReadFileSystemFile(GetProcess()->GetID(), file_system_url)) {
filtered_data.file_system_files.push_back(file_system_file);
}
}

if (frame_tree_) {
bool intercepted = false;
devtools_instrumentation::WillStartDragging(
frame_tree_->root(), filtered_data, std::move(drag_data),
drag_operations_mask, &intercepted);
if (intercepted) {
return;
}
}

RenderViewHostDelegateView* view = delegate_->GetDelegateView();
if (!view || !GetView()) {
// Need to clear drag and drop state in blink.
DragSourceSystemDragEnded();
return;
}
float scale = GetScaleFactorForView(GetView());
gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(bitmap, scale);
gfx::Vector2d offset = cursor_offset_in_dip;
gfx::Rect rect = drag_obj_rect_in_dip;
#if BUILDFLAG(IS_WIN)
// Scale the offset by device scale factor, otherwise the drag
// image location doesn't line up with the drop location (drag destination).
// TODO(crbug.com/1354831): this conversion should not be necessary.
gfx::Vector2dF scaled_offset = static_cast<gfx::Vector2dF>(offset);
scaled_offset.Scale(scale);
offset = gfx::ToRoundedVector2d(scaled_offset);
gfx::RectF scaled_rect = static_cast<gfx::RectF>(rect);
scaled_rect.Scale(scale);
rect = gfx::ToRoundedRect(scaled_rect);
#endif
view->StartDragging(filtered_data, drag_operations_mask, image, offset, rect,
*event_info, this);
}

bool RenderWidgetHostImpl::IsAutoscrollInProgress() {
return autoscroll_in_progress_;
}
Expand Down
13 changes: 7 additions & 6 deletions content/browser/renderer_host/render_widget_host_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,13 @@ class CONTENT_EXPORT RenderWidgetHostImpl
cc::BrowserControlsState current,
bool animate);

void StartDragging(blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask drag_operations_mask,
const SkBitmap& unsafe_bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info);

protected:
// |routing_id| must not be MSG_ROUTING_NONE.
// If this object outlives |delegate|, DetachDelegate() must be called when
Expand Down Expand Up @@ -1037,12 +1044,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void AutoscrollStart(const gfx::PointF& position) override;
void AutoscrollFling(const gfx::Vector2dF& velocity) override;
void AutoscrollEnd() override;
void StartDragging(blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask drag_operations_mask,
const SkBitmap& unsafe_bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) override;

// When the RenderWidget is destroyed and recreated, this resets states in the
// browser to match the clean start for the renderer side.
Expand Down
8 changes: 0 additions & 8 deletions content/public/test/fake_render_widget_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,6 @@ void FakeRenderWidgetHost::AutoscrollFling(const gfx::Vector2dF& position) {}

void FakeRenderWidgetHost::AutoscrollEnd() {}

void FakeRenderWidgetHost::StartDragging(
blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask operations_allowed,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) {}

blink::mojom::WidgetInputHandler*
FakeRenderWidgetHost::GetWidgetInputHandler() {
if (!widget_input_handler_) {
Expand Down
6 changes: 0 additions & 6 deletions content/public/test/fake_render_widget_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ class FakeRenderWidgetHost : public blink::mojom::FrameWidgetHost,
void AutoscrollStart(const gfx::PointF& position) override;
void AutoscrollFling(const gfx::Vector2dF& position) override;
void AutoscrollEnd() override;
void StartDragging(blink::mojom::DragDataPtr drag_data,
blink::DragOperationsMask operations_allowed,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
blink::mojom::DragEventSourceInfoPtr event_info) override;

// blink::mojom::WidgetHost overrides.
void SetCursor(const ui::Cursor& cursor) override;
Expand Down
2 changes: 1 addition & 1 deletion content/test/test_render_view_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ void TestRenderViewHost::TestStartDragging(const DropData& drop_data,
SkBitmap bitmap) {
StoragePartitionImpl* storage_partition =
static_cast<StoragePartitionImpl*>(GetProcess()->GetStoragePartition());
GetWidget()->StartDragging(
GetMainRenderFrameHost()->StartDragging(
DropDataToDragData(
drop_data, storage_partition->GetFileSystemAccessManager(),
GetProcess()->GetID(),
Expand Down
13 changes: 13 additions & 0 deletions third_party/blink/public/mojom/frame/frame.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import "services/network/public/mojom/network_types.mojom";
import "services/network/public/mojom/source_location.mojom";
import "services/network/public/mojom/url_loader_completion_status.mojom";
import "services/network/public/mojom/attribution.mojom";
import "skia/public/mojom/bitmap.mojom";
import "skia/public/mojom/skcolor.mojom";
import "skia/public/mojom/skcolor4f.mojom";
import "third_party/blink/public/mojom/blob/blob.mojom";
Expand All @@ -29,6 +30,7 @@ import "third_party/blink/public/mojom/css/preferred_color_scheme.mojom";
import "third_party/blink/public/mojom/devtools/console_message.mojom";
import "third_party/blink/public/mojom/devtools/devtools_agent.mojom";
import "third_party/blink/public/mojom/devtools/inspector_issue.mojom";
import "third_party/blink/public/mojom/drag/drag.mojom";
import "third_party/blink/public/mojom/favicon/favicon_url.mojom";
import "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom";
import "third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom";
Expand Down Expand Up @@ -759,6 +761,17 @@ interface LocalFrameHost {
// See https://github.com/WICG/view-transitions/blob/main/explainer.md#declarative-opt-in-to-transitions.
OnViewTransitionOptInChanged(
ViewTransitionSameOriginOptIn view_transition_opt_in);

// Used to tell the browser the user started dragging in the content area.
// |drag_data| contains contextual information about the pieces of the page
// the user dragged. The browser uses this notification to initiate a drag
// session at the OS level.
StartDragging(DragData drag_data,
AllowedDragOperations operations_allowed,
skia.mojom.BitmapN32? image,
gfx.mojom.Vector2d cursor_offset_in_dip,
gfx.mojom.Rect drag_obj_rect_in_dip,
DragEventSourceInfo event_info);
};

// Implemented in Browser, this interface defines frame-specific methods
Expand Down
11 changes: 0 additions & 11 deletions third_party/blink/public/mojom/page/widget.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,6 @@ interface FrameWidgetHost {

// Sent by a widget to the browser to notify the end of the autoscroll.
AutoscrollEnd();

// Used to tell the browser the user started dragging in the content area.
// |drag_data| contains contextual information about the pieces of the page
// the user dragged. The browser uses this notification to initiate a drag
// session at the OS level.
StartDragging(DragData drag_data,
AllowedDragOperations operations_allowed,
skia.mojom.BitmapN32? image,
gfx.mojom.Vector2d cursor_offset_in_dip,
gfx.mojom.Rect drag_obj_rect_in_dip,
DragEventSourceInfo event_info);
};

// Implemented in Browser, this interface defines popup-widget-specific methods
Expand Down
8 changes: 0 additions & 8 deletions third_party/blink/renderer/core/frame/frame_test_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1086,14 +1086,6 @@ void TestWebFrameWidgetHost::AutoscrollFling(const gfx::Vector2dF& position) {}

void TestWebFrameWidgetHost::AutoscrollEnd() {}

void TestWebFrameWidgetHost::StartDragging(
const blink::WebDragData& drag_data,
blink::DragOperationsMask operations_allowed,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
mojom::blink::DragEventSourceInfoPtr event_info) {}

void TestWebFrameWidgetHost::BindWidgetHost(
mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost> receiver,
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
Expand Down
6 changes: 0 additions & 6 deletions third_party/blink/renderer/core/frame/frame_test_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,6 @@ class TestWebFrameWidgetHost : public mojom::blink::WidgetHost,
void AutoscrollStart(const gfx::PointF& position) override;
void AutoscrollFling(const gfx::Vector2dF& position) override;
void AutoscrollEnd() override;
void StartDragging(const blink::WebDragData& drag_data,
blink::DragOperationsMask operations_allowed,
const SkBitmap& bitmap,
const gfx::Vector2d& cursor_offset_in_dip,
const gfx::Rect& drag_obj_rect_in_dip,
mojom::blink::DragEventSourceInfoPtr event_info) override;

void BindWidgetHost(
mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,8 @@ void WebFrameWidgetImpl::CancelDrag() {
current_drag_data_ = nullptr;
}

void WebFrameWidgetImpl::StartDragging(const WebDragData& drag_data,
void WebFrameWidgetImpl::StartDragging(LocalFrame* source_frame,
const WebDragData& drag_data,
DragOperationsMask operations_allowed,
const SkBitmap& drag_image,
const gfx::Vector2d& cursor_offset,
Expand All @@ -1255,7 +1256,7 @@ void WebFrameWidgetImpl::StartDragging(const WebDragData& drag_data,
gfx::Rect drag_obj_rect_in_dips =
gfx::Rect(widget_base_->BlinkSpaceToFlooredDIPs(drag_obj_rect.origin()),
widget_base_->BlinkSpaceToFlooredDIPs(drag_obj_rect.size()));
GetAssociatedFrameWidgetHost()->StartDragging(
source_frame->GetLocalFrameHostRemote().StartDragging(
drag_data, operations_allowed, drag_image, offset_in_dips,
drag_obj_rect_in_dips, possible_drag_event_info_.Clone());
}
Expand Down
Loading

0 comments on commit 1427674

Please sign in to comment.