← Chrome — 2026-W33

197052359826ba5d3b11842aeaf461235a2f9424  [Code health] Remove dangling pointer in QuicChromiumClientSession

severity medium class UAF CVSS 5.1 signal score 6.7 net/ AI review CONFIRMED
Structural signals: uaf_lifetime (+2.2), msg_medium (+2.0), area:net/ (+1.2), surgical (+1.3)

The bug at a glance

The code bound and later used a raw QuicPacketWriter* via UnsafeDanglingUntriaged that could be replaced and destroyed during a prior migration, leaving MigrateSessionOnWriteError operating on a dangling pointer; it is a genuine use-after-free class, but it sits on the write-error/network-migration path and the pointer was used only for an identity comparison, limiting controllability.

A network-positioned attacker (or adverse network conditions) that induces write errors and triggers rapid connection/socket migrations could race the writer’s replacement against the deferred MigrateSessionOnWriteError task, turning a QUIC migration edge case into a dangling-pointer use.

Root cause

On a write error, the session posted MigrateSessionOnWriteError bound to connection()->writer() wrapped in base::UnsafeDanglingUntriaged. If a migration (MigratePath) replaced and destroyed that writer before the posted task ran, the task held a dangling QuicPacketWriter*; comparing writer != connection()->writer() and any callback use then touched freed memory. The patch replaces the raw-pointer capture with a monotonic packet_writer_generation_ counter (incremented after each MigratePath) and compares generations instead, so a stale task simply aborts without ever referencing the freed writer.

Key code

Dangling writer pointer replaced by a generation counter

-          base::UnsafeDanglingUntriaged(connection()->writer())));
+                     packet_writer_generation_));
...
-  if (writer != connection()->writer() ||
+  if (writer_generation != packet_writer_generation_ ||

Patch walkthrough

  • net/quic/quic_chromium_client_session.cc — Stops binding the raw connection writer pointer (UnsafeDanglingUntriaged) into the posted migration task and instead passes packet_writer_generation_, comparing generations to detect a replaced writer; increments the generation after MigratePath so a stale task aborts without dereferencing freed memory.
  • net/quic/quic_chromium_client_session.h — Changes MigrateSessionOnWriteError’s signature from QuicPacketWriter* to uint64_t writer_generation and adds the packet_writer_generation_ member, removing the dangling-pointer parameter from the API surface.

Background

QuicChromiumClientSession — Chrome’s net-stack object managing a QUIC connection, including connection/socket migration on network changes and write errors.

UnsafeDanglingUntriaged — A base annotation that opts a raw pointer out of MiraclePtr dangling-pointer protection, used as a temporary suppression for known-risky pointers.

Connection migration — QUIC’s ability to move a session to a new network path/socket, which can replace and destroy the previous QuicPacketWriter.

Vulnerability window

  1. Reachability — A live QUIC session with connection-migration-v2 enabled encounters a packet write error (network-path dependent, e.g. interface change or adverse network).
  2. Trigger — HandleWriteError posts MigrateSessionOnWriteError bound to the current writer, and a concurrent MigratePath replaces/destroys that writer before the task runs (inferred race window).
  3. Primitive — The deferred task holds a dangling QuicPacketWriter*, yielding a use-after-free read/compare and potential callback use on freed memory (inferred).
  4. Escalation — Converting the dangling read into a controlled reuse/corruption would require heap grooming of the freed writer allocation, which the diff neither shows nor enables (inferred).

Proof of concept

Conceptually, establish a QUIC session with connection migration enabled, induce a socket write error, and race a network-change-driven MigratePath so the original writer is freed before the posted MigrateSessionOnWriteError task executes; the pre-patch build would then operate on the freed writer. No exploit code provided.

Exploitation

  1. Setup — Attacker influences network conditions to force QUIC write errors and migrations against a victim session (inferred).
  2. Race — Timing is arranged so writer replacement/destruction completes before the deferred migration task runs (inferred).
  3. Use — Deferred task touches the freed writer; turning this into memory corruption requires reclaiming the freed allocation with controlled data (inferred).

Detection & hunting

For defenders and detection engineers:

  • grep for base::UnsafeDanglingUntriaged and UnsafeDangling across net/ and anywhere a raw pointer is bound into a PostTask/BindOnce — Flag deferred tasks that capture a raw pointer to an object whose lifetime can end before the task runs; prefer weak pointers, generation counters, or ownership transfer.
  • ASAN/MiraclePtr crash reports in QuicChromiumClientSession::MigrateSessionOnWriteError — Hunt use-after-free reports on the write-error migration path in net QUIC fuzzing and canary crash telemetry.

Audit directions

  • Remaining UnsafeDanglingUntriaged/UnsafeDangling call sites in net/ and QUIC session migration code — Audit each suppression for a replace-then-use lifetime hazard and migrate it to a generation counter or weak reference as done here.
  • PostTask callbacks capturing connection()/writer()/socket raw pointers — Look for other migration or error-handling tasks that assume the captured transport object survives until the task executes.

Before / after

Loading diff…