Medium firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionIncorrect boundary conditions in the Graphics: WebGPU component
ComponentDOM
Bug ClassLogic Error
Tracker2045410
Fix commit94b01edf180a (firefox) +52/-25
CISA KEVNot listed
CreditedAtsushi Sada
Disclosed2026-07-21

Changed Functions

FunctionChangeNotes
for
dom/webgpu/SharedTextureD3D11.cpp
modified
if
dom/webgpu/SharedTextureD3D11.cpp
modified
for
dom/webgpu/SharedTextureDMABuf.cpp
modified
if
dom/webgpu/SharedTextureDMABuf.cpp
modified
for
dom/webgpu/SharedTextureMacIOSurface.cpp
modified
if
dom/webgpu/SharedTextureMacIOSurface.cpp
modified
for
dom/webgpu/ipc/WebGPUParent.cpp
modified
if
dom/webgpu/ipc/WebGPUParent.cpp
modified
for
gfx/layers/RemoteTextureMap.cpp
modified
if
gfx/layers/RemoteTextureMap.cpp
modified

Files Changed

  • dom/webgpu/SharedTextureD3D11.cpp
  • dom/webgpu/SharedTextureDMABuf.cpp
  • dom/webgpu/SharedTextureMacIOSurface.cpp
  • dom/webgpu/ipc/WebGPUParent.cpp
  • gfx/layers/RemoteTextureMap.cpp
diff --git a/dom/webgpu/SharedTextureD3D11.cpp b/dom/webgpu/SharedTextureD3D11.cpp
index e5d27e77898..87619a1c747 100644
--- a/dom/webgpu/SharedTextureD3D11.cpp
+++ b/dom/webgpu/SharedTextureD3D11.cpp
@@ -206,11 +206,15 @@ void SharedTextureD3D11::GetSnapshot(const ipc::Shmem& aDestShmem,
   uint8_t* dst = aDestShmem.get<uint8_t>();
 
   const size_t src_stride = static_cast<size_t>(map.RowPitch);
-  // note that this might still copy some padding bytes
-  const size_t min_stride = std::min(src_stride, aDestStride);
+  const size_t bytesPerRow = static_cast<size_t>(mWidth) * 4;
+  MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+  MOZ_RELEASE_ASSERT(aDestStride >= bytesPerRow);
 
   for (uint32_t y = 0; y < mHeight; y++) {
-    memcpy(dst, src, min_stride);
+    memcpy(dst, src, bytesPerRow);
+    if (bytesPerRow < aDestStride) {
+      memset(dst + bytesPerRow, 0, aDestStride - bytesPerRow);
+    }
     src += src_stride;
     dst += aDestStride;
   }
diff --git a/dom/webgpu/SharedTextureDMABuf.cpp b/dom/webgpu/SharedTextureDMABuf.cpp
index bdd1c84886c..7ce3c967808 100644
--- a/dom/webgpu/SharedTextureDMABuf.cpp
+++ b/dom/webgpu/SharedTextureDMABuf.cpp
@@ -146,11 +146,15 @@ void SharedTextureDMABuf::GetSnapshot(const ipc::Shmem& aDestShmem,
   uint8_t* dst = aDestShmem.get<uint8_t>();
 
   const size_t src_stride = static_cast<size_t>(map.GetStride());
-  // note that this might still copy some padding bytes
-  const size_t min_stride = std::min(src_stride, aDestStride);
+  const size_t bytesPerRow = static_cast<size_t>(mWidth) * 4;
+  MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+  MOZ_RELEASE_ASSERT(aDestStride >= bytesPerRow);
 
   for (uint32_t y = 0; y < mHeight; y++) {
-    memcpy(dst, src, min_stride);
+    memcpy(dst, src, bytesPerRow);
+    if (bytesPerRow < aDestStride) {
+      memset(dst + bytesPerRow, 0, aDestStride - bytesPerRow);
+    }
     src += src_stride;
     dst += aDestStride;
   }
diff --git a/dom/webgpu/SharedTextureMacIOSurface.cpp b/dom/webgpu/SharedTextureMacIOSurface.cpp
index 1dd14953558..874449a0f94 100644
--- a/dom/webgpu/SharedTextureMacIOSurface.cpp
+++ b/dom/webgpu/SharedTextureMacIOSurface.cpp
@@ -85,16 +85,20 @@ void SharedTextureMacIOSurface::GetSnapshot(const ipc::Shmem& aDestShmem,
     return;
   }
 
-  const size_t bytesPerRow = mSurface->GetBytesPerRow();
+  const size_t src_stride = mSurface->GetBytesPerRow();
   uint8_t* src = (uint8_t*)mSurface->GetBaseAddress();
   uint8_t* dst = aDestShmem.get<uint8_t>();
 
-  // note that this might still copy some padding bytes
-  const size_t min_stride = std::min(bytesPerRow, aDestStride);
+  const size_t bytesPerRow = static_cast<size_t>(mWidth) * 4;
+  MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+  MOZ_RELEASE_ASSERT(aDestStride >= bytesPerRow);
 
   for (uint32_t y = 0; y < mHeight; y++) {
-    memcpy(dst, src, min_stride);
-    src += bytesPerRow;
+    memcpy(dst, src, bytesPerRow);
+    if (bytesPerRow < aDestStride) {
+      memset(dst + bytesPerRow, 0, aDestStride - bytesPerRow);
+    }
+    src += src_stride;
     dst += aDestStride;
   }
 
diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp
index 556757ee03b..660ef6a6949 100644
--- a/dom/webgpu/ipc/WebGPUParent.cpp
+++ b/dom/webgpu/ipc/WebGPUParent.cpp
@@ -1078,19 +1078,25 @@ static void ReadbackPresentCallback(uint8_t* userdata,
       uint8_t* src = mapped.ptr;
       uint8_t* dst = mappedData.data;
 
-      const uint32_t dst_stride = mappedData.stride;
+      const size_t dst_stride = static_cast<size_t>(mappedData.stride);
       // `mappedData.stride` is computed via
       // `ImageDataSerializer::ComputeRGBStride` and returns 0 if it overflows
       MOZ_RELEASE_ASSERT(dst_stride != 0);
 
-      // note that this might still copy some padding bytes
-      const uint32_t min_stride = std::min(data->mBufferStride, dst_stride);
+      const size_t src_stride = static_cast<size_t>(data->mBufferStride);
+      const size_t bytesPerRow =
+          static_cast<size_t>(data->mDesc.size().width) * 4;
+      MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+      MOZ_RELEASE_ASSERT(dst_stride >= bytesPerRow);
 
       // The height is in bounds for both buffers since we just requested a new
       // destination buffer with the same height of the source.
       for (auto row = 0; row < size.height; ++row) {
-        memcpy(dst, src, min_stride);
-        src += data->mBufferStride;
+        memcpy(dst, src, bytesPerRow);
+        if (bytesPerRow < dst_stride) {
+          memset(dst + bytesPerRow, 0, dst_stride - bytesPerRow);
+        }
+        src += src_stride;
         dst += dst_stride;
       }
       req->mRemoteTextureOwner->PushTexture(req->mTextureId, req->mOwnerId,
@@ -1176,13 +1182,17 @@ static void ReadbackSnapshotCallback(uint8_t* userdata,
   uint8_t* dst = req->mDestShmem.get<uint8_t>();
 
   const size_t src_stride = static_cast<size_t>(data->mBufferStride);
-  // note that this might still copy some padding bytes
-  const size_t min_stride = std::min(src_stride, req->mDestStride);
+  const size_t bytesPerRow = static_cast<size_t>(data->mDesc.size().width) * 4;
+  MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+  MOZ_RELEASE_ASSERT(req->mDestStride >= bytesPerRow);
 
   // The height is in bounds for both buffers since we previously created a new
   // destination buffer with the same height of the source.
   for (auto row = 0; row < data->mDesc.size().height; ++row) {
-    memcpy(dst, src, min_stride);
+    memcpy(dst, src, bytesPerRow);
+    if (bytesPerRow < req->mDestStride) {
+      memset(dst + bytesPerRow, 0, req->mDestStride - bytesPerRow);
+    }
     src += src_stride;
     dst += req->mDestStride;
   }
diff --git a/gfx/layers/RemoteTextureMap.cpp b/gfx/layers/RemoteTextureMap.cpp
index 3635a685505..ae65668d34f 100644
--- a/gfx/layers/RemoteTextureMap.cpp
+++ b/gfx/layers/RemoteTextureMap.cpp
@@ -557,15 +557,20 @@ void RemoteTextureMap::GetLatestBufferSnapshot(
     uint8_t* src = bufferTextureHost->GetBuffer();
     uint8_t* dst = aDestShmem.get<uint8_t>();
 
-    const Maybe<int32_t> src_stride = ImageDataSerializer::GetRGBStride(
+    const Maybe<int32_t> maybe_src_stride = ImageDataSerializer::GetRGBStride(
         bufferTextureHost->GetBufferDescriptor());
-    MOZ_RELEASE_ASSERT(src_stride.isSome());
-    // note that this might still copy some padding bytes
-    const size_t min_stride = std::min(size_t(src_stride.value()), aDestStride);
+    MOZ_RELEASE_ASSERT(maybe_src_stride.isSome());
+    const size_t src_stride = static_cast<size_t>(maybe_src_stride.value());
+    const size_t bytesPerRow = static_cast<size_t>(src_size.width) * 4;
+    MOZ_RELEASE_ASSERT(src_stride >= bytesPerRow);
+    MOZ_RELEASE_ASSERT(aDestStride >= bytesPerRow);
 
     for (int y = 0; y < src_size.height; y++) {
-      memcpy(dst, src, min_stride);
-      src += src_stride.value();
+      memcpy(dst, src, bytesPerRow);
+      if (bytesPerRow < aDestStride) {
+        memset(dst + bytesPerRow, 0, aDestStride - bytesPerRow);
+      }
+      src += src_stride;
       dst += aDestStride;
     }
   }
Loading diff…