Medium watch CVSS 4.3 chrome Uninitialized Memory 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUninitialized Use in GPU
DescriptionUninitialized Use in GPU
ComponentGPU
Sub-componentFortify
Bug ClassUninitialized Memory
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker497546281
Fix commite5d38dd102bd (chromium/src) +1/-0
CWECWE-457 (Use of uninitialized)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-03-29 (per vendor advisory)
Fix landed2026-04-02 (public git)
Disclosed2026-05-05
Patch gap33 days — fix public in source before the advisory

Background

RasterDecoderImpl
the GPU-process command-buffer decoder that services raster/canvas GL commands on behalf of untrusted renderer clients.
`DoWritePixelsINTERNAL`
the decoder handler (named in the commit subject) that copies client-supplied pixel data into a destination SkCanvas/shared image.
Scoped write access
dest_scoped_access is an RAII handle to the destination image whose contents are committed to the GPU by FlushWriteAccess.
Uninitialized use
reading or publishing memory whose bytes were never written with valid data.

Root Cause Analysis

In the !written branch, the code recognized that the pixel write into the SkCanvas had failed and raised GL_INVALID_OPERATION via LOCAL_SET_GL_ERROR, but it then fell through and still called shared_context_state_->FlushWriteAccess(dest_scoped_access.get()). Because the destination was never successfully populated, flushing committed a destination image backed by uninitialized (or stale) memory. The invariant violated is that a write-access handle must only be flushed after a successful write; on the failure path that invariant was broken by the missing early exit.

The fix inserts return; immediately after setting the GL error, so the failure path no longer reaches FlushWriteAccess, leaving the uninitialized destination uncommitted. This is a straightforward addition of an early-exit guard before the sink, not a change to any validation condition.

Key insight
The core mistake was treating a failed pixel write as a non-fatal condition and continuing to FlushWriteAccess on the unwritten destination; adding return; after the error ensures the uninitialized buffer is never flushed.

Attack Path

  1. Issue a crafted WritePixels command A compromised or malicious renderer sends a raster glWritePixels command whose parameters cause the SkCanvas write to fail (written == false).
  2. Error is set but execution continues The handler records GL_INVALID_OPERATION yet, pre-patch, does not return, so control proceeds to the flush step.
  3. Flush of uninitialized destination FlushWriteAccess(dest_scoped_access.get()) commits the destination image even though no valid pixels were written, publishing uninitialized memory.
  4. Observe leaked contents The attacker reads back the destination (e.g. via subsequent GPU reads/compositing) to recover uninitialized GPU-process memory (inferred: an information-disclosure primitive; the patch demonstrates the uninitialized flush, not a concrete readback).

Impact Assessment

An attacker controlling a renderer can cause the GPU process to commit a destination image from uninitialized memory, potentially exposing residual GPU-process memory contents to the renderer. The advisory rates this medium severity (uninitialized use in GPU) and does not report in-the-wild exploitation. The precondition is the ability to drive raster write-pixels commands that fail the SkCanvas write while reaching the flush path.

Changed Functions

FunctionChangeNotes
if
gpu/command_buffer/service/raster_decoder.cc
modified

Files Changed

  • gpu/command_buffer/service/raster_decoder.cc

Audit Directions

  • Error-set-but-no-return
    Search decoder handlers for paths that call LOCAL_SET_GL_ERROR (or similar) without an immediate return, allowing execution to continue into commit/flush/use sinks.
  • Flush after failed write
    Audit scoped write-access patterns (FlushWriteAccess, EndWriteAccess) to confirm they are reached only when the preceding write succeeded.
  • Partial-success GPU operations
    Review raster/skia operations whose success is captured in a boolean that must gate every downstream publish of the destination resource.
From e5d38dd102bdab1617cbf0db17f1c9292cb5c0ec Mon Sep 17 00:00:00 2001
From: Yuki Shiino <yukishiino@chromium.org>
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 <yukishiino@chromium.org>
Reviewed-by: Khushal Sagar <khushalsagar@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
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());
Loading diff…

Original Bug Report

reported by vm...@google.com

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.

  1. Compromise Renderer: Gain code execution in a renderer process.
  2. Create SharedImage: Create an uninitialized SharedImage via the GPU command buffer with SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_RASTER_READ usages.
  3. Bypass Fast Path: Send a WritePixelsINTERNALImmediate command. Provide a valid SkColorSpace that deliberately does not match the destination texture’s color space to bypass the direct-upload fast path.
  4. Trigger Failure: In the same command, set src_sk_alpha_type to 0 (kUnknown_SkAlphaType) and provide x_offset=0, y_offset=0, and dimensions matching the full texture size.
  5. Exploit Fallthrough: The GPU process will fail to write the pixels in Skia, log a GL_INVALID_OPERATION error, but incorrectly mark the texture as cleared due to the missing return statement.
  6. Readback Memory: Send a ReadbackARGBImagePixelsINTERNALImmediate command 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.

View on issue tracker