← Chrome — 2026-W33

9d6494bbf8dd65cac5f99d0eb8706543215f9749  Destruct `cdm_factory_` before `frame_interfaces_` to avoid dangling pointer

severity low class UAF CVSS 4.0 signal score 5.1 mojo/ AI review CONFIRMED
Structural signals: msg_medium (+2.0), area:mojo/ (+1.8), surgical (+1.3)

The bug at a glance

A member-destruction-order bug left cdm_factory_ holding a dangling raw pointer to the already-destroyed frame_interfaces_ Remote during InterfaceFactoryImpl teardown; it manifested as error logs during DRM playback and is a destruction-time UAF in the media mojo service, not a demonstrated attacker-controlled corruption primitive.

During DRM video playback teardown the CDM factory could touch a Remote that had already been destroyed, a use-after-free at destruction that a defender cares about as a latent lifetime bug in a privileged media service process.

Root cause

C++ destroys class members in reverse order of declaration. cdm_factory_ (a std::unique_ptr) is constructed with a raw pointer to frame_interfaces_ (a mojo::Remote). In the original layout frame_interfaces_ was declared after cdm_factory_, so it was destroyed first, leaving cdm_factory_’s raw pointer dangling if cdm_factory_’s destructor (or any late callback) accessed it. The fix moves frame_interfaces_ above the ENABLE_MOJO_CDM block so cdm_factory_ is declared later and therefore destroyed first, ensuring frame_interfaces_ outlives its user.

Key code

Reorder members so frame_interfaces_ outlives cdm_factory_ (destroyed later/first)

+  mojo::Remote<mojom::FrameInterfaceFactory> frame_interfaces_;
+
 #if BUILDFLAG(ENABLE_MOJO_CDM)
   std::unique_ptr<CdmFactory> cdm_factory_;
 ...
-  mojo::Remote<mojom::FrameInterfaceFactory> frame_interfaces_;

Patch walkthrough

  • media/mojo/services/interface_factory_impl.h — Moves the frame_interfaces_ Remote member declaration before cdm_factory_ (and the ENABLE_MOJO_CDM block). Because members destruct in reverse declaration order, cdm_factory_ now destructs before frame_interfaces_, so the raw pointer cdm_factory_ holds to frame_interfaces_ is no longer dangling during teardown, eliminating the use-after-free.

Background

InterfaceFactoryImpl — A media mojo service object (runs in a privileged media/GPU service process, inferred) that vends media interfaces including the CDM factory used for DRM.

CdmFactory — Creates Content Decryption Modules for encrypted/DRM media and here stores a raw pointer to the frame interface factory it was constructed with.

C++ member destruction order — Class members are destroyed in the reverse of their declaration order, so a member that borrows another must be declared after it to be destroyed first.

Vulnerability window

  1. Reachability — Reached by playing DRM/encrypted media, which causes the media service to construct a CdmFactory referencing frame_interfaces_ (requires an EME/DRM-capable platform).
  2. Trigger — InterfaceFactoryImpl is destroyed; frame_interfaces_ is torn down before cdm_factory_ under the old declaration order.
  3. Primitive — cdm_factory_’s destructor/late use dereferences the freed frame_interfaces_ raw pointer, a use-after-free observed as DRM error logs.
  4. Escalation — No demonstrated escalation; destruction-order UAF in a service process with no shown attacker control over the freed contents (inferred).

Proof of concept

Conceptually: initiate DRM video playback so a CdmFactory is created holding a pointer to the frame interface factory, then cause the InterfaceFactoryImpl to be torn down (e.g. frame/renderer disconnect); under the old member order the factory outlived its referent’s destruction and accessed freed memory. Observed only as error logs, not a weaponized corruption.

Exploitation

  1. Setup — Start DRM playback to construct cdm_factory_ with a borrowed pointer to frame_interfaces_ (inferred).
  2. Teardown — Destroy the InterfaceFactoryImpl so frame_interfaces_ is freed before cdm_factory_ under the buggy order (inferred).
  3. UAF — cdm_factory_ touches the freed frame_interfaces_, a destruction-time use-after-free (inferred; manifested as error logs).

Detection & hunting

For defenders and detection engineers:

  • Member declaration order: a unique_ptr/object constructed with a raw pointer to another member declared below it — Audit classes where a borrowing member is declared before the member it borrows.
  • ASAN/error logs mentioning CdmFactory and FrameInterfaceFactory during media teardown — Correlate DRM playback shutdown with heap-use-after-free reports in the media service.

Audit directions

  • media/mojo/services and other mojo impls holding raw pointers between members — Verify borrowed-pointer members are declared after their owners so destruction order is safe.
  • Objects taking raw_ptr/raw pointers in constructors to sibling mojo::Remote members — Grep for constructor args that forward &other_member_ and check relative declaration order.

Before / after

Loading diff…