← Chrome — 2026-W37

9f9aa5ace61edb4eb5c49a34aed7d578d85b8af0  [gap-decorations] Fix crash with huge row gaps

severity low class DoS CVSS 5.3 signal score 3.8 third_party/blink/renderer/core/ AI review CONFIRMED
Structural signals: area:third_party/blink/renderer/core/ (+2.5), surgical (+1.3)

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

  1. Reachability — Any page can style a block-fragmented grid (e.g. multicol container) with an enormous row-gap and line-height.
  2. Trigger — The oversized gap value saturates LayoutUnit during per-fragmentainer offset arithmetic.
  3. Primitive — The saturated spillover is written into the persistent cumulative_gap_offset_adjustment, corrupting subsequent fragments’ geometry.
  4. 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

  1. Setup — Attacker serves a page with the crashing CSS; no user interaction required.
  2. 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.

Before / after

Loading diff…