CVE-2026-9872
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifgpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc |
modified | |
CopyTextureResourceManagerImplgpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc |
modified |
Files Changed
gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
Patch
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
Original Bug Report
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?
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
- Symbolized ASan stack trace (from Android content shell) attached as symbolized_stack_trace.txt
- Chrome Stable tombstone is from com.android.chrome:privileged_process* (CrGpuMain), signal 11 SEGV_ACCERR (write), with the fault in ReadPixels/glReadPixels
- chrome://crashes
0e2b36268c1779c4or311f8eaf5e9c3abb
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)
Is the security issue related to a crash?
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