1d5f4f482b9e98c3dc83a921707b57875a7ba5ec [M150] Fix crash in CSSNumericValue.parse() with unsupported functions
The bug at a glance
Web-reachable renderer crash: a CSS calc() division expression simplifies to a unary kInvert node, and the binary-operator loop in CalcToNumericValue() reads a non-existent second operand, producing an out-of-bounds access. Impact is denial of service (crash), with no evidence of controllable corruption in the diff.
Any page can call CSSNumericValue.parse() (Typed OM) or trigger the same simplification path via a crafted calc() string; a defender cares because it is a reliably reachable, unauthenticated renderer-process crash.
Root cause
Division expressions such as ‘1 / sign(10em)’ or division by zero are simplified by the calculation tree into a kInvert node, which is a unary operator with a single operand. CalcToNumericValue() previously fell through to a loop that assumed binary operators and accessed the second operand, reading past the end of the operands vector (OOB). The patch handles IsInvert() explicitly (asserting exactly one operand) and adds null-checks so sub-expressions that fail to convert to a valid CSSNumericValue return nullptr instead of being dereferenced/indexed.
Key code
Explicit unary kInvert handling plus null propagation prevents OOB second-operand access
if (const auto& node = To<CSSMathExpressionOperation>(root);
node.IsInvert()) {
DCHECK_EQ(node.GetOperands().size(), 1u);
CSSNumericValue* value = CalcToNumericValue(*node.GetOperands()[0]);
if (!value) {
return nullptr;
}
return CSSMathInvert::Create(value);
}
Patch walkthrough
third_party/blink/renderer/core/css/cssom/css_numeric_value.cc— Adds an explicit IsInvert() branch that treats the node as unary (one operand) and returns early, so the downstream binary-operator loop never indexes a missing second operand; also adds null checks after every recursive CalcToNumericValue() call (min/max/step, math-function operands, and the trailing cur_node push) so an unconvertible sub-expression yields nullptr instead of being used, eliminating the OOB/null-deref crash.
Background
Typed OM CSSNumericValue.parse() — A web-exposed API that parses a CSS numeric string into CSSNumericValue objects, reachable from any script.
CSSMathExpressionOperation / kInvert — Internal calc() tree node; kInvert is a unary operator representing 1/x created when division is simplified.
CalcToNumericValue() — Converts a simplified calc expression tree into CSSNumericValue objects, iterating operands by operator arity.
Vulnerability window
- Reachability — Script calls CSSNumericValue.parse() with a calc() containing a division (or division by zero).
- Trigger — The calc simplifier rewrites the division into a unary kInvert node.
- Primitive — CalcToNumericValue() accesses the kInvert node’s second operand, reading out of bounds on the operands vector (inferred to be the crash site).
- Escalation — Results in a renderer crash / DoS; no memory-corruption primitive is demonstrated in the diff (inferred).
Proof of concept
Conceptually, call CSSNumericValue.parse() with a calc() string whose division simplifies to an invert node combined with an unsupported function, e.g. a value like ‘calc(1 / sign(10em - 10rem))’ as shown in the added WPT; pre-patch this crashed, post-patch it throws SyntaxError.
Exploitation
- Reach — Load a page that calls the Typed OM parse entry point with attacker-controlled calc text.
- Crash — Induce the unary-node OOB access to crash the renderer (DoS); further escalation would require demonstrating controllable OOB content, not shown (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for ‘GetOperands()[1]’ or binary-operand indexing without an arity check in css_numeric_value.cc — Hunt for operand-vector indexing that assumes binary operators without checking IsInvert()/operand count.
- crash signature in CalcToNumericValue with CSSMathExpressionOperation — Correlate renderer crash reports mentioning calc/numeric-value conversion with division or sign()/unsupported functions in page CSS.
Audit directions
- third_party/blink/renderer/core/css/cssom/ conversion helpers — Review every site that iterates calc tree operands for unchecked arity assumptions and missing null-propagation after recursive conversion.
- calc simplification producing unary nodes (kInvert, kNegate) — Confirm all consumers of simplified trees handle unary operators explicitly.