High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionSandbox escape in the DOM: Core & HTML component
ComponentDOM
Bug ClassLogic Error
Tracker2064287
Fix commitf94dc29b1565 (firefox) +68/-10
CISA KEVNot listed
CreditedQuy Pham
Disclosed2026-09-15

Changed Functions

FunctionChangeNotes
if
dom/events/EventStateManager.cpp
modified
if
dom/ipc/BrowserParent.cpp
modified
UserCancelled
widget/nsBaseDragService.cpp
modified

Files Changed

  • dom/base/PointerLockManager.cpp
  • dom/events/EventStateManager.cpp
  • dom/events/EventStateManager.h
  • dom/ipc/BrowserParent.cpp
  • widget/nsBaseDragService.cpp
  • widget/nsIDragService.idl
diff --git a/dom/base/PointerLockManager.cpp b/dom/base/PointerLockManager.cpp
index 288361efd55..4f1e1b98311 100644
--- a/dom/base/PointerLockManager.cpp
+++ b/dom/base/PointerLockManager.cpp
@@ -510,6 +510,12 @@ void PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent,
     return;
   }
 
+  if (nsCOMPtr<nsIDragService> dragService =
+          do_GetService("@mozilla.org/widget/dragservice;1")) {
+    dragService->Suppress();
+  }
+  presContext->EventStateManager()->StopTrackingDragGesture(true);
+
   MOZ_POINTERLOCK_LOG("Set locked remote target to 0x%p", aBrowserParent);
   sLockedRemoteTarget = aBrowserParent;
   PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
@@ -539,6 +545,11 @@ void PointerLockManager::ReleaseLockedRemoteTarget(
 
     nsCOMPtr<nsIWidget> widget = aBrowserParent->GetTopLevelWidget();
     EventStateManager::ReleaseLockedPointer(widget);
+
+    if (nsCOMPtr<nsIDragService> dragService =
+            do_GetService("@mozilla.org/widget/dragservice;1")) {
+      dragService->Unsuppress();
+    }
   }
 }
 
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 3ef7a8a883b..881b2b41408 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2636,6 +2636,8 @@ void EventStateManager::BeginTrackingDragGesture(
     if (!mGestureDownFrameOwner) {
       mGestureDownFrameOwner = mGestureDownContent;
     }
+    mGestureDownTopLevelRemoteTarget =
+        BrowserParent::GetFrom(mGestureDownContent);
   }
   mGestureModifiers = aMouseDownOrTouchDragEvent.mModifiers;
   mGestureDownButtons = aMouseDownOrTouchDragEvent.mButtons;
@@ -2687,6 +2689,8 @@ void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
     return;
   }
 
+  mGestureDownTopLevelRemoteTarget = nullptr;
+
   // Only notify if there is NOT a drag session active in the parent.
   RefPtr<nsIDragSession> dragSession =
       nsContentUtils::GetDragSession(mPresContext);
@@ -7990,6 +7994,7 @@ bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
 void EventStateManager::UpdateGestureContent(nsIContent* aContent) {
   mGestureDownContent = aContent;
   mGestureDownFrameOwner = aContent;
+  mGestureDownTopLevelRemoteTarget = BrowserParent::GetFrom(aContent);
 }
 
 void EventStateManager::NotifyContentWillBeRemovedForGesture(
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index e9963a401d2..af59f10e4a7 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -561,6 +561,10 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
     return mGestureDownContent;
   }
 
+  dom::BrowserParent* GetTrackingDragGestureTopLevelRemoteTarget() const {
+    return mGestureDownTopLevelRemoteTarget;
+  }
+
   // Update the tracked gesture content to the parent of its frame when it's
   // removed, so that the gesture can be continued.
   void NotifyContentWillBeRemovedForGesture(nsIContent& aContent);
@@ -1446,6 +1450,7 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
   // as the target in most cases but not always - for example when dragging
   // an <area> of an image map this is the image. (bug 289667)
   nsCOMPtr<nsIContent> mGestureDownFrameOwner;
+  RefPtr<dom::BrowserParent> mGestureDownTopLevelRemoteTarget;
   // Data associated with a drag started in a content process.
   RefPtr<dom::RemoteDragStartData> mGestureDownDragStartData;
   // State of keys when the original gesture-down happened
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
index 924bee2a2c5..d640d0f2653 100644
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -1060,6 +1060,20 @@ mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
   NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());
 
+  if (nsCOMPtr<nsIDragService> dragService =
+          do_GetService("@mozilla.org/widget/dragservice;1")) {
+    RefPtr<nsIWidget> widget = GetTopLevelWidget();
+    if (RefPtr<nsIDragSession> session =
+            dragService->GetCurrentSession(widget)) {
+      session->EndDragSession(false, 0);
+    }
+  }
+
+  if (nsPresContext* presContext =
+          mFrameElement->OwnerDoc()->GetPresContext()) {
+    presContext->EventStateManager()->StopTrackingDragGesture(true);
+  }
+
   // `BrowserChild` only sends the values to actually be changed, see more
   // details in `BrowserChild::SetDimensions()`.
   // Note that `BrowserChild::SetDimensions()` may be called before receiving
@@ -3883,8 +3897,29 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
     const CookieJarSettingsArgs& aCookieJarSettingsArgs,
     const MaybeDiscarded<WindowContext>& aSourceWindowContext,
     const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
-  PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
-  if (!presShell) {
+  nsCOMPtr<nsIDragService> dragService =
+      do_GetService("@mozilla.org/widget/dragservice;1");
+  nsPresContext* presContext = mFrameElement->OwnerDoc()->GetPresContext();
+  const bool isValidRemoteDrag = [&]() {
+    if (!dragService || !presContext) {
+      return false;
+    }
+
+    if (dragService->GetIsSuppressed()) {
+      return false;
+    }
+
+    BrowserParent* dragTopLevelRemoteTarget =
+        presContext->EventStateManager()
+            ->GetTrackingDragGestureTopLevelRemoteTarget();
+    if (NS_WARN_IF(dragTopLevelRemoteTarget != TopLevelBrowserParent())) {
+      return false;
+    }
+
+    return true;
+  }();
+
+  if (!isValidRemoteDrag) {
     (void)SendEndDragSession(true, true, LayoutDeviceIntPoint(), 0,
                              nsIDragService::DRAGDROP_ACTION_NONE);
     // Continue sending input events with input priority when stopping the dnd
@@ -3922,15 +3957,10 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
     }
   }
 
-  nsCOMPtr<nsIDragService> dragService =
-      do_GetService("@mozilla.org/widget/dragservice;1");
-  if (dragService) {
-    dragService->MaybeAddBrowser(this);
-  }
+  dragService->MaybeAddBrowser(this);
 
-  presShell->GetPresContext()
-      ->EventStateManager()
-      ->BeginTrackingRemoteDragGesture(mFrameElement, dragStartData);
+  presContext->EventStateManager()->BeginTrackingRemoteDragGesture(
+      mFrameElement, dragStartData);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   os->NotifyObservers(nullptr, "content-invoked-drag", nullptr);
diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp
index a67b8af9975..68cbacea55a 100644
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -1169,6 +1169,8 @@ nsBaseDragService::Unsuppress() {
   return NS_OK;
 }
 
+bool nsBaseDragService::GetIsSuppressed() { return mSuppressLevel > 0; }
+
 NS_IMETHODIMP
 nsBaseDragSession::UserCancelled() {
   mUserCancelled = true;
diff --git a/widget/nsIDragService.idl b/widget/nsIDragService.idl
index 5ef0fa0e6aa..8ebc5a3b8af 100644
--- a/widget/nsIDragService.idl
+++ b/widget/nsIDragService.idl
@@ -172,6 +172,11 @@ interface nsIDragService : nsISupports
   void suppress();
   void unsuppress();
 
+  /**
+   * True if the dragging is disabled.
+   */
+  [notxpcom, nostdcall] readonly attribute boolean isSuppressed;
+
   [notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP);
   [notxpcom, nostdcall] boolean removeAllBrowsers();
 
Loading diff…