4b3e281393b8cce41eedc0c6ac66de2a739121f1 [gpu] Safely handle in-process SharedImageInterface teardown
The bug at a glance
This is a preventive lifetime-ownership refactor: the use-after-free it guards against only materializes when the not-yet-default UseStrongRefToSharedImageInterface feature is enabled, so no exploitable UAF exists in a stock build today; it is a prerequisite hardening rather than a live fix.
A defender cares because it closes a latent GPU-process UAF before the strong-ref feature ships: once ClientSharedImage can keep a SharedImageInterfaceInProcess alive past its manager, SIIIP’s destructor would dereference an already-destroyed task sequence.
Root cause
SharedImageInterfaceInProcess (SIIIP) held its SingleTaskSequence as a raw_ptr owned by the manager object (InProcessCommandBuffer, SharedImageInterfaceProvider, GmbVideoFramePoolContext). Those managers destroyed the task sequence during their own teardown. With UseStrongRefToSharedImageInterface, a strong ref in ClientSharedImage could outlive the manager and keep SIIIP alive, so SIIIP’s later destruction would use the already-freed task sequence (use-after-free). The patch transfers ownership of the SingleTaskSequence into SIIIP (unique_ptr member, created-and-moved in via Create()), so the sequence lives exactly as long as SIIIP; managers now schedule teardown through sii_in_process_->task_sequence() and drop their raw sequence members. CHECK(task_sequence_) and a null-guard in MarkContextLostOnGpuThread() add defense in depth.
Key code
SIIIP now owns its task sequence so it cannot be freed before SIIIP is destroyed
- raw_ptr<SingleTaskSequence> task_sequence_;
+ // Used to schedule work on the gpu thread.
+ const std::unique_ptr<SingleTaskSequence> task_sequence_;
Patch walkthrough
gpu/command_buffer/service/shared_image_interface_in_process.h— Changes task_sequence_ from a raw_ptr aliasing manager-owned memory to an owning const unique_ptr and adds a task_sequence() accessor, making SIIIP’s scheduling sequence outlive any ref that keeps SIIIP alive.gpu/command_buffer/service/shared_image_interface_in_process.cc— Create()/ctor take unique_ptr by value and CHECK it is non-null; MarkContextLostOnGpuThread() guards context_state_ before use, preventing a null/stale deref during teardown ordering.gpu/ipc/in_process_command_buffer.cc— Creates the sequence locally and moves it into SIIIP instead of holding a GpuTaskSchedulerHelper; reorders destruction so task_sequence_ is cleared and shared_image_interface_ (now the sequence owner) is released last.components/viz/service/frame_sinks/shared_image_interface_provider.cc/.h— Moves the SchedulerSequence into SIIIP via the OnGpu callback and drops the owned scheduler_sequence_ member, so provider teardown can no longer free the sequence out from under a surviving SIIIP.components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc— Hands sequence ownership to SIIIP at init and schedules its destructor task through sii_in_process_->task_sequence() rather than a locally owned sequence_, removing the premature sequence destruction in the context dtor.
Background
SharedImageInterfaceInProcess (SIIIP) — In-process implementation of the GPU SharedImageInterface that schedules shared-image work onto a GPU task sequence.
SingleTaskSequence / SchedulerSequence — Serializes tasks onto the GPU thread; SIIIP needs it alive for both initialization and GPU-thread destruction work.
UseStrongRefToSharedImageInterface — A not-yet-default feature that would let ClientSharedImage hold a strong scoped_refptr to SIIIP, allowing SIIIP to outlive its creating manager.
ClientSharedImage — Client-side handle to a shared image whose strong ref would extend SIIIP lifetime under the new feature.
Vulnerability window
- Reachability — Not reachable in a stock build: the UAF only arises when UseStrongRefToSharedImageInterface is enabled (not the current default), which is why this lands as a prerequisite.
- Trigger — With the feature on, a ClientSharedImage strong ref keeps SIIIP alive past its manager’s destruction (inferred — feature not yet enabled).
- Primitive — SIIIP’s destructor schedules/uses the task sequence after the manager freed it, a use-after-free on the GPU/scheduler sequence (inferred).
- Escalation — GPU-process memory corruption from the dangling sequence could be shaped toward control-flow hijack (inferred, future/hypothetical).
Proof of concept
No current PoC is possible because the triggering feature is disabled; conceptually it would require enabling UseStrongRefToSharedImageInterface and keeping a ClientSharedImage strong ref alive while the owning manager is destroyed so SIIIP’s teardown touches a freed task sequence.
Exploitation
- Precondition — UseStrongRefToSharedImageInterface must be enabled (inferred — not default today).
- Lifetime skew — Retain a ClientSharedImage strong ref to SIIIP beyond its manager’s lifetime so the manager frees the task sequence first (inferred).
- Use-after-free — SIIIP destruction dereferences the freed SingleTaskSequence (inferred).
Detection & hunting
For defenders and detection engineers:
- grep gpu/ components/viz for raw_ptr/raw_ptr to scheduler sequences whose lifetime is tied to a separate owner — Flag ref-counted objects that schedule on a sequence they do not own, especially where a strong client ref can outlive the owner.
Audit directions
- Other ref-counted GPU objects (command buffers, shared-image factories) that hold raw_ptr to externally owned task sequences or runners — Verify the scheduling sequence is owned by (or outlives) every object that may be kept alive by a client strong ref, mirroring this ownership move.