e16e582198885c627a5ffa4ca5e11f56e6e6030e [viz] Add checks to reject invalid VTResourceId in SharedElementQuad
The bug at a glance
A fuzzer-discovered crash in the privileged viz/GPU process: an invalid (default-constructed) ViewTransitionElementResourceId arriving over mojo from a (potentially compromised) renderer was not validated, reaching SharedElementDrawQuad handling in surface_animation_manager and tripping an invalid-token check; the fix rejects it at the IPC boundary and defensively in-method.
A compromised or buggy renderer can send a SharedElementDrawQuad with an invalid element_resource_id across the compositing mojo interface to the GPU process, causing a crash (DoS of the GPU process) and probing a trust-boundary deserialization path.
Root cause
SharedElementQuadState mojom deserialization previously accepted any value ReadElementResourceId produced without checking element_resource_id.IsValid(), so an invalid TransitionToken/resource id flowed into SurfaceAnimationManager where downstream code assumes validity, triggering the fuzzer at surface_animation_manager.cc:272. The patch adds an IsValid() check in the mojo traits Read() (rejecting the message and setting a deserialization crash key) and a defensive guard in surface_animation_manager that logs and returns early on an invalid id. It also reorders the per-quad deserialization so the SharedQuadState is read before quads.Read(i, quad), tightening the deserialization sequence.
Key code
Reject invalid resource id at the mojo deserialization trust boundary
if (!shared_element_quad->element_resource_id.IsValid()) {
viz::SetDeserializationCrashKeyString(
"Invalid ViewTransitionElementResourceId in SharedElementDrawQuad");
return false;
}
Patch walkthrough
services/viz/public/cpp/compositing/quads_mojom_traits.cc— Adds an IsValid() check after ReadElementResourceId in the SharedElementQuadState mojo trait so an invalid resource id causes deserialization failure instead of entering the compositor with a bad token.components/viz/service/transitions/surface_animation_manager.cc— Defensive in-method guard: if the SharedElementDrawQuad’s element_resource_id is invalid, log and return early (treat as handled) instead of proceeding to texture/lookup logic that assumes a valid id (the fuzzer’s crash site).services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc— Reorders deserialization so SharedQuadState is read before quads.Read(i, quad), ensuring quad state is established before the quad is populated during IPC decode.services/viz/public/cpp/compositing/mojom_traits_unittest.cc— Adds tests confirming a valid SharedElementDrawQuad round-trips and an invalid (default-constructed) resource id fails SerializeAndDeserialize, locking in the new validation.
Background
viz / SurfaceAnimationManager — GPU-process compositing service code that manages view-transition shared-element surfaces and quads.
ViewTransitionElementResourceId — Identifier (carrying a TransitionToken) tying a SharedElementDrawQuad to a view-transition element resource; can be default-constructed into an invalid state.
mojom StructTraits Read() — Deserialization hook for IPC messages where untrusted cross-process input must be validated before use.
Vulnerability window
- Reachability — A renderer submits a compositor frame containing a SharedElementDrawQuad over the compositing mojo interface to viz.
- Trigger — The quad carries an invalid/default ViewTransitionElementResourceId that was not validated during deserialization.
- Primitive — SurfaceAnimationManager processes the quad assuming a valid id, reaching the fuzzer-flagged failure/crash at line 272 (DoS of the GPU process).
- Escalation — Beyond a crash, feeding unvalidated resource ids into surface lookups could enable confusion of which element/surface is drawn, though no memory-corruption path is shown (inferred).
Proof of concept
Conceptually, from a renderer (or a compromised one) construct a compositor render pass containing a SharedElementDrawQuad whose element_resource_id is left at its default-constructed/invalid value and submit the frame to viz; pre-patch this bypasses validation and reaches SurfaceAnimationManager. No exploit code is provided.
Exploitation
- Setup — Compromise or instrument a renderer to craft arbitrary CompositorRenderPass mojo messages (inferred).
- Craft — Embed a SharedElementDrawQuad with an invalid ViewTransitionElementResourceId (inferred).
- Submit — Send the frame over the compositing interface so viz deserializes and processes it (inferred).
- Impact — Pre-patch, trigger the crash/invalid-token path in the GPU process (DoS) (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for ‘.Read’ IPC traits that populate ids/tokens without a following IsValid()/validity check — Audit mojom StructTraits Read() methods for resource-id/token fields consumed without validation before being handed to service code.
- LOG(ERROR) ‘Invalid ViewTransitionElementResourceId’ / crash-key ‘Invalid ViewTransitionElementResourceId’ — Monitor GPU-process logs and deserialization crash keys for this signal indicating malformed compositor input.
Audit directions
- services/viz/public/cpp/compositing/quads_mojom_traits.cc and sibling quad traits — Check every DrawQuad subtype’s mojo Read() for missing validity checks on ids, tokens, resource handles, and rects before they reach viz service logic.
- components/viz/service/transitions/* — Review other SurfaceAnimationManager entry points that dereference element_resource_id / tokens for the same validity assumption.