Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in ANGLE
DescriptionUse after free in ANGLE
ComponentANGLE
Sub-componentVulkan
Bug ClassUAF
Tracker490808751
Fix commit97389890be65 (angle/angle) +9/-7
CISA KEVNot listed
Creditedmikey233 of HackerOne
Disclosed2026-10-20

Files Changed

  • src/libANGLE/renderer/vulkan/TextureVk.cpp
From 97389890be6546eb0e3e368bb1f6adefef6920dd Mon Sep 17 00:00:00 2001
From: Amirali Abdolrashidi <abdolrashidi@google.com>
Date: Fri, 18 Sep 2026 14:51:44 -0700
Subject: [PATCH] Vulkan: Add more casts to size calculations

* Cast some extents to size_t when multiplied by another value to be
  assigned to another size_t value.

Bug: chromium:490808751
Change-Id: I9547886d40c5efc3d65ac184c25a4e692c86282f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8430088
Auto-Submit: Amirali Abdolrashidi <abdolrashidi@google.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
---
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 6c69c7f..c6fb266 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1868,15 +1868,17 @@
                                                        stagingIndex, stagingExtents, stagingOffset,
                                                        &destData, dstFormatID));
 
-    // Source and dst data is tightly packed
-    GLuint srcDataRowPitch = sourceBox.width * srcTextureFormat.pixelBytes;
-    GLuint dstDataRowPitch = sourceBox.width * dstTextureFormat.pixelBytes;
+    // Source and destination data are tightly packed.
+    const size_t srcDataRowPitch =
+        static_cast<size_t>(sourceBox.width) * srcTextureFormat.pixelBytes;
+    const size_t dstDataRowPitch =
+        static_cast<size_t>(sourceBox.width) * dstTextureFormat.pixelBytes;
 
-    GLuint srcDataDepthPitch = srcDataRowPitch * sourceBox.height;
-    GLuint dstDataDepthPitch = dstDataRowPitch * sourceBox.height;
+    const size_t srcDataDepthPitch = srcDataRowPitch * static_cast<size_t>(sourceBox.height);
+    const size_t dstDataDepthPitch = dstDataRowPitch * static_cast<size_t>(sourceBox.height);
 
-    rx::PixelReadFunction pixelReadFunction   = srcTextureFormat.pixelReadFunction;
-    rx::PixelWriteFunction pixelWriteFunction = dstTextureFormat.pixelWriteFunction;
+    PixelReadFunction pixelReadFunction   = srcTextureFormat.pixelReadFunction;
+    PixelWriteFunction pixelWriteFunction = dstTextureFormat.pixelWriteFunction;
 
     // Fix up the read/write functions for the sake of luminance/alpha that are emulated with
     // formats whose channels don't correspond to the original format (alpha is emulated with red,
Loading diff…

Original Bug Report

reported by ri...@gmail.com

ANGLE Vulkan: readPixelsImpl 32-bit overflow in staging buffer size calculation


Report description

ANGLE Vulkan: readPixelsImpl 32-bit overflow in staging buffer size calculation


Bug location

Where do you want to report your vulnerability?

Chrome VRP – Report security issues affecting the Chrome browser. See program rules

Which URL (or repository) have you found the vulnerability in?

https://chromium.googlesource.com/angle/angle


The problem

Please describe the technical details of the vulnerability

The problem

ImageHelper::readPixelsImpl in the ANGLE Vulkan backend computes a staging buffer size using 32-bit arithmetic that overflows before widening to size_t. This is a missed instance from the CVE-2026-3536 fix (commit 56c952c, Bug: chromium:487208468).

Vulnerable code — src/libANGLE/renderer/vulkan/vk_helpers.cpp, line 11502:

size_t allocationSize = readFormat->pixelBytes * area.width * area.height;

Type analysis:

  • readFormat->pixelBytes: GLuint (32-bit unsigned)
  • area.width, area.height: int (32-bit signed)
  • The multiplication evaluates entirely in 32-bit, wrapping before assignment to size_t
  • For RGBA32F (16 bytes/pixel) at 16384×16384: 16 × 16384 × 16384 = 4,294,967,296 wraps to 0

Fixed instance in same file (commit 56c952c, line 9414):

const size_t bufferSize = static_cast<size_t>(clippedRectangle.width) *
                          static_cast<size_t>(clippedRectangle.height) *
                          storageFormat.pixelBytes;

The static_cast<size_t>() pattern was applied to stageSubresourceUpdateFromFramebuffer but not to readPixelsImpl in the same file.

Code path: Reachable via copyTexSubImage2D when both GPU transfer and GPU draw copy paths fail:

gl.copyTexSubImage2D(target, level, 0, 0, 0, 0, 16384, 16384)
  → TextureVk::copySubImageImpl()
    → [transfer copy fails: format mismatch]
    → [draw copy fails: dest lacks VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT]
    → stageSubresourceUpdateFromFramebuffer() [CPU fallback]
      → ImageHelper::readPixelsImpl()         [line 11502, OVERFLOW]

The internal readPixelsImpl call from stageSubresourceUpdateFromFramebuffer constructs its own PackPixelsParams with packBuffer = nullptr, bypassing PBO validation and always reaching the CPU Readback section containing the overflow.

Practical exploitability is low. The CPU fallback requires a destination format lacking VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT for a 16-byte-per-pixel format. All three WebGL 2 candidates (RGBA32F/UI/I) have COLOR_ATTACHMENT support on 97–99% of Vulkan devices. This is primarily a defense-in-depth fix.

Suggested fix:

size_t allocationSize = static_cast<size_t>(readFormat->pixelBytes) *
                        static_cast<size_t>(area.width) *
                        static_cast<size_t>(area.height);

Additional missed instances (same 32-bit overflow pattern):

  • D3D11: Image11.cpp:428
  • GL: BlitGL.cpp:833, TextureGL.cpp:750

Impact analysis

Impact analysis

This vulnerability has low practical exploitability on current hardware. An attacker would need to target the ~1–3% of Vulkan devices where 16-byte-per-pixel formats lack COLOR_ATTACHMENT support, and those devices typically have MAX_TEXTURE_SIZE below the threshold needed for overflow.

If the overflow were triggered, it would produce a zero-sized Vulkan staging buffer followed by a full-size GPU DMA write, causing potential out-of-bounds writes in renderer GPU process memory.

The primary value is defense-in-depth: the overflow could become reachable through future code changes, new GPU drivers, or new internal callers of readPixelsImpl that bypass validation. The fix is a one-line cast matching the pattern already applied elsewhere in the same file.



The cause

What version of Chrome have you found the security issue in?

145.0.7632.160 + stable

Yes, it is related to a crash.

Choose the type of vulnerability

Other

How would you like to be publicly acknowledged for your report?

mikey233 of HackerOne

View on issue tracker