Moderate firefox Logic Error 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionPrivilege escalation in the Panning and Zooming component
ComponentGraphics
Bug ClassLogic Error
Tracker2059195
Fix commit440bc0a800c2 (firefox) +40/-10
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
if
gfx/layers/wr/WebRenderBridgeParent.cpp
modified
mPaintSequenceNumber
gfx/layers/wr/WebRenderScrollData.cpp
modified

Files Changed

  • gfx/layers/wr/WebRenderBridgeParent.cpp
  • gfx/layers/wr/WebRenderScrollData.cpp
  • gfx/layers/wr/WebRenderScrollData.h
diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp
index 58842a96f2d..7ed9c9014b1 100644
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1352,6 +1352,33 @@ bool WebRenderBridgeParent::SetDisplayList(
   return success;
 }
 
+// True if every referent id in aScrollData is actually embedded by
+// aOwnLayersId, per the parent process's own record of the frame tree.
+static bool ReferentsAreOwnedBy(const WebRenderScrollData& aScrollData,
+                                LayersId aOwnLayersId) {
+  for (size_t i = 0; i < aScrollData.GetLayerCount(); i++) {
+    Maybe<LayersId> referent = aScrollData.GetLayerData(i)->GetReferentId();
+    if (!referent) {
+      continue;
+    }
+    LayersId embedder;
+    bool found = CompositorBridgeParent::CallWithLayerTreeState(
+        *referent, [&](CompositorBridgeParent::LayerTreeState& aState) {
+          embedder = aState.mEmbedderLayersId;
+        });
+    if (!found || embedder != aOwnLayersId) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool ValidateScrollData(const WebRenderScrollData& aScrollData,
+                               LayersId aOwnLayersId) {
+  return aScrollData.ValidateShape() &&
+         ReferentsAreOwnedBy(aScrollData, aOwnLayersId);
+}
+
 bool WebRenderBridgeParent::ProcessDisplayListData(
     DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
     const TimeStamp& aTxnStartTime, bool aValidTransaction,
@@ -1360,13 +1387,16 @@ bool WebRenderBridgeParent::ProcessDisplayListData(
                              mRemoteTextureTxnScheduler, mFwdTransactionId);
   Maybe<wr::AutoTransactionSender> sender;
 
-  if (aDisplayList.mScrollData && !aDisplayList.mScrollData->Validate()) {
-    // If the scroll data is invalid, the entire transaction needs to be dropped
-    // because the scroll data and the display list cross-reference each other.
-    MOZ_ASSERT(
-        false,
-        "Content sent malformed scroll data (or validation check has a bug)");
-    aValidTransaction = false;
+  if (aDisplayList.mScrollData) {
+    // If the scroll data is invalid, the entire transaction needs to be
+    // dropped because the scroll data and the display list cross-reference
+    // each other.
+    if (!ValidateScrollData(*aDisplayList.mScrollData, GetLayersId())) {
+      MOZ_ASSERT(false,
+                 "Content sent malformed scroll data (or validation check "
+                 "has a bug)");
+      aValidTransaction = false;
+    }
   }
 
   if (!aValidTransaction) {
diff --git a/gfx/layers/wr/WebRenderScrollData.cpp b/gfx/layers/wr/WebRenderScrollData.cpp
index d8f2e99d0b6..ec4494fddf7 100644
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -222,7 +222,7 @@ WebRenderScrollData::WebRenderScrollData(WebRenderLayerManager* aManager,
       mIsFirstPaint(false),
       mPaintSequenceNumber(0) {}
 
-bool WebRenderScrollData::Validate() const {
+bool WebRenderScrollData::ValidateShape() const {
   // Attempt to traverse the tree structure encoded by the descendant counts,
   // validating as we go that everything is within bounds and properly nested.
   // In addition, check that the traversal visits every node exactly once.
diff --git a/gfx/layers/wr/WebRenderScrollData.h b/gfx/layers/wr/WebRenderScrollData.h
index 7bec2045315..b1f08180826 100644
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -45,7 +45,7 @@ class WebRenderLayerScrollData final {
 
   using ViewID = ScrollableLayerGuid::ViewID;
 
-  // Helper function for WebRenderScrollData::Validate().
+  // Helper function for WebRenderScrollData::ValidateShape().
   bool ValidateSubtree(const WebRenderScrollData& aParent,
                        std::vector<size_t>& aVisitCounts,
                        size_t aCurrentIndex) const;
@@ -241,7 +241,7 @@ class WebRenderScrollData {
   // Validate that the scroll data is well-formed, and particularly that
   // |mLayerScrollData| encodes a valid tree. This is necessary because
   // the data can be sent over IPC from a less-trusted content process.
-  bool Validate() const;
+  bool ValidateShape() const;
 
   WebRenderLayerManager* GetManager() const;
 
Loading diff…