High chrome Race 📄 Reporter bug report

Overview

High
Severity
—
CVSS
No
Exploited ITW
Embargoed
Fix Status
ImpactRace condition in Fonts
DescriptionRace condition in Fonts
ComponentFonts
Sub-componentBlink>Fonts
Bug ClassRace
Tracker520179149
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-06

Fix not yet public

No public source fix for this bug has been identified on the main branch yet — it is embargoed or not yet disclosed. Root-cause analysis is withheld until the fix commit is available.

Original Bug Report

reported by vm...@google.com

Browser Process UAF / Heap OOB Write via FontConfig Race Condition on ChromeOS

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential race condition exists on ChromeOS between the browser UI thread registering language pack fonts and background ThreadPool threads executing FontService IPC queries. Because modern FontConfig versions are treated as thread-safe, no synchronization lock is acquired, allowing concurrent modification of the global application font set. This race can potentially result in a Use-After-Free (UAF) or a Heap Out-Of-Bounds (OOB) write in the browser process.

Affected files:

  • chrome/browser/ash/language_packs/language_pack_font_service.cc
  • content/browser/font_service.cc
  • ui/gfx/linux/fontconfig_util.cc
  • third_party/fontconfig/src/src/fcmatch.c
  • third_party/fontconfig/src/src/fcfs.c
  • third_party/fontconfig/src/src/fccfg.c

Estimated timestamp from git blame: 2024-02-09

Background

On ChromeOS, when the feature kLanguagePacksFonts is enabled, LanguagePackFontService manages localized font assets (e.g., Japanese and Korean). When a localized font pack DLC finishes mounting or downloading, the service registers the font directory on the browser process UI thread:

  • Writer Path (UI Thread): LanguagePackFontService::AddFontDirFromPackResult (at chrome/browser/ash/language_packs/language_pack_font_service.cc:115) -> gfx::AddAppFontDir -> FcConfigAppFontAddDir (at ui/gfx/linux/fontconfig_util.cc:124 / third_party/fontconfig/src/src/fccfg.c:2760).

Concurrently, a sandboxed renderer process can communicate with the background font service to resolve localized characters. The font service handles these Mojo IPCs on a background ThreadPool sequenced task runner:

  • Reader Path (ThreadPool Thread): FontServiceApp::FallbackFontForCharacter -> gfx::GetFallbackFontForChar -> CachedFontSet::CreateForLocale -> FcFontSort (at ui/gfx/font_fallback_linux.cc:474).

The Vulnerability

Historically, Skia wrapped FontConfig calls in FCLocker to enforce serialization. However, for FontConfig versions 2.13.93 or newer (the bundled version in Chrome is 2.17.x), FCLocker behaves as a no-op because it assumes FontConfig’s internal synchronization is sufficient:

// third_party/skia/src/ports/SkFontConfigInterface_direct.cpp
struct FCLocker {
    inline static constexpr int FontConfigThreadSafeVersion = 21393;
    FCLocker() {
        if (FcGetVersion() < FontConfigThreadSafeVersion) {
            f_c_mutex().acquire();
        }
    }
    ...
};

While FontConfig’s lock_config() protects pointer modifications to the global _fcConfig pointer itself, it does not protect against concurrent modifications to individual FcFontSet structures, such as config->fonts[FcSetApplication]. This lack of synchronization permits concurrent execution of FcFontSetAdd (on the UI Thread) and FcFontSetSort (on the ThreadPool thread) on the same font set.

There are two primary potential exploitation primitives resulting from this race:

Primitive A: Use-After-Free (UAF)

During font registration, FcFontSetAdd (at third_party/fontconfig/src/src/fcfs.c:58) may trigger a resize of the underlying pointer array when capacity is reached:

f = (FcPattern **)realloc (s->fonts, sfont * sizeof (FcPattern *));

If the heap manager relocates this allocation, the old s->fonts buffer is freed. If the ThreadPool thread is currently executing FcFontSetSort (at third_party/fontconfig/src/src/fcmatch.c:1182-1187), it will read from and dereference the freed pointer array, leading to a Use-After-Free.

Primitive B: Heap Out-Of-Bounds (OOB) Write via TOCTOU

In FcFontSetSort, the ThreadPool thread performs a two-pass operation on the font set. First, it reads s->nfont to determine the required allocation size for sorting nodes:

nnodes = 0;
for (set = 0; set < nsets; set++) {
    s = sets[set];
    ...
    nnodes += s->nfont;
}
nodes = malloc (nnodes * sizeof (FcSortNode) + ...);

Subsequently, it iterates through the loop again to populate the buffer:

for (f = 0; f < s->nfont; f++) {
    newp->pattern = s->fonts[f];
    *nodep = newp;
    newp++;
    nodep++;
}

If the UI thread inserts a font via FcFontSetAdd between these two passes, s->nfont is incremented. The second loop then runs for more iterations than originally allocated, resulting in an out-of-bounds heap write of up to ~256 bytes per added font directly into adjacent heap allocations.

Potential Attack Scenario

Note: These are potential steps estimated from code analysis; our tooling does not currently have the capability to execute live exploit code.

  1. An attacker compromises the sandboxed renderer process (e.g., via a separate V8 or Blink vulnerability).
  2. The compromised renderer connects to the font_service::mojom::FontService interface.
  3. The renderer floods FallbackFontForCharacter IPC requests with randomized, unique locale strings (e.g., "en-US-x-0", "en-US-x-1", …) to force cache misses, keeping background threads actively performing FcFontSort queries.
  4. The renderer triggers a localized font DLC installation or causes the user’s kPreferredLanguages setting to update, forcing the UI thread to execute font directory registration via FcConfigAppFontAddDir.
  5. The race condition occurs, resulting in heap corruption (UAF or Heap OOB Write) in the browser process, which could potentially be leveraged for a sandbox escape.

Suggested Fix

To remediate this issue, FontConfig modifications on the UI thread must be serialized with background font queries. Since Skia’s FCLocker assumes FontConfig is thread-safe, Chrome should enforce its own synchronization lock in the browser process around any operations modifying the application-level font config (FcConfigAppFontAddDir), or ensure that all FontConfig-related queries and modifications are dispatched and executed on a single dedicated sequence runner rather than running concurrently on ThreadPool threads and the UI thread.

Evaluated with Chrome root at commit: d8b226a3be7c9c1ac9240c09e14698866c82e4ac


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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