76749c84fc57ce8d2cf0263b5b47c594fe628e07 [Media] Simplify context loss check when creating StaticBitmapImages
Triage note: Replaces the accelerated-only IsGpuContextLost() check with an unconditional !IsValid() guard when creating StaticBitmapImages from video. Defensive hardening (bug 40230609); watch, not exploitable.
The bug at a glance
The pre-patch guard only revalidated the cached snapshot provider when it was accelerated and its GPU context was lost; a non-accelerated (software) provider whose context had become invalid for other reasons was reused without a validity check. The realistic outcome is drawing/reading through a provider in an invalid state, which can manifest as a crash or use of a stale/invalid resource rather than a controllable use-after-free. The referenced bug (40230609) is an old, low-CVSS hardening item and the author frames it as ‘simplify’, not as fixing an active exploit. No test, no attacker-controlled corruption path is shown in the diff. Low/3.7 reflects a latent-safety hardening of a reuse guard with a plausible-but-unproven UAF/invalid-use ceiling.
A one-line guard replacement disguised as cleanup (‘Simplify context loss check’). The security substance is that the old condition scoped context-loss revalidation to the accelerated case only, leaving a hole for non-accelerated providers with invalid contexts to be reused across video-frame snapshots. IsValid() is a superset check covering both accelerated and non-accelerated invalidity.
Root cause
HTMLVideoElement caches a CanvasResourceProvider (snapshot_provider_) to produce StaticBitmapImages from decoded video frames, reusing it across calls when parameters match to avoid reallocation. The reuse gate rejected the cached provider only if it was null, OR if it was accelerated AND its GPU context was lost, OR if allow-accelerated/size/color-space changed. The flaw: (snapshot_provider_->IsAccelerated() && snapshot_provider_->IsGpuContextLost()) never fires for a non-accelerated provider, so a software provider that had become invalid (its underlying context/resources no longer usable) passed the gate and was reused. The patch replaces that compound accelerated-only clause with a single !snapshot_provider_->IsValid(), which validates the provider regardless of acceleration. If the provider is invalid it is discarded and recreated instead of drawn into, closing the reuse-of-invalid-resource window.
Key code
Replace accelerated-only context-lost check with an unconditional validity check
- if (!snapshot_provider_ ||
- (snapshot_provider_->IsAccelerated() &&
- snapshot_provider_->IsGpuContextLost()) ||
+ if (!snapshot_provider_ || !snapshot_provider_->IsValid() ||
allow_accelerated_images != allow_accelerated_images_ ||
dest_size != snapshot_provider_->Size() ||
dest_color_space != snapshot_provider_->GetColorSpace() ||
Patch walkthrough
third_party/blink/renderer/core/html/media/html_video_element.cc— In the snapshot-provider reuse guard, the two-line accelerated-and-context-lost condition is collapsed to !snapshot_provider_->IsValid(). IsValid() is expected to report invalidity for both accelerated (GPU context lost) and non-accelerated (software provider no longer usable) cases, so any invalid cached provider now forces recreation before it is drawn into to produce the StaticBitmapImage.
Background
CanvasResourceProvider — Blink abstraction owning the backing surface (GPU or software) used to rasterize into. It exposes IsAccelerated(), IsGpuContextLost(), and IsValid(); IsValid() is the broad correctness predicate covering all invalidity causes.
StaticBitmapImage from video — HTMLVideoElement produces snapshots (for drawImage to canvas, createImageBitmap, etc.) by drawing the current media frame through snapshot_provider_. Reusing the provider avoids per-call allocation.
Context loss vs validity — GPU context loss is one cause of invalidity; a provider can also be invalid without being accelerated (e.g. surface allocation/state failure). The old guard conflated ‘invalid’ with ‘accelerated + context lost’.
Bug 40230609 — A long-standing (legacy-numbered) hardening item about context-loss handling in this area; the low score and ‘simplify’ framing indicate defensive cleanup rather than an in-the-wild bug.
Vulnerability window
- Introduced — The reuse guard scoped context-loss revalidation to the accelerated case, leaving non-accelerated invalidity unchecked. Long-standing per bug 40230609.
- Fixed — Landed 2026-01-08, refs/heads/main@{#1566132}, auto-submitted as a simplification.
Proof of concept
No test or exploit code ships in this diff. Repro would require driving HTMLVideoElement snapshot generation with a non-accelerated CanvasResourceProvider and inducing provider invalidity (surface/context failure) between snapshot calls while size/color-space/accel flags stay constant, then observing reuse of the invalid provider. Whether that yields a controllable use-after-free versus a benign recreate/crash depends on internal provider lifetime, which the diff does not expose. No exploit demonstrated; treat the UAF class as latent/plausible, not proven.
Exploitation
- Reachability — Script can repeatedly snapshot a (drawImage/createImageBitmap) to keep the cached provider path warm, and can influence acceleration via allow-accelerated flags and platform conditions.
- Trigger — The attacker needs the provider to become invalid while the reuse parameters remain unchanged, which is the ambient part they cannot reliably force, limiting practicality.
- Ceiling — Most likely a crash or use of a stale surface. A weaponizable UAF is not demonstrated and would need a separate lifetime bug to be controllable.
Detection & hunting
For defenders and detection engineers:
- Acceleration-scoped validity checks — Flag guards of the form (IsAccelerated() && IsGpuContextLost()) used to decide reuse; they miss non-accelerated invalidity. Prefer a single IsValid().
- Cached provider reuse gates — Audit any code caching a CanvasResourceProvider/surface across calls to ensure every reuse revalidates the object unconditionally before drawing.
Audit directions
- Other CanvasResourceProvider reuse sites — Grep for IsGpuContextLost() gated by IsAccelerated() across blink (canvas, imagebitmap, media snapshotting) and replace with IsValid() where reuse safety depends on it.
- Provider lifetime — Determine whether reusing an invalid provider can actually free-then-use backing memory; if so, this class warrants re-rating upward.
- IsValid() semantics — Confirm IsValid() truly covers all invalidity causes for both software and GPU providers so the collapsed check is not narrower than intended.