← WebKit — 2026-W35

42b1e2aac2c7818c53377a9e0103e3532b994b65  Use-after-free in CSSFontSelector::opportunisticallyStartFontDataURLLoading

severity medium class UAF confidence 0.42 signal score 11.3 Source/WebCore/css
Primitive: raw reference to CSSSegmentedFontFace/constituent faces/FontCascade::fonts() held across opportunistic font loading
Triage note: Under RC_REMOVE_SEC_ACCEL_3 the active branch converts fontFace() result to RefPtr, constituentFaces() loop to Ref, and fonts() to Ref in FontCascade::width(). Prophylactic Ref/RefPtr hardening holding strong refs across reentrant font loading; no specific identified bug, so not graded exploitable.
Structural signals: smartptr_member_added (+3.0), msg_strong (+3.0), msg_medium (+2.0), area:Source/WebCore/css (+2.0), surgical (+1.3)

Commit message

Use-after-free in CSSFontSelector::opportunisticallyStartFontDataURLLoading
rdar://182680798

Reviewed by Zak Ridouh.

The CSSSegmentedFontFace returned by CSSFontFaceSet::fontFace() is owned only by
CSSFontFaceSet::m_cache. In a worker a small data: URL font load completes synchronously
and resolves the FontFace loaded promise. Author script running from that promise can call
FontFaceSet.add(), which clears m_cache. The segmented font face is then destroyed while
the loop over its constituentFaces() is still running.

CSSFontSelector::fontRangesForFamily and CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts
already hold a RefPtr across the same call.

That same script reaches CanvasRenderingContext2DBase::FontProxy::fontsNeedUpdate, which
replaces FontCascade::m_fonts. The previous FontCascadeFonts is left referenced only by
FontCascadeCache, so the next FontCache purge drops it through pruneUnreferencedEntries().
FontCascade::width takes a raw GlyphGeometryCache entry out of that object, runs the nested
width computation, and then writes the result back into the entry.

* Source/WebCore/css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::opportunisticallyStartFontDataURLLoading):
* Source/WebCore/platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::width const):
* LayoutTests/sar3/fast/text/font-face/css-font-selector-opportunistic-load-reentrancy-crash.html: Added.
* LayoutTests/sar3/fast/text/font-face/css-font-selector-opportunistic-load-reentrancy-crash-expected.txt: Added.
* LayoutTests/sar3/fast/text/font-face/resources/opportunistic-load-reentrancy-worker.js: Added.

Identifier: 316606.520@safari-7625-branch

Before / after

Loading diff…