CVE-2026-7972
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifgpu/command_buffer/service/raster_decoder.cc |
modified |
Files Changed
gpu/command_buffer/service/raster_decoder.cc
Patch
From e5d38dd102bdab1617cbf0db17f1c9292cb5c0ec Mon Sep 17 00:00:00 2001 From: Yuki Shiino <[email protected]> Date: Wed, 01 Apr 2026 22:20:34 -0700 Subject: [PATCH] fortify: Fix a bailout in RasterDecoderImpl::DoWritePixelsINTERNAL Bug: 497546281 Change-Id: Ibe76a24636c0c46e86cff3cbf622ed432b116b89 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7720035 Auto-Submit: Yuki Shiino <[email protected]> Reviewed-by: Khushal Sagar <[email protected]> Reviewed-by: Kai Ninomiya <[email protected]> Commit-Queue: Kai Ninomiya <[email protected]> Cr-Commit-Position: refs/heads/main@{#1608978} --- diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index dad0ff5..4424789b 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc @@ -2033,6 +2033,7 @@ if (!written) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glWritePixels", "Failed to write pixels to SkCanvas"); + return; } shared_context_state_->FlushWriteAccess(dest_scoped_access.get());
Original Bug Report
Uninitialized GPU memory disclosure in RasterDecoderImpl::DoWritePixelsINTERNAL
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A missing return statement in RasterDecoderImpl::DoWritePixelsINTERNAL allows uninitialized GPU texture memory to be incorrectly marked as cleared when a write operation fails. A compromised renderer can exploit this to bypass initialization checks and leak cross-origin GPU memory.
Affected files:
gpu/command_buffer/service/raster_decoder.cc
Estimated timestamp from git blame: 2020-04-15
Summary
There is a potential high-severity information disclosure vulnerability in gpu/command_buffer/service/raster_decoder.cc. In RasterDecoderImpl::DoWritePixelsINTERNAL, if the Skia canvas->writePixels operation fails, the code logs a GL error but fails to return early. This allows execution to fall through and incorrectly mark the destination SharedImage as fully initialized, permitting a compromised renderer to read back uninitialized, potentially cross-origin GPU memory.
Technical Details
When processing a pixel upload to a SharedImage, the function DoWritePixelsINTERNAL executes the following logic on the Skia fallback path:
bool written =
canvas->writePixels(src_info, pixel_data, row_bytes, x_offset, y_offset);
if (!written) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glWritePixels",
"Failed to write pixels to SkCanvas");
// VULNERABILITY: Missing return statement here
}
// ... synchronization code ...
if (!dest_shared_image->IsCleared()) {
dest_shared_image->SetClearedRect(
gfx::Rect(x_offset, y_offset, src_width, src_height));
}
An attacker can intentionally trigger the Skia write failure by providing parameters that pass the decoder’s initial validation but are rejected by Skia. For instance, setting src_sk_alpha_type to 0 (kUnknown_SkAlphaType) passes the enum range check in RasterDecoderImpl (which just checks <= kLastEnum_SkAlphaType) but causes SkColorInfoIsValid to fail inside Skia’s internal checks, resulting in canvas->writePixels returning false without modifying the GPU memory.
Because there is no return statement inside the if (!written) block, execution erroneously continues and dest_shared_image->SetClearedRect is called. If the attacker provided dimensions that cover the entire texture, the SharedImage is marked as fully cleared.
The attacker can then issue a readback command (e.g., ReadbackARGBImagePixelsINTERNALImmediate). Since the IsCleared() security check now returns true, the system will happily copy the uninitialized GPU memory—which may contain sensitive textures from other tabs, WebGL framebuffers, or browser UI tiles—back to a shared memory buffer accessible to the attacker.
Suggested Attacker Steps
Note: These are potential steps, as our tooling agent does not yet have the ability to run code to verify them with a live proof-of-concept.
- Compromise Renderer: Gain code execution in a renderer process.
- Create SharedImage: Create an uninitialized
SharedImagevia the GPU command buffer withSHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_RASTER_READusages. - Bypass Fast Path: Send a
WritePixelsINTERNALImmediatecommand. Provide a validSkColorSpacethat deliberately does not match the destination texture’s color space to bypass the direct-upload fast path. - Trigger Failure: In the same command, set
src_sk_alpha_typeto0(kUnknown_SkAlphaType) and providex_offset=0,y_offset=0, and dimensions matching the full texture size. - Exploit Fallthrough: The GPU process will fail to write the pixels in Skia, log a
GL_INVALID_OPERATIONerror, but incorrectly mark the texture as cleared due to the missingreturnstatement. - Readback Memory: Send a
ReadbackARGBImagePixelsINTERNALImmediatecommand for the exact same mailbox. The initialization security gate will pass, and uninitialized GPU memory will be copied into shared memory accessible by the compromised renderer.
Suggested Fix
Add a return; statement immediately after logging the error inside the if (!written) block in RasterDecoderImpl::DoWritePixelsINTERNAL:
if (!written) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glWritePixels",
"Failed to write pixels to SkCanvas");
return; // <--- ADD THIS
}
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.