CVE-2026-10925
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
whilesrc/ports/SkTypeface_mac_ct.cpp |
modified | |
ifsrc/ports/SkTypeface_mac_ct.cpp |
modified |
Files Changed
src/ports/SkTypeface_mac_ct.cpp
Patch
From fa3d352e688f1edc9b8fd4fc4e7b099c35214225 Mon Sep 17 00:00:00 2001 From: Daniel Angulo <[email protected]> Date: Thu, 16 Apr 2026 16:59:03 +0000 Subject: [PATCH] added bounds check for glyph access on typeface quick fix for a potential security issue Bug: 500071763 Change-Id: I24a6f4a6a4b58706b792668037011d86da8bd1d4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1210036 Reviewed-by: Ben Wagner <[email protected]> Commit-Queue: Ben Wagner <[email protected]> Auto-Submit: Daniel Angulo <[email protected]> --- diff --git a/src/ports/SkTypeface_mac_ct.cpp b/src/ports/SkTypeface_mac_ct.cpp index f52a5e5..21d6e9c 100644 --- a/src/ports/SkTypeface_mac_ct.cpp +++ b/src/ports/SkTypeface_mac_ct.cpp @@ -376,16 +376,17 @@ // Web fonts added to the CTFont registry do not return their character set. // Iterate through the font in this case. The existing caller caches the result, // so the performance impact isn't too bad. -static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, +static void populate_glyph_to_unicode_slow(CTFontRef ctFont, const CFIndex glyphCount, SkUnichar* out) { sk_bzero(out, glyphCount * sizeof(SkUnichar)); + CFIndex glyphsRemaining = glyphCount; UniChar unichar = 0; - while (glyphCount > 0) { + while (glyphsRemaining > 0) { CGGlyph glyph; if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { - if (out[glyph] == 0) { + if (glyph < glyphCount && out[glyph] == 0) { out[glyph] = unichar; - --glyphCount; + --glyphsRemaining; } } if (++unichar == 0) {
Original Bug Report
Potential Heap OOB Write in Skia's populate_glyph_to_unicode_slow during PDF generation
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 heap out-of-bounds write exists in Skia’s macOS font handling when processing malicious fonts during PDF generation. A compromised renderer can bypass OpenType Sanitizer (OTS) by sending a crafted font to the PrintCompositor, triggering an OOB write when Skia maps Unicode characters to glyphs. This could potentially allow an attacker to achieve Remote Code Execution in the privileged PrintCompositor process.
Affected files:
third_party/skia/src/ports/SkTypeface_mac_ct.cpp
Estimated timestamp from git blame: 2020-06-05
Summary
A potential heap-based out-of-bounds (OOB) write vulnerability exists in SkTypeface_Mac::populate_glyph_to_unicode_slow within Skia’s macOS-specific font handling code. When the PrintCompositor utility process deserializes an untrusted font provided by a compromised renderer, it bypasses the standard OpenType Sanitizer (OTS) checks. A maliciously crafted font can cause macOS’s CoreText API to return out-of-bounds glyph IDs, which Skia then uses to index a heap-allocated buffer without verifying the bounds, leading to memory corruption.
Note: The steps and impact described below are based on detailed static analysis. Our tooling does not yet have the ability to run code to provide a fully working Proof of Concept.
Technical Details
The defect is located in third_party/skia/src/ports/SkTypeface_mac_ct.cpp. The function populate_glyph_to_unicode_slow builds a mapping from glyph IDs to Unicode characters.
static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
SkUnichar* out) {
sk_bzero(out, glyphCount * sizeof(SkUnichar));
UniChar unichar = 0;
while (glyphCount > 0) {
CGGlyph glyph;
if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
// VULNERABILITY: No bounds check to ensure glyph < glyphCount
if (out[glyph] == 0) {
out[glyph] = unichar;
--glyphCount;
}
}
// ...
}
}
The out array is backed by a std::vector<SkUnichar> allocated in SkPDFFont::GetUnicodeMap. The size of this vector is strictly determined by the font’s reported numGlyphs (from the font’s maxp table). However, the code uses the glyph ID returned by CTFontGetGlyphsForCharacters directly as an index into out. If a malicious font’s cmap table maps a character to a glyph ID exceeding the total glyph count, an out-of-bounds write occurs on the PartitionAlloc heap. A sibling function in the same file, get_plane_glyph_map, correctly implements this check (if (glyphs[0] < glyphCount)).
Potential Attacker Steps
An attacker could potentially trigger this vulnerability by following these steps:
- Compromise a Renderer: The attacker gains code execution in a renderer process.
- Craft a Malicious Font: The attacker generates an SFNT font blob with a very small
maxp.numGlyphsvalue (e.g., 10), but crafts thecmaptable to map a specific Unicode character (e.g.,0x1337) to a large, out-of-bounds glyph ID (e.g.,1000). - Trigger Print Spooling: The compromised renderer initiates a print job, embedding the raw malicious font into the serialized
SkPicturedata stream sent to the browser. - Bypass OTS: The
PrintCompositorutility process receives the stream and deserializes the font viaDeserializeOopTypeface. On macOS, this invokesCTFontManagerCreateFontDescriptorFromDatadirectly, entirely bypassing the OpenType Sanitizer (OTS) which would normally catch thecmap/maxpmismatch. - Trigger OOB Write: During PDF generation,
SkPDFFont::GetUnicodeMapallocates a tiny 10-element vector. Skia falls back topopulate_glyph_to_unicode_slow, iterates over characters, and asks CoreText for the glyph mapping. CoreText returns the malicious out-of-bounds glyph ID (1000). Skia writes the 32-bit Unicode character intoout[1000], corrupting memory far beyond the allocated vector.
Impact
This vulnerability provides a strong primitive: a controlled out-of-bounds write of a 16-bit value (zero-extended to 32 bits) at a highly controllable offset on the heap. Exploiting this could allow an attacker to overwrite adjacent objects or pointers (e.g., vtable pointers) to achieve Remote Code Execution (RCE) in the PrintCompositor process.
While PrintCompositor is a sandboxed utility process, it frequently processes cross-origin print jobs (such as OOPIFs). An RCE in this process would allow an attacker to bypass Site Isolation and steal sensitive cross-origin data from printed documents.
Suggested Fix
Add an explicit bounds check in populate_glyph_to_unicode_slow before accessing the out array.
CGGlyph glyph;
if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
if (glyph < glyphCount && out[glyph] == 0) {
out[glyph] = unichar;
// ...
Evaluated with Chrome root at commit: f200f57a19490707ff8bc7aa5de3cbc443a3afad
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.