Low chrome UAF 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Bluetooth
DescriptionUse after free in Bluetooth
ComponentBluetooth
Bug ClassUAF
Tracker495783474
Fix commit375096a7dd43 (chromium/src) +40/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
device/bluetooth/bluetooth_socket_mac.mm
modified

Files Changed

  • device/bluetooth/bluetooth_socket_mac.mm
From 375096a7dd434f3fa2a5cff6a8c71c3f3827da83 Mon Sep 17 00:00:00 2001
From: Alvin Ji <alvinji@chromium.org>
Date: Fri, 22 May 2026 20:15:45 -0700
Subject: [PATCH] bluetooth: Fix potential browser-process UAF in socket listeners

Due to an Apple framework bug (FB13705522), IOBluetooth holds an
unsafe_unretained pointer and may dispatch late callbacks to freed
listeners after unregistration.

This CL fixes the UAF by clearing back-pointers and posting a keep-alive
block to the main queue, ensuring the listener safely outlives any
pending OS notifications.

Bug: 495783474
Change-Id: I79497e722159320158bb411fcb15f99066d7ca0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7833747
Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
Commit-Queue: Alvin Ji <alvinji@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1635359}
---

diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
index 60b5df97..2348f81a 100644
--- a/device/bluetooth/bluetooth_socket_mac.mm
+++ b/device/bluetooth/bluetooth_socket_mac.mm
@@ -122,6 +122,7 @@
                      channelID:(BluetoothRFCOMMChannelID)channelID;
 - (void)rfcommChannelOpened:(IOBluetoothUserNotification*)notification
                     channel:(IOBluetoothRFCOMMChannel*)rfcommChannel;
+- (void)stopListening;
 
 @end
 
@@ -150,8 +151,26 @@
   [_rfcommNewChannelNotification unregister];
 }
 
+- (void)stopListening {
+  [_rfcommNewChannelNotification unregister];
+  _socket = nullptr;
+
+  // Keep self alive for a brief period to allow any already-enqueued
+  // notifications on the main run loop to fire safely (and become no-ops
+  // since _socket is now null) rather than hitting a deallocated object.
+  // See FB13705522.
+  __strong auto strongSelf = self;
+  dispatch_async(dispatch_get_main_queue(), ^{
+    (void)strongSelf;
+  });
+}
+
 - (void)rfcommChannelOpened:(IOBluetoothUserNotification*)notification
                     channel:(IOBluetoothRFCOMMChannel*)rfcommChannel {
+  if (!_socket) {
+    return;
+  }
+
   if (notification != _rfcommNewChannelNotification) {
     // This case is reachable if there are pre-existing RFCOMM channels open at
     // the time that the listener is created. In that case, each existing
@@ -184,6 +203,7 @@
                            psm:(BluetoothL2CAPPSM)psm;
 - (void)l2capChannelOpened:(IOBluetoothUserNotification*)notification
                    channel:(IOBluetoothL2CAPChannel*)l2capChannel;
+- (void)stopListening;
 
 @end
 
@@ -212,8 +232,26 @@
   [_l2capNewChannelNotification unregister];
 }
 
+- (void)stopListening {
+  [_l2capNewChannelNotification unregister];
+  _socket = nullptr;
+
+  // Keep self alive for a brief period to allow any already-enqueued
+  // notifications on the main run loop to fire safely (and become no-ops
+  // since _socket is now null) rather than hitting a deallocated object.
+  // See FB13705522.
+  __strong auto strongSelf = self;
+  dispatch_async(dispatch_get_main_queue(), ^{
+    (void)strongSelf;
+  });
+}
+
 - (void)l2capChannelOpened:(IOBluetoothUserNotification*)notification
                    channel:(IOBluetoothL2CAPChannel*)l2capChannel {
+  if (!_socket) {
+    return;
+  }
+
   if (notification != _l2capNewChannelNotification) {
     // This case is reachable if there are pre-existing L2CAP channels open at
     // the time that the listener is created. In that case, each existing
@@ -1001,7 +1039,9 @@
 
   [service_record_ removeServiceRecord];
   service_record_ = nil;
+  [rfcomm_connection_listener_ stopListening];
   rfcomm_connection_listener_ = nil;
+  [l2cap_connection_listener_ stopListening];
   l2cap_connection_listener_ = nil;
 
   // Destroying the listener above prevents the callback delegate from being
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.