← All issues

[4] WebCore::Color: MTE hardening for compact pointer in destructor

Severity: Low | Component: WebCore graphics (Color value type) | d474526

Rated Low because the diff is defense-in-depth hardening that scrubs a compact-pointer-bearing word in Color's destructor. It does not fix an observable trigger but shrinks the amplification surface of a hypothetical upstream UAF on a Color value; escalation requires an independent UAF that the diff does not exhibit.

WebCore::Color is made of a single field that contains flags in the upper bits and can contain a pointer to an OutOfLineComponents instance. This compact pointer is untagged by libpas, so it must be manually cleared to prevent any security issues if the Color object is freed and later observed. secureZeroBytes and secureZeroSpan are annotated NODELETE so the safer-cpp static analyzer can prove that calling them from ~Color() does not run any destructor or free memory.

Source/WebCore/platform/graphics/Color.h

inline Color::~Color()
{
if (isOutOfLine())
asOutOfLine().deref();
+ secureZeroBytes(m_colorAndFlags);
}

Source/WTF/wtf/StdLibExtras.h

template<typename T, std::size_t Extent>
-void secureZeroSpan(std::span<T, Extent> destination)
+void NODELETE secureZeroSpan(std::span<T, Extent> destination)
...
-template<typename T> void secureZeroBytes(T& object)
+template<typename T> void NODELETE secureZeroBytes(T& object)

Color::~Color() is extended to call secureZeroBytes(m_colorAndFlags) after the existing asOutOfLine().deref(), ensuring the compact pointer/flags word is overwritten before the object's storage is released. In wtf/StdLibExtras.h, secureZeroSpan and secureZeroBytes gain the NODELETE annotation so WebKit's safer-cpp static analyzer can prove that invoking them from a destructor does not itself transitively destruct other objects or free memory.

Failure to scrub a pointer-bearing field in a destructor, leaving an exploitable residue if the freed object is reached via use-after-free.

MTE (Memory Tagging Extension) is an ARMv8.5 hardware feature where each allocation is tagged with a 4-bit color, and pointer dereferences trap when the pointer's tag does not match the memory's tag. libpas is WebKit's userspace allocator; it integrates with MTE to retag memory on free, which causes most dangling pointers to fault on access. A compact pointer is a pointer stored alongside other bits in a single word — here, m_colorAndFlags holds a pointer to OutOfLineComponents in the upper bits plus flag bits. Because the bits are not stored as a normal tagged pointer, libpas's MTE retagging logic does not automatically clear or retag the value when the containing object is freed.

NODELETE is a WebKit safer-cpp annotation declaring that a function will not transitively run any destructor or free memory, which lets the static analyzer admit calls to it from contexts that must not re-enter allocator code. secureZeroBytes is a zeroing primitive whose write is guaranteed not to be optimized away by the compiler, intended for scrubbing residual capability-bearing words.

WebCore::Color is a pervasive value type used in CSS parsing, painting, canvas, and SVG. Its layout is a single word m_colorAndFlags that either packs an inline sRGBA color plus flags, or stores a tagged pointer to a ref-counted OutOfLineComponents carrying wide-gamut/float color data.

The hardening gap is the absence of a defensive scrub in a destructor whose remaining residue is a usable capability. Before the fix, ~Color() released the OutOfLineComponents reference when out-of-line but left m_colorAndFlags — the single compact word that, for out-of-line colors, contains the pointer to the just-derefed OutOfLineComponents — intact in the dead Color's storage. Color is TZone-allocated, and because the compact pointer is not tagged by libpas's MTE machinery, the freed slot retains a recognizable pointer value even on MTE-enabled hardware.

🔒

The lifetime and residual-capability implications of compact pointer fields under MTE are analysed in depth, including how this hardening reshapes the value of a hypothetical upstream bug.

Subscribe to read more

🔒

Multiple reusable audit patterns identified for compact-pointer destructor scrubbing and MTE retagging gaps, with concrete starting points across WTF and WebCore graphics.

Subscribe to read more