High firefox Memory Corruption 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionMemory safety bugs present in Firefox 140 and Thunderbird 140. Some of these bugs showed evidence of memory corruption and we presume that with enough effort some of these could have been exploited to run arbitrary code.
ComponentDOM
Bug ClassMemory Corruption
Tracker1933572
Fix commit9d4537de2e3f (firefox) +98/-39
CISA KEVNot listed
CreditedAkmat Suleimanov, Andrew McCreight
Disclosed2025-07-22

Changed Functions

FunctionChangeNotes
if
dom/canvas/CanvasRenderingContext2D.cpp
modified
ErrorResult
dom/canvas/CanvasRenderingContextHelper.h
modified
SurfaceDescriptor
dom/canvas/CanvasRenderingContextHelper.h
modified
BlobCallback
dom/canvas/CanvasRenderingContextHelper.h
modified
if
gfx/2d/RecordedEventImpl.h
modified

Files Changed

  • dom/canvas/CanvasRenderingContext2D.cpp
  • dom/canvas/CanvasRenderingContextHelper.h
  • gfx/2d/RecordedEventImpl.h
  • gfx/2d/RecordingTypes.h
  • gfx/gl/GLBlitHelper.cpp
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index f8eee7a9617..b177937ab39 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5500,54 +5500,71 @@ static Matrix ComputeRotationMatrix(gfxFloat aRotatedWidth,
       .PostTranslate(shiftLeftTopToOrigin);
 }
 
-static Maybe<layers::SurfaceDescriptor>
-MaybeGetSurfaceDescriptorForRemoteCanvas(
-    const SurfaceFromElementResult& aResult) {
-  if (!StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path()) {
+// -
+
+Maybe<layers::SurfaceDescriptor> ValidSurfaceDescriptorForRemoteCanvas2d(
+    const layers::SurfaceDescriptor& sdConst) {
+  auto sd = sdConst;  // Copy, so we can mutate it.
+  if (sd.type() != layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) {
     return Nothing();
   }
 
-  if (!aResult.mLayersImage) {
+  auto& sdv = sd.get_SurfaceDescriptorGPUVideo();
+  if (sdv.type() !=
+      layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder) {
     return Nothing();
   }
+  auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder();
+  auto& subdesc = sdrd.subdesc();
+  switch (subdesc.type()) {
+    case layers::RemoteDecoderVideoSubDescriptor::Tnull_t:
+      break;
+    case layers::RemoteDecoderVideoSubDescriptor::
+        TSurfaceDescriptorMacIOSurface: {
+      const auto& ssd = subdesc.get_SurfaceDescriptorMacIOSurface();
+      if (ssd.gpuFence()) {
+        return Nothing();
+      }
+      break;
+    }
+    case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10: {
+      if (!StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path_d3d()) {
+        return Nothing();
+      }
+      auto& ssd = subdesc.get_SurfaceDescriptorD3D10();
+
+      ssd.handle() =
+          nullptr;  // Not IPC-able, but it's just an optimization to have this.
+      if (auto& fenceInfo = ssd.fenceInfo()) {
+        fenceInfo->mFenceHandle = nullptr;  // Not IPC-able, but it's just an
+                                            // optimization to have this.
+      }
+
+      if (ssd.gpuProcessQueryId() && ssd.gpuProcessQueryId()->mOnlyForOverlay) {
+        return Nothing();
+      }
+      break;
+    }
+    default:
+      return Nothing();
+  }
+  return Some(sd);
+}
 
-  Maybe<layers::SurfaceDescriptor> sd;
-  sd = aResult.mLayersImage->GetDesc();
-  if (sd.isNothing() ||
-      sd.ref().type() !=
-          layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) {
+static Maybe<layers::SurfaceDescriptor>
+MaybeGetSurfaceDescriptorForRemoteCanvas(
+    const SurfaceFromElementResult& aResult) {
+  if (!StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path()) {
     return Nothing();
   }
 
-  auto& sdv = sd.ref().get_SurfaceDescriptorGPUVideo();
-  const auto& sdvType = sdv.type();
-  if (sdvType ==
-      layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder) {
-    auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder();
-    auto& subdesc = sdrd.subdesc();
-    const auto& subdescType = subdesc.type();
-    if (subdescType == layers::RemoteDecoderVideoSubDescriptor::Tnull_t) {
-      return sd;
-    }
-    if (subdescType == layers::RemoteDecoderVideoSubDescriptor::
-                           TSurfaceDescriptorMacIOSurface) {
-      return sd;
-    }
-    if (subdescType ==
-            layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10 &&
-        StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path_d3d()) {
-      auto& descD3D10 = subdesc.get_SurfaceDescriptorD3D10();
-      // Clear FileHandleWrapper, since FileHandleWrapper::mHandle could not be
-      // cross process delivered by using Shmem. Cross-process delivery of
-      // FileHandleWrapper::mHandle is not possible simply by using shmen. When
-      // it is tried, parent side process just causes crash during destroying
-      // FileHandleWrapper.
-      descD3D10.handle() = nullptr;
-      return sd;
-    }
+  if (!aResult.mLayersImage) {
+    return Nothing();
   }
 
-  return Nothing();
+  const auto sd = aResult.mLayersImage->GetDesc();
+  if (!sd) return Nothing();
+  return ValidSurfaceDescriptorForRemoteCanvas2d(*sd);
 }
 
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
diff --git a/dom/canvas/CanvasRenderingContextHelper.h b/dom/canvas/CanvasRenderingContextHelper.h
index 77146d2431a..68c1212c76e 100644
--- a/dom/canvas/CanvasRenderingContextHelper.h
+++ b/dom/canvas/CanvasRenderingContextHelper.h
@@ -19,6 +19,10 @@ namespace mozilla {
 
 class ErrorResult;
 
+namespace layers {
+class SurfaceDescriptor;
+}  // namespace layers
+
 namespace dom {
 
 class BlobCallback;
@@ -89,6 +93,9 @@ class CanvasRenderingContextHelper {
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
 };
 
+Maybe<layers::SurfaceDescriptor> ValidSurfaceDescriptorForRemoteCanvas2d(
+    const layers::SurfaceDescriptor&);
+
 }  // namespace dom
 namespace CanvasUtils {
 bool GetCanvasContextType(const nsAString&, dom::CanvasContextType* const);
diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h
index 8c898089bdf..032edcc8541 100644
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -17,6 +17,9 @@
 #include "ScaledFontBase.h"
 #include "SFNTData.h"
 
+#include "mozilla/dom/CanvasRenderingContextHelper.h"
+#include "mozilla/IntegerRange.h"
+#include "mozilla/layers/BuildConstants.h"
 #include "mozilla/layers/LayersSurfaces.h"
 
 namespace mozilla {
@@ -3247,6 +3250,35 @@ inline bool RecordedDrawSurfaceDescriptor::PlayEvent(
   return true;
 }
 
+template <class S>
+struct ElementStreamFormat<S, layers::SurfaceDescriptor> {
+  using T = layers::SurfaceDescriptor;
+
+  static void Write(S& s, const T& t) {
+    // More rigorous version is coming soon! -Kelsey
+    const auto valid = dom::ValidSurfaceDescriptorForRemoteCanvas2d(t);
+    MOZ_RELEASE_ASSERT(valid && *valid == t);
+    if (kIsDebug) {
+      // We better be able to memcpy and destroy this if we're going to send it
+      // over IPC!
+      constexpr int A_COUPLE_TIMES = 3;
+      for (const auto i : IntegerRange(A_COUPLE_TIMES)) {
+        (void)i;
+        auto copy = T{};
+        memcpy(&copy, &t, sizeof(T));
+      }
+    }
+    const auto& tValid = *valid;
+    s.write(reinterpret_cast<const char*>(&tValid), sizeof(T));
+  }
+  static void Read(S& s, T& t) {
+    s.read(reinterpret_cast<char*>(&t), sizeof(T));
+    const auto valid = dom::ValidSurfaceDescriptorForRemoteCanvas2d(t);
+    MOZ_RELEASE_ASSERT(valid && *valid == t);
+    t = *valid;
+  }
+};
+
 template <class S>
 void RecordedDrawSurfaceDescriptor::Record(S& aStream) const {
   WriteElement(aStream, mDesc);
diff --git a/gfx/2d/RecordingTypes.h b/gfx/2d/RecordingTypes.h
index fa7f0153e2e..d80f7e6b4be 100644
--- a/gfx/2d/RecordingTypes.h
+++ b/gfx/2d/RecordingTypes.h
@@ -7,7 +7,7 @@
 #ifndef MOZILLA_GFX_RECORDINGTYPES_H_
 #define MOZILLA_GFX_RECORDINGTYPES_H_
 
-#include <ostream>
+#include <type_traits>
 #include <vector>
 
Loading diff…