← Chrome — 2026-W33

e8736f9d1a1d77dc60fabfd4e0a50f46e4e834fd  [mojo] Guard VM buffer address access in ChannelMac

severity low class DoS CVSS 3.5 signal score 4.1 mojo/ AI review CONFIRMED
Structural signals: msg_soft (+1.0), area:mojo/ (+1.8), surgical (+1.3)

The bug at a glance

A shutdown race nulls the ChannelMac VM buffer address (via receive_buffer_.reset()/send_buffer_.reset()), and a pending Mach-port read/write callback then dereferences address 0 or passes a null header to mach_msg, producing a reproducible crash (SIGSEGV) but no attacker-controlled memory corruption.

An attacker who can influence the timing of a mojo channel teardown on macOS could race a pending I/O callback against buffer deallocation to crash the process; a defender cares because it is a renderer/broker-process liveness and stability issue rather than a corruption primitive.

Root cause

During ChannelMac shutdown, receive_buffer_.reset() and send_buffer_.reset() deallocate the backing VM page and set the buffer address to 0. If an in-flight Mach-port read event (ReceiveMessages path) or a queued write callback (SendPendingMessagesLocked / SendMessageLocked) runs during or after this teardown, the code builds a base::BufferIterator over reinterpret_cast<char*>(address()==0) with the old size, so it dereferences null or hands a null header to mach_msg. The fix adds early-return guards checking send_buffer_.address() and receive_buffer_.address() before any buffer access, mirroring ChannelLinux’s defensive validation so callbacks exit gracefully.

Key code

Guard VM buffer address before building BufferIterator / calling mach_msg

if (!send_buffer_.address()) {
  return false;
}
...
if (!receive_buffer_.address()) {
  return;
}

Patch walkthrough

  • mojo/core/channel_mac.cc — Adds address-validity guards at the start of SendPendingMessagesLocked, SendMessageLocked, and the receive handler so that a callback firing during/after reset() returns early instead of dereferencing a freed (address-0) VM buffer or passing a null header to mach_msg.

Background

mojo ChannelMac — The macOS-specific mojo IPC channel implementation that shuttles messages between processes using Mach ports and VM-page-backed send/receive buffers.

base::mac VM buffer (ScopedMachVM) — A buffer backed by an allocated Mach VM page whose reset() deallocates the page and zeroes the reported address().

Vulnerability window

  1. Reachability — Reachable on macOS whenever a mojo channel is torn down (e.g. process/connection shutdown) with I/O callbacks still pending; ordinary operation, no special flag or gesture needed.
  2. Trigger — A pending Mach-port read event or queued write callback executes after receive_buffer_.reset()/send_buffer_.reset() has nulled the buffer address during shutdown (inferred ordering).
  3. Primitive — Null-pointer dereference / null mach_msg header producing EXC_BAD_ACCESS / SIGSEGV, i.e. a crash only.
  4. Escalation — No escalation path; the access is to address 0 with no attacker-controlled offset, so it is a denial-of-service rather than a corruption primitive (inferred).

Proof of concept

Conceptually, drive a mojo connection over the macOS channel while rapidly initiating teardown so that an outstanding send or Mach-port receive callback is delivered after the buffers have been reset to address 0; the subsequent buffer access crashes. No exploit code provided.

Exploitation

  1. Timing — Induce channel shutdown while I/O callbacks remain queued so the reset() and the callback interleave (inferred).
  2. Impact — Process crash from null dereference; not weaponizable into code execution from the diff alone (inferred).

Detection & hunting

For defenders and detection engineers:

  • weggli: buffer address cast reinterpret_cast<char>(->address()) without a preceding if(!->address()) guard* — Hunt for ScopedMachVM/VM-buffer address() consumers that build BufferIterator or call mach_msg without first validating the address is non-zero.
  • Crash telemetry EXC_BAD_ACCESS at address 0 in mojo::core::channel_mac during shutdown — Correlate SIGSEGV reports whose stacks pass through SendMessageLocked/SendPendingMessages/ReceiveMessages near teardown.

Audit directions

  • Other platform Channel implementations (channel_fuchsia, channel_win, channel_posix) — Check each platform’s send/receive buffer accessors for the same reset()-then-callback race and confirm they guard against a zeroed/freed buffer during shutdown.

Before / after

Loading diff…