# Attacker-controlled Bluetooth Classic device

The browser-side UAF window only opens when the RFCOMM open does **not**
complete successfully. The attacker therefore needs a BR/EDR device that:

1. **Pairs normally** with the macOS host (so it appears in IOBluetooth's
   device list and in the Web Serial chooser).
2. **Advertises an SDP record** for Serial Port Profile
   (ServiceClassID `0x1101`, ProtocolDescriptorList with RFCOMM channel N),
   so `BluetoothSocketMac::OnSDPQueryComplete` resolves a valid
   `rfcomm_channel_id` and calls `BluetoothRfcommChannelMac::OpenAsync`.
3. Then does **one** of:

   **Window A — stall (preferred, deterministic 10 s timeout):**
   After the host opens the L2CAP channel for RFCOMM (PSM 0x0003) and sends
   the multiplexer SABM (DLCI 0) and/or the per-DLCI SABM, **do not reply**
   (no UA, no DM). Chrome's `kChannelOpeningTimeoutInterval` (10 000 ms) fires
   `OnChannelOpeningTimeout` → `ReleaseChannel()` while `_strongSelf == nil`.
   Optionally reply ~50–200 ms **after** the 10 s mark so IOBluetooth still
   has a pending event to dispatch to the now-freed delegate.

   **Window B — reject:**
   Reply to the per-DLCI SABM with **DM** (or close the L2CAP channel).
   IOBluetooth delivers `rfcommChannelOpenComplete:status:<error>` with
   `error != kIOReturnSuccess`; `_strongSelf` is not set; the posted
   `BluetoothSocketMac::OnChannelOpenComplete` calls `ReleaseChannel()`;
   a trailing `rfcommChannelClosed:` then hits the freed delegate.

## Reference firmware

Any stack with controllable RFCOMM behaviour works. Tested-style options:

- **BTstack** (`bluekitchen/btstack`) on ESP32 / nRF52 / USB-BT dongle:
  start from `examples/spp_counter.c`, register the SPP SDP record, then in
  the RFCOMM event handler drop or NAK `RFCOMM_EVENT_INCOMING_CONNECTION` /
  never call `rfcomm_accept_connection()`.
- **Linux + BlueZ** with a USB BR/EDR dongle: register the SPP SDP record via
  `sdptool add SP`, then use a raw L2CAP socket on PSM 3 and simply never
  `accept()` the RFCOMM DLCI, or close it immediately.

The exact firmware is out of scope for this repo; only the wire behaviour
above is required.
