Medium chrome Uninitialized Memory 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUninitialized Use in Skia
DescriptionUninitialized Use in Skia
ComponentSkia
Bug ClassUninitialized Memory
Tracker498951946
Fix commit5ab06c8b68c4 (skia) +3/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • src/core/SkTypeface_remote.cpp
From 5ab06c8b68c41343a7287bb155a6411ddff0223f Mon Sep 17 00:00:00 2001
From: Michael Ludwig <[email protected]>
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 <[email protected]>
Commit-Queue: Michael Ludwig <[email protected]>
---

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&) {
Loading diff…

Original Bug Report

reported by [email protected]

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.cpp
  • third_party/skia/src/core/SkScalerContext.cpp
  • third_party/skia/src/core/SkGlyph.cpp
  • third_party/skia/src/gpu/ganesh/text/GrAtlasManager.cpp
  • third_party/skia/src/gpu/graphite/text/GlyphData.cpp
  • third_party/skia/src/gpu/graphite/text/TextAtlasManager.cpp
  • gpu/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):

  1. Craft a Malicious Strike: The attacker constructs a serialized font strike containing an SkDescriptor. They set fFrameWidth = -1.0f to indicate a fill operation, ensuring that fGenerateImageFromPath evaluates to false in the GPU process.
  2. 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.
  3. Omit Image Data: To bypass image verification, the attacker places the glyph in the pathsCount section of the strike buffer rather than the imagesCount section, and sets the hasPath boolean to false. This creates an SkGlyph with valid metrics but a nullptr image.
  4. Send and Render: The attacker sends this strike to the GPU process and subsequently issues a draw command referencing the malicious glyph.
  5. 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 generateImage no-op. The uninitialized GPU heap memory is uploaded to the atlas texture.
  6. 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.

  1. Update SkScalerContextProxy::generateImage to explicitly zero the destination buffer (e.g., using sk_bzero(dst, glyph.imageSize())) before returning.
  2. Alternatively, ensure that SkGlyph::allocImage zeroes the memory upon allocation, or enforce stricter validation in SkStrike::mergeFromBuffer to 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.

View on issue tracker