High firefox Memory Corruption 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionInternally found bugs present in Firefox ESR 115.38, Firefox ESR 140.13, Firefox ESR 153.0 and Firefox 153. Some of these bugs showed evidence of memory corruption or another security-relevant defect and we presume that with enough effort some of these could have been exploited.
ComponentDOM
Bug ClassMemory Corruption
Tracker2045774
Fix commitba3797fd94e3 (firefox) +22/-15
CISA KEVNot listed
CreditedChristian Holler, Jan de Mooij, Tom Ritter and the Mozilla Fuzzing Team
Disclosed2026-08-18

Changed Functions

FunctionChangeNotes
if
dom/media/webm/WebMDemuxer.cpp
modified
if
gfx/layers/ImageContainer.cpp
modified

Files Changed

  • dom/media/MediaData.cpp
  • dom/media/webm/WebMDemuxer.cpp
  • gfx/layers/ImageContainer.cpp
diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp
index 85a6b1ca0fa..040da354eb6 100644
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -229,9 +229,10 @@ static MediaResult ValidateBufferAndPicture(
   }
   // Ensure the picture size specified in the headers can be extracted out of
   // the frame we've been supplied without indexing out of bounds.
+  // The picture extent and the plane width are both measured in samples.
   CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
   CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
-  if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
+  if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mWidth ||
       !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight) {
     // The specified picture dimensions can't be contained inside the video
     // frame, we'll stomp memory if we try to copy it. Fail.
diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp
index 3bf19b09cde..dfa3a39a28f 100644
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -527,19 +527,19 @@ nsresult WebMDemuxer::ReadMetadata() {
       mInfo.mVideo.mHDRMetadata = ParseWebMMasteringMetadata(params);
 
       // Picture region, taking into account cropping, before scaling
-      // to the display size.
-      unsigned int cropH = params.crop_right + params.crop_left;
-      unsigned int cropV = params.crop_bottom + params.crop_top;
-      gfx::IntRect pictureRect(params.crop_left, params.crop_top,
-                               params.width - cropH, params.height - cropV);
-
-      // If the cropping data appears invalid then use the frame data
-      if (pictureRect.width <= 0 || pictureRect.height <= 0 ||
-          pictureRect.x < 0 || pictureRect.y < 0) {
-        pictureRect.x = 0;
-        pictureRect.y = 0;
-        pictureRect.width = params.width;
-        pictureRect.height = params.height;
+      // to the display size. Default to the full frame and apply cropping only
+      // when it leaves a non-empty region within the frame.
+      gfx::IntRect pictureRect(0, 0, AssertedCast<int32_t>(params.width),
+                               AssertedCast<int32_t>(params.height));
+      uint64_t cropH =
+          static_cast<uint64_t>(params.crop_left) + params.crop_right;
+      uint64_t cropV =
+          static_cast<uint64_t>(params.crop_top) + params.crop_bottom;
+      if (cropH < params.width && cropV < params.height) {
+        pictureRect.x = AssertedCast<int32_t>(params.crop_left);
+        pictureRect.y = AssertedCast<int32_t>(params.crop_top);
+        pictureRect.width = AssertedCast<int32_t>(params.width - cropH);
+        pictureRect.height = AssertedCast<int32_t>(params.height - cropV);
       }
 
       // Validate the container-reported frame and pictureRect sizes. This
diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp
index 5cab470b982..901ced77a29 100644
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -894,7 +894,13 @@ static void CopyPlane(uint8_t* aDst, const uint8_t* aSrc,
   int32_t width = aSize.width;
   const int32_t rowBytes = width * aBytesPerElement;
 
-  MOZ_RELEASE_ASSERT(rowBytes <= aStride);
+  // The interleaved (aSkip != 0) path steps over skipped elements between
+  // pixels, so a row reaches further than the packed width. Computed with
+  // 64-bit arithmetic.
+  const int64_t srcRowSpan =
+      (static_cast<int64_t>(width) + static_cast<int64_t>(width - 1) * aSkip) *
+      aBytesPerElement;
+  MOZ_RELEASE_ASSERT(srcRowSpan <= aStride);
 
   if (!aSkip) {
     // Fast path: planar input.
Loading diff…