Medium firefox UAF 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionUse-after-free in the Layout: Text and Fonts component
ComponentGraphics
Bug ClassUAF
Tracker2056065
Fix commit4061800c286f (firefox) +1/-1
CISA KEVNot listed
CreditedHyeonjun Ahn
Disclosed2026-08-18

Background

`gfxFontGroup::FindFontForChar`
the font-fallback routine that walks a font group to pick a gfxFont capable of rendering a given character.
`gfxUserFontEntry` (`ufe`)
a font-group entry describing a downloadable/user (@font-face) font whose underlying platform font may be loaded or swapped asynchronously.
`gfxFontEntry` (`pfe`)
the platform-level font entry backing a user font, returned by ufe->GetPlatformFontEntry(), whose lifetime is managed by reference counting.
`RefPtr<T>`
Gecko’s smart pointer that holds a strong reference, keeping a refcounted object alive for the duration of the pointer’s scope.

Root Cause Analysis

In gfxFontGroup::FindFontForChar, the platform font entry was captured as a raw pointer via gfxFontEntry* pfe = ufe->GetPlatformFontEntry() and then dereferenced (pfe->HasCharacter(...)) and used alongside a call to GetFontAt(i, aCh, &loading). Because pfe was only a borrowed raw pointer, nothing kept the underlying gfxFontEntry alive across the surrounding font-fallback/loading logic, so if the user font’s platform entry was released or replaced during that processing the pointer could dangle. The violated invariant is that any refcounted gfxFontEntry must be held by a strong reference while it is being dereferenced.

The fix changes the declaration to RefPtr<gfxFontEntry> pfe, taking a strong reference so the entry stays alive for the entire block regardless of concurrent load-state or font-list mutation. This closes the use-after-free window without altering the fallback logic itself.

Key insight
The single mistake was borrowing a refcounted platform font entry as a bare raw pointer while operations that could free it were still in flight; wrapping it in RefPtr<gfxFontEntry> pins the object’s lifetime for the whole scope, eliminating the dangling access.

Attack Path

  1. Trigger user-font fallback A page loads content that forces gfxFontGroup::FindFontForChar to consult a gfxUserFontEntry (e.g. an @font-face font) for a character.
  2. Capture raw platform entry The code stores the platform gfxFontEntry in a raw pfe while the user font’s load state is still in flux.
  3. Free the entry mid-use Font-loading/fallback processing releases or swaps the underlying gfxFontEntry, freeing the memory pfe points at.
  4. Dereference dangling pointer Subsequent use of pfe (HasCharacter / continued fallback) reads freed memory, yielding a use-after-free that may be shaped into a controlled access.

Impact Assessment

An attacker who controls page content and fonts can provoke a use-after-free of a gfxFontEntry in the graphics/layout text-and-font code, which runs in the content process. This is a moderate-severity memory-safety defect that could lead to a crash or potentially exploitable memory corruption; the precondition is rendering text with a user/downloadable font whose platform entry can be freed during fallback.

Files Changed

  • gfx/thebes/gfxTextRun.cpp

Audit Directions

  • Raw pointers from getters returning refcounted objects
    audit other call sites that assign GetPlatformFontEntry() (and similar gfxFontEntry/gfxFont getters) to raw pointers and hold them across load or fallback calls; prefer RefPtr.
  • Lifetime across reentrant font-loading
    review font-fallback paths where user-font load state can mutate the font group or free entries mid-iteration and confirm every dereferenced entry is strongly held.
  • Borrowed pointers spanning callbacks
    flag any borrowed pointer to a refcounted graphics object that survives across a call (like GetFontAt) capable of triggering deletion, swap, or re-entrancy.
diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp
index d05fe57ef83..5b68d6602b4 100644
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -3432,7 +3432,7 @@ already_AddRefed<gfxFont> gfxFontGroup::FindFontForChar(
           loading = true;
         }
 
-        gfxFontEntry* pfe = ufe->GetPlatformFontEntry();
+        RefPtr<gfxFontEntry> pfe = ufe->GetPlatformFontEntry();
         if (pfe && (pfe->HasCharacter(aCh) ||
                     (fallbackChar && pfe->HasCharacter(fallbackChar)))) {
           font = GetFontAt(i, aCh, &loading);
Loading diff…