9f9aa5ace61edb4eb5c49a34aed7d578d85b8af0 [gap-decorations] Fix crash with huge row gaps
The bug at a glance
A LayoutUnit saturation during grid fragmentation produces a corrupted gap-offset adjustment that persists in the break token and corrupts later fragments, culminating in a null dereference and renderer crash; the outcome shown is a crash with no demonstrated memory-corruption primitive, so impact is a DoS.
An attacker-controlled page can trigger a renderer crash purely with CSS (an extremely large row-gap on a block-fragmented grid), giving a reliable, no-interaction denial of service against the rendering process.
Root cause
During grid fragmentation, next_row_offset/last_gap_end_offset are computed from set offsets plus accumulated adjustments. When a row-gap value exceeds LayoutUnit::Max, the arithmetic saturates (clamps) so the computed spillover past the fragmentainer edge is a fabricated, too-small number. That bogus adjustment is folded into cumulative_gap_offset_adjustment, which persists across fragmentainers in the break token, corrupting the geometry of subsequent fragments and eventually causing a null pointer dereference. The fix bails out of the adjustment when either offset MightBeSaturated(), so a value that cannot be represented safely does not poison later fragments.
Key code
Bail out of spillover adjustment when the gap offset has saturated
if (last_gap_end_offset.MightBeSaturated() ||
next_row_offset.MightBeSaturated()) {
return;
}
Patch walkthrough
third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc— Adds a saturation guard before applying the gap-offset spillover adjustment. Because the adjustment feeds cumulative_gap_offset_adjustment that survives in the break token across fragmentainers, a saturated (clamped) value previously propagated corrupted geometry into later fragments; returning early prevents the corruption and the downstream null deref.third_party/blink/web_tests/external/wpt/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-038-crash.html— Regression crash test using columns:0px plus a grid with row-gap:1.05e+10px and line-height:3.40282e+38px to force LayoutUnit saturation and reproduce the crash.
Background
LayoutUnit — Blink’s fixed-point layout coordinate type with a saturating max (LayoutUnit::Max) and a MightBeSaturated() query.
Grid fragmentation / break token — Mechanism that splits grid layout across fragmentainers (e.g. columns), carrying state like cumulative gap-offset adjustments between fragments via a break token.
Gap decorations — CSS feature that paints decorations in row/column gaps, requiring per-fragment gap offset computation during fragmentation.
Vulnerability window
- Reachability — Any page can style a block-fragmented grid (e.g. multicol container) with an enormous row-gap and line-height.
- Trigger — The oversized gap value saturates LayoutUnit during per-fragmentainer offset arithmetic.
- Primitive — The saturated spillover is written into the persistent cumulative_gap_offset_adjustment, corrupting subsequent fragments’ geometry.
- Escalation — Corrupted fragment state leads to a null pointer dereference and renderer crash (inferred: no further memory-corruption primitive demonstrated).
Proof of concept
Conceptually, render a multicol container (columns:0px) holding a display:grid element with a row-gap near/above LayoutUnit’s representable max (e.g. ~1e10px) and a huge line-height, forcing block fragmentation; the saturated gap offset corrupts a later fragment and crashes the renderer. The committed WPT crash test illustrates the trigger shape.
Exploitation
- Setup — Attacker serves a page with the crashing CSS; no user interaction required.
- Impact — Renderer process crashes (tab/iframe DoS); no sandbox escape or data disclosure shown (inferred).
Detection & hunting
For defenders and detection engineers:
- weggli/grep for LayoutUnit arithmetic feeding break-token-persisted adjustments without MightBeSaturated() checks — Hunt fragmentation code that stores computed offsets into cumulative/persistent adjustment fields; flag any lacking a saturation guard.
- Crash reports with null deref in grid gap-decoration fragmentation — Correlate renderer crashes referencing GridLayoutAlgorithm gap-offset paths with pages using large row/column gaps.
Audit directions
- Column-gap and other fragmentation offset paths — Check the analogous column-gap spillover and any other LayoutUnit value persisted across fragmentainers for the same saturation hazard.
- LayoutUnit saturation in layout math — Audit layout algorithms that subtract/accumulate LayoutUnit offsets where one operand can reach LayoutUnit::Max.