CVE-2026-74969
Overview
Background
- `gfxFontGroup::FindFontForChar`
- the font-fallback routine that walks a font group to pick a
gfxFontcapable 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.
RefPtr<gfxFontEntry> pins the object’s lifetime for the whole scope, eliminating the dangling access.Attack Path
- Trigger user-font fallback
A page loads content that forces
gfxFontGroup::FindFontForCharto consult agfxUserFontEntry(e.g. an@font-facefont) for a character. - Capture raw platform entry
The code stores the platform
gfxFontEntryin a rawpfewhile the user font’s load state is still in flux. - Free the entry mid-use
Font-loading/fallback processing releases or swaps the underlying
gfxFontEntry, freeing the memorypfepoints at. - 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
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 objectsaudit other call sites that assign
GetPlatformFontEntry()(and similargfxFontEntry/gfxFontgetters) to raw pointers and hold them across load or fallback calls; preferRefPtr. - Lifetime across reentrant font-loadingreview 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 callbacksflag any borrowed pointer to a refcounted graphics object that survives across a call (like
GetFontAt) capable of triggering deletion, swap, or re-entrancy.
Patch
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);