CVE-2026-11057
Overview
Files Changed
src/core/SkTypeface_remote.cpp
Patch
From 5ab06c8b68c41343a7287bb155a6411ddff0223f Mon Sep 17 00:00:00 2001
From: Michael Ludwig <michaelludwig@google.com>
Date: Wed, 29 Apr 2026 09:48:05 -0400
Subject: [PATCH] [text] Zero out glyph images on cache miss
Bug: b/498951946
Change-Id: I50b050ccfcf64565842496ba5ba2dd724dc6ad39
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1221656
Reviewed-by: Kaylee Lubick <kjlubick@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
---
diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp
index fb3fb60..780ca8b 100644
--- a/src/core/SkTypeface_remote.cpp
+++ b/src/core/SkTypeface_remote.cpp
@@ -44,7 +44,7 @@
return {glyph.maskFormat()};
}
-void SkScalerContextProxy::generateImage(const SkGlyph& glyph, void*) {
+void SkScalerContextProxy::generateImage(const SkGlyph& glyph, void* imageBuffer) {
TRACE_EVENT1("skia", "generateImage", "rec", TRACE_STR_COPY(this->getRec().dump().c_str()));
if (this->getProxyTypeface()->isLogging()) {
SkDebugf("GlyphCacheMiss generateImage: %s\n", this->getRec().dump().c_str());
@@ -54,6 +54,8 @@
// copied over with the metrics search.
fDiscardableManager->notifyCacheMiss(
SkStrikeClient::CacheMissType::kGlyphImage, fRec.fTextSize);
+ // Fill the glyph image with zeros so the missing glyph doesn't display unitialized memory.
+ sk_bzero(imageBuffer, glyph.imageSize());
}
std::optional<SkScalerContext::GeneratedPath> SkScalerContextProxy::generatePath(const SkGlyph&) {
Original Bug Report
GPU Process Heap Leak via SkScalerContextProxy
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the security team.
Overview: A potential vulnerability in Skia’s remote glyph cache allows a compromised renderer to leak up to 256KB of uninitialized GPU process heap memory per glyph. This occurs because SkScalerContextProxy::generateImage is a no-op that leaves its destination buffer uninitialized. By carefully crafting a font strike, an attacker can force the system to allocate an uninitialized bitmap and upload it to the texture atlas, leading to a cross-origin information leak.
Affected files:
third_party/skia/src/core/SkTypeface_remote.cppthird_party/skia/src/core/SkScalerContext.cppthird_party/skia/src/core/SkGlyph.cppthird_party/skia/src/gpu/ganesh/text/GrAtlasManager.cppthird_party/skia/src/gpu/graphite/text/GlyphData.cppthird_party/skia/src/gpu/graphite/text/TextAtlasManager.cppgpu/command_buffer/service/raster_decoder.cc
Estimated timestamp from git blame: 2023-07-27
Background
In Chrome’s Out-of-Process Rasterization (OOP-R), the renderer process communicates font and glyph information to the GPU process. This information is cached in the GPU process using a remote glyph cache (SkChromeRemoteGlyphCache). When a glyph needs to be rendered, it is added to a texture atlas if it isn’t already present.
Vulnerability Description
There is a potential heap memory disclosure vulnerability in the GPU process caused by how SkScalerContextProxy handles missing glyph images.
When a glyph’s image is missing from the cache, SkGlyph::setImage allocates memory for the glyph’s mask by calling allocImage. This memory is backed by SkArenaAlloc, which uses sk_malloc_throw. In Chrome production builds, PartitionAlloc does not zero-fill malloc allocations by default, meaning the allocated buffer contains raw, uninitialized GPU process heap memory.
The system then calls scalerContext->getImage to populate this buffer. For remote typefaces, this invokes SkScalerContextProxy::generateImage (third_party/skia/src/core/SkTypeface_remote.cpp). However, this function is a no-op that simply notifies a cache miss and returns without writing to the buffer. The uninitialized heap data is then blindly copied into the text atlas staging buffer by TextAtlasManager and uploaded to the GPU.
Potential Attack Vector
An attacker who has compromised a sandboxed renderer process could potentially exploit this issue with the following steps (note: this is a theoretical sequence, as our tooling cannot currently run live code):
- Craft a Malicious Strike: The attacker constructs a serialized font strike containing an
SkDescriptor. They setfFrameWidth = -1.0fto indicate a fill operation, ensuring thatfGenerateImageFromPathevaluates tofalsein the GPU process. - Define a Maximum Size Glyph: The attacker includes a glyph with metrics set to the maximum allowed atlas dimensions (e.g., 256x256) and an ARGB32 format, resulting in an expected image size of 256KB.
- Omit Image Data: To bypass image verification, the attacker places the glyph in the
pathsCountsection of the strike buffer rather than theimagesCountsection, and sets thehasPathboolean tofalse. This creates anSkGlyphwith valid metrics but anullptrimage. - Send and Render: The attacker sends this strike to the GPU process and subsequently issues a draw command referencing the malicious glyph.
- Leak via Atlas Upload: The GPU process realizes the glyph image is missing and attempts to generate it. It allocates a 256KB uninitialized buffer and calls the
generateImageno-op. The uninitialized GPU heap memory is uploaded to the atlas texture. - Exfiltration: The text is rendered onto the canvas using the tainted atlas texture. The attacker reads back the canvas pixels (e.g., via WebGL or
getImageData), exfiltrating 256KB of sensitive GPU process memory per drawn glyph.
Impact
This vulnerability allows a compromised renderer to repeatedly read large, controlled chunks of the GPU process heap. An attacker can use this to leak sensitive cross-origin data, such as the contents of other renderers’ SharedImages, browser UI state, or cryptographic material, facilitating further attacks or a complete GPU process compromise.
Suggested Remediation
Memory allocated for glyph images should be explicitly zero-initialized, especially when interacting with proxy contexts that may not populate the buffer.
- Update
SkScalerContextProxy::generateImageto explicitly zero the destination buffer (e.g., usingsk_bzero(dst, glyph.imageSize())) before returning. - Alternatively, ensure that
SkGlyph::allocImagezeroes the memory upon allocation, or enforce stricter validation inSkStrike::mergeFromBufferto reject glyphs that possess metrics but lack both image and path data when they should be populated.
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results 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.