[3] Highlight API iterator-invalidation UAF in clearFromSetLike
Severity: High | Component: CSS Custom Highlight API | 13d284a
Rated High because the observable effect is a confirmed use-after-free during document teardown (ASAN crash under Highlight::clearFromSetLike), and the re-entrant modification path through repaintRange() is plausible given WebKit's synchronous layout model — escalation to a controlled read/write primitive would require heap reclamation during the re-entrant window, which is unverified but architecturally feasible.
Follow-up fix after a previous embargoed patch. clearFromSetLike() now drains m_highlightRanges into a stack-local temporary via std::exchange before iterating, so any re-entrant modification to the member during repaintRange() callbacks operates on the now-empty container.
Source/WebCore/Modules/highlight/Highlight.cpp
void Highlight::clearFromSetLike()
{
- for (auto& highlightRange : m_highlightRanges)
+ for (auto& highlightRange : std::exchange(m_highlightRanges, { }))
repaintRange(highlightRange->range());
m_highlightRanges.clear();
}
Patch Details
The single-line change replaces m_highlightRanges as the iteration target with std::exchange(m_highlightRanges, { }), which atomically moves the vector's contents into a temporary and leaves the member empty. The loop body (repaintRange(highlightRange->range())) is unchanged. The trailing m_highlightRanges.clear() is now a no-op (the member is already empty) but remains as defensive code.
Background
The CSS Custom Highlight API allows JavaScript to create Highlight objects containing AbstractRanges, which are registered with the document's HighlightRegistry. When a highlight is cleared (clearFromSetLike), each range must be repainted to remove its visual highlight. repaintRange() walks the DOM nodes intersecting the range and calls renderer->repaint() on each, which can synchronously trigger style recalculation and layout in WebKit's synchronous layout model.
std::exchange(obj, {}) is a C++ idiom that moves the value out of obj (replacing it with a default-constructed empty value) in a single expression and returns the original. In WebKit, this drain-before-iterate pattern is a well-established defensive idiom against re-entrant container modification.
Analysis
Iterator invalidation from re-entrant modification of a live container during a callback-invoking iteration loop.
Before the fix, clearFromSetLike() iterated directly over the live m_highlightRanges member while calling repaintRange() on each element. repaintRange() walks intersecting nodes and triggers renderer->repaint(), which can synchronously trigger style recalculation, layout, or other repainting side effects. These repaint callbacks could re-entrantly modify m_highlightRanges — for example by removing or adding highlight ranges through observer callbacks or other code paths that mutate the highlight set. This re-entrant modification is a re-entrancy boundary — a point where native code calls into layout/style machinery, which may synchronously re-enter and mutate object state before returning. Such modification would invalidate the iterator mid-loop, producing a use-after-free or out-of-bounds access on the vector's backing store. The ASAN crash signature (Highlight::clearFromSetLike; HighlightRegistry::clear; Document::commonTeardown) confirms this path is reachable during document teardown.
Aa Aaaaaaaa Aaaaa Aaaaaa a Aaaaaaaaaaa Aaaa Aaaaaaaa Aaaaaaa Aaa Aa Aaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaaaaa a Aaaaaaaaaa Aaaaaaaa Aaaaaa Aaa Aaaaaaaaaaaa Aaaaaaaaa Aa Aaaaa Aaaaaaaa Aaaaaaaaa Aaaaaa Aaaaaaaa Aaaa Aaaaaaaa Aaa Aaaaaaaaaaaaa Aaaaa Aaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aa Aaa Aaa Aa Aaaaaa Aaaaaaaa Aaaa Aaa Aaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaaa Aa Aaaaaaaaaa
Aa Aaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaa Aaa Aaaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaaa Aaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaa Aaaaa Aaaaa Aaaaaaa a Aaaa Aaaaaaaaa Aaa Aa Aaa Aaaa Aaaa Aaaaaa Aaaaaaa Aaa Aaaaa Aaaaaaaaaa a Aaaaa Aaaaaaaaaa Aaa Aaaaaa Aa Aaaaaaa Aaaaaaa Aa Aaaaaaa Aaa Aaaaaaaa Aaa Aaaaaaa a Aaaaaa Aaaaaaaaaaaa Aa a Aaaaaaaaaa Aaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaa Aaaaaaaaaa Aaaaaa Aaaaaa Aa Aaaaaaa Aa a Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaaa Aaaaaaa Aaaa Aaaaaaaa Aa Aaaaaaa Aaa Aaaaa Aaaaaa Aaaaaaa Aaaaaa Aaaaa Aa Aaaaaaaaa Aaa Aaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaa Aa Aaa Aaaaaaaa Aaaaaaaa Aa Aaaaaaaa Aaa Aaaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaaaa Aaaa Aaaaa Aaaaa Aaa Aaaaaaaa Aaaaa Aaa Aaaaa Aaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaaa Aaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaa Aaaaaaaa
Aaaaaaaa Aaaaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaa Aaaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaaaa a Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaa Aaaaaaa Aaaaa Aaaaaaaaa Aa Aaaaaaa Aaa Aaaaaaaaa Aaaaaaaa Aaa Aaaaaaa Aaaaaaaaaaa Aaaa Aaaaaaaa Aaa Aaaaaaa
🔒The ownership model and escalation potential of this iterator-invalidation bug are explored in depth
Subscribe to read more
Audit directions
a Aaaaaaaa Aaaaaaaaa a Aaaaaa Aaaaaaaaa Aaaaa Aaaaaaaa a Aaaaaaaa Aaaa Aaa Aaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaaa Aaa Aaaa Aaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaaa Aaa Aaaa Aaaa Aaaaa Aaa Aaa Aaa Aaa Aaaaa Aaaaa Aaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaaaaaaa Aa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaa Aaaa Aaaaaaaaa Aaaa Aaaaaaaaa Aaaaaaaaaaa a Aaaaaaaaaa Aaa Aaaa Aaaaaaa Aaaaa Aaaaaaaaaaaaa Aaaaaaa Aa Aaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaa
a Aaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaa Aaaaa Aaaaaa Aaaaaaaaa Aaaaaaaaaaa Aa Aaa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaaa a Aaaaaaaaaaaaaaaaaaaaa Aaaaaa a a Aaaaaaaaa Aaaa Aa Aaaaaaaa Aa Aa Aaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaaaaaa Aaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaa Aaaa Aa Aaaaaaaaaaa Aaaaa Aaa Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaaa Aaaaa Aaa Aaaaaaaaa Aa Aaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaa
a Aaaaaaaa Aaaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aa Aaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaa Aaaaaaa Aaaa Aaaaaaa Aaaaaaaaaa Aaaa Aaaaaaaaaa Aaaa Aaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaa
Aaaaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaaaa Aaaa Aaaaaaa Aaaaaaaaaaaaaaaa Aa Aaaaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaa Aaaaaa Aaaaa Aaaaaa Aaaa Aaaaaaaa Aaaaaa Aa Aaa Aaaaa Aaa Aaaa Aaaaa Aaaa Aaa Aaa Aaaaaaaaa Aaa Aaaaaaaaa Aa Aaa Aaaa Aaaaaaaaa Aaa Aaa Aaaaaaaaaaa Aaaaa Aaaaaaaa
🔒Multiple reusable audit patterns identified, with concrete starting points for variant discovery across WebCore
Subscribe to read more