Overview

Critical
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds write in GPU
DescriptionOut of bounds write in GPU
ComponentGPU
Bug ClassOOB
Tracker505077859
Fix commitae8c96f69539 (chromium/src) +11/-0
CISA KEVNot listed
Creditedcinzinga
Disclosed2026-05-27

Changed Functions

FunctionChangeNotes
if
gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
modified
CopyTextureResourceManagerImpl
gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
modified

Files Changed

  • gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
From ae8c96f69539e21694476ca6e3fad3f125698850 Mon Sep 17 00:00:00 2001
From: Vasiliy Telezhnikov <vasilyt@chromium.org>
Date: Thu, 23 Apr 2026 13:58:48 -0700
Subject: [PATCH] Fix pack/unpack state during DoReadbackAndTexImage

Bug: 505077859
Change-Id: If5fd8a788710e0a7b0724fdfacfa309416a2b153
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7789335
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1619750}
---

diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index 98e7f6f..a73cca8 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -677,6 +677,10 @@
     return false;
   }
 
+  // We're about to read pixels, so we need to reset PACK params
+  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+  glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
   // Result of glReadPixels with format == GL_RGB and type == GL_UNSIGNED_BYTE
   // from read framebuffer in RGBA format is not correct on desktop core
   // profile on both Linux Mesa and Linux NVIDIA. This may be a driver bug.
@@ -839,9 +843,15 @@
       decoder->RestoreActiveTexture();
       decoder->RestoreFramebufferBindings();
       decoder->RestoreBufferBindings();
+      decoder->RestoreGlobalState();
       return;
     }
 
+    // Our buffer is tightly packed, so reset unpack params.
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
     if (command_type == kTexImage) {
       glTexImage2D(dest_target, dest_level, dest_internal_format, width, height,
                    0, format, type, 0);
@@ -858,6 +868,7 @@
   decoder->RestoreActiveTexture();
   decoder->RestoreFramebufferBindings();
   decoder->RestoreBufferBindings();
+  decoder->RestoreGlobalState();
 }
 
 class CopyTextureResourceManagerImpl
Loading diff…

Original Bug Report

reported by ci...@gmail.com

Validating Decoder Stale PACK_ALIGNMENT causes GPU Heap OOB Write


Report description

Validating Decoder Stale PACK_ALIGNMENT causes GPU Heap OOB Write


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://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc


The problem

Please describe the technical details of the vulnerability

PrepareUnpackBuffer() allocates a width * height * 4 RGBA scratch buffer and calls glReadPixels(..., GL_RGBA, GL_UNSIGNED_BYTE, ...) on Android for the fallback readback path used by GL_RGB / GL_FLOAT uploads. The code assumes tightly packed rows, but attacker-controlled GL_PACK_ALIGNMENT is still honored because the validating decoder forwards pack state to native GL and Blink resets only unpack state before this path. With PACK_ALIGNMENT = 8 and width = 3, each row is written with a 16-byte stride even though only 12 bytes per row are allocated.

The PoC sets PACK_ALIGNMENT = 8 and uploads a 3 x 8192 source canvas with per-row markers via texImage2D(GL_TEXTURE_2D, 0, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT, srcCanvas), reaching PrepareUnpackBuffer() on Android with the undersized buffer.

At those dimensions, the allocation is 98304 bytes, but rows are written at 16-byte stride. The last 2048 rows therefore go out of bounds, yielding 24576 bytes of attacker-controlled data written over roughly 32 KB beyond the allocation.

Steps to Reproduce

Serve poc.html over HTTP and open it in Chrome on Android. No flags required.

Crash Evidence

  1. Symbolized ASan stack trace (from Android content shell) attached as symbolized_stack_trace.txt
  2. Chrome Stable tombstone is from com.android.chrome:privileged_process* (CrGpuMain), signal 11 SEGV_ACCERR (write), with the fault in ReadPixels/glReadPixels
  3. chrome://crashes 0e2b36268c1779c4 or 311f8eaf5e9c3abb

Proposed Fix

Either compute the allocation using the effective packed row stride, or temporarily force a safe GL_PACK_ALIGNMENT around the internal glReadPixels call and restore the previous value.

Bisect

Introduced by commit 986a220965888 (Add readback path for CopyTextureCHROMIUM, 2017-03-30), which added the fallback readback path and its tight-row allocation assumption.

Impact analysis

  • Web-accessible via WebGL2 on Android, no compromised renderer required.
  • GPU process linear heap overwrite of attacker-controlled pixel data, 24576 bytes, deterministic geometry.
  • On current Android phone builds, this reaches the GPU process without the Android GPU sandbox enabled by default.

The cause

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

147.0.7727.101 (Official Build) (64-bit)

Yes, it is related to a crash.

Choose the type of vulnerability

Memory Corruption (in a non-sandboxed process)

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

cinzinga

View on issue tracker