High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionPrivilege escalation in the Graphics: WebRender component
ComponentGraphics
Bug ClassLogic Error
Tracker2023443
Fix commit0517b85e48a4 (firefox) +62/-2
CISA KEVNot listed
Creditedchoeseyeong
Disclosed2026-06-16

Changed Functions

FunctionChangeNotes
if
gfx/layers/ipc/ImageBridgeParent.cpp
modified

Files Changed

  • gfx/layers/ipc/CompositorBridgeParent.cpp
  • gfx/layers/ipc/CompositorBridgeParent.h
  • gfx/layers/ipc/CompositorManagerParent.h
  • gfx/layers/ipc/ContentCompositorBridgeParent.cpp
  • gfx/layers/ipc/ImageBridgeParent.cpp
  • gfx/layers/ipc/ImageBridgeParent.h
  • gfx/layers/wr/WebRenderBridgeParent.cpp
  • gfx/layers/wr/WebRenderBridgeParent.h
diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp
index 2afe2cb373c..bdb031b8854 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -149,6 +149,13 @@ bool CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem) {
   return PCompositorBridgeParent::DeallocShmem(aShmem);
 }
 
+bool CompositorBridgeParentBase::OwnsExternalImageId(
+    const wr::ExternalImageId& aId) const {
+  return mCompositorManager &&
+         (static_cast<uint32_t>(wr::AsUint64(aId) >> 32) ==
+          mCompositorManager->GetNamespace());
+}
+
 CompositorBridgeParent::LayerTreeState::LayerTreeState()
     : mApzcTreeManagerParent(nullptr),
       mApzInputBridgeParent(nullptr),
diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h
index 00f46b06f5b..0530c9e8eba 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -153,6 +153,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
   // from the Compositor thread.
   virtual void EnsureWebRenderBridgeParentInitialized() = 0;
 
+  bool OwnsExternalImageId(const wr::ExternalImageId& aId) const;
+
  protected:
   virtual ~CompositorBridgeParentBase();
 
diff --git a/gfx/layers/ipc/CompositorManagerParent.h b/gfx/layers/ipc/CompositorManagerParent.h
index ea5f0198ff9..c1a1210088a 100644
--- a/gfx/layers/ipc/CompositorManagerParent.h
+++ b/gfx/layers/ipc/CompositorManagerParent.h
@@ -78,6 +78,8 @@ class CompositorManagerParent final : public PCompositorManagerParent {
     return mNamespace == static_cast<uint32_t>(wr::AsUint64(aId) >> 32);
   }
 
+  uint32_t GetNamespace() const { return mNamespace; }
+
  private:
   static StaticMonitor sMonitor;
   static StaticRefPtr<CompositorManagerParent> sInstance
diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
index f806b1ccf93..bf23dea49cb 100644
--- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
@@ -423,6 +423,12 @@ PTextureParent* ContentCompositorBridgeParent::AllocPTextureParent(
     const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
     const LayersId& aId, const uint64_t& aSerial,
     const wr::MaybeExternalImageId& aExternalImageId) {
+  if (aExternalImageId.isSome() &&
+      !OwnsExternalImageId(aExternalImageId.ref())) {
+    NS_ERROR("We do not own this external image id.");
+    return nullptr;
+  }
+
   CompositorBridgeParent::LayerTreeState* state = nullptr;
 
   StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp
index 1926260319b..2dcf9b6bc2b 100644
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -317,8 +317,9 @@ PTextureParent* ImageBridgeParent::AllocPTextureParent(
     const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
     const uint64_t& aSerial, const wr::MaybeExternalImageId& aExternalImageId) {
   if (aExternalImageId.isSome()) {
-    uint32_t ns = static_cast<uint32_t>(wr::AsUint64(*aExternalImageId) >> 32);
-    if (ns == 0) {
+    if (aExternalImageId.isSome() &&
+        !OwnsExternalImageId(aExternalImageId.ref())) {
+      NS_ERROR("We do not own this external image id.");
       return nullptr;
     }
   }
@@ -408,6 +409,12 @@ already_AddRefed<ImageBridgeParent> ImageBridgeParent::GetInstance(
   return bridge.forget();
 }
 
+bool ImageBridgeParent::OwnsExternalImageId(
+    const wr::ExternalImageId& aId) const {
+  return (static_cast<uint32_t>(wr::AsUint64(aId) >> 32) ==
+          static_cast<uint32_t>(static_cast<uint64_t>(mContentId) >> 32));
+}
+
 bool ImageBridgeParent::AllocShmem(size_t aSize, ipc::Shmem* aShmem) {
   if (mClosed) {
     return false;
diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h
index 672a8efa0e3..f300f8edce6 100644
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -126,6 +126,9 @@ class ImageBridgeParent final : public PImageBridgeParent,
   static void ShutdownInternal();
 
   void DeferredDestroy();
+
+  bool OwnsExternalImageId(const wr::ExternalImageId& aId) const;
+
   nsCOMPtr<nsISerialEventTarget> mThread;
 
   dom::ContentParentId mContentId;
diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp
index ef4b5b085da..adcf06a7266 100644
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -884,6 +884,11 @@ bool WebRenderBridgeParent::AddSharedExternalImage(
     return true;
   }
 
+  if (!GetCompositorBridge()->OwnsExternalImageId(aExtId)) {
+    gfxCriticalNote << "We do not own extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
+
   auto key = wr::AsUint64(aKey);
   auto it = mSharedSurfaceIds.find(key);
   if (it != mSharedSurfaceIds.end()) {
@@ -1660,6 +1665,12 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
       case WebRenderParentCommand::TOpAddPipelineIdForCompositable: {
         const OpAddPipelineIdForCompositable& op =
             cmd.get_OpAddPipelineIdForCompositable();
+        if (wr::AsUint64(op.pipelineId()) >> 32 !=
+            mLateInit->mIdNamespace.mHandle) {
+          success = false;
+          continue;
+        }
+
         AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.owner(),
                                      aTxn, txnForImageBridge);
         break;
@@ -1667,6 +1678,12 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
       case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
         const OpRemovePipelineIdForCompositable& op =
             cmd.get_OpRemovePipelineIdForCompositable();
+        if (wr::AsUint64(op.pipelineId()) >> 32 !=
+            mLateInit->mIdNamespace.mHandle) {
+          success = false;
+          continue;
+        }
+
         auto* pendingOps =
             mLateInit->mApi->GetPendingAsyncImagePipelineOps(aTxn);
 
@@ -1681,6 +1698,11 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
       case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
         const OpUpdateAsyncImagePipeline& op =
             cmd.get_OpUpdateAsyncImagePipeline();
+        if (wr::AsUint64(op.pipelineId()) >> 32 !=
+            mLateInit->mIdNamespace.mHandle) {
+          success = false;
+          continue;
+        }
 
         auto* pendingOps =
             mLateInit->mApi->GetPendingAsyncImagePipelineOps(aTxn);
@@ -1699,6 +1721,12 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
       case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
         const OpUpdatedAsyncImagePipeline& op =
             cmd.get_OpUpdatedAsyncImagePipeline();
+        if (wr::AsUint64(op.pipelineId()) >> 32 !=
+            mLateInit->mIdNamespace.mHandle) {
+          success = false;
+          continue;
+        }
+
         aTxn.InvalidateRenderedFrame(wr::RenderReasons::ASYNC_IMAGE);
 
         auto* pendingOps =
diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h
index 698943773a0..babfe604ae9 100644
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -260,6 +260,11 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
     return aFontKey.mNamespace == mLateInit->mIdNamespace;
   }
 
+  bool OwnsExternalImageId(const wr::ExternalImageId& aId) const {
+    return static_cast<uint32_t>(wr::AsUint64(aId) >> 32) ==
+           mLateInit->mIdNamespace.mHandle;
+  }
+
   void FlushRendering(wr::RenderReasons aReasons, bool aBlocking);
 
   /**
Loading diff…