CVE-2026-72126
CVE-2026-72126 is a use-after-free in the ISO-TP (ISO 15765-2) CAN bus protocol handler, and the root cause is a conditional `synchronize_rcu()` that gated protection on a state variable vulnerable to asynchronous mutation from the netdev notifier chain. The vulnerability works like this: `isotp_release()` called `synchronize_rcu()` only when `so->bound` was true, assuming bound sockets needed protection while unbound ones did not. But `isotp_notify()` — triggered during network device unregistration — cleared `so->bound` without its own synchronization. This created a race: `isotp_release()` could read a stale false value of `so->bound`, skip the RCU grace period, and free the socket while `can_rx_unregister()` had already scheduled RCU callbacks that would later re-arm timers and access the freed structure. The fix makes `synchronize_rcu()` unconditional in `isotp_release()`. This is the correct fix, but it reveals something important about the original code. The conditional guard was never a real optimization worth its complexity — it was a stale invariant guard that corresponded to assumptions baked into an earlier version of the code, likely when the socket was considered bound once and never re-entered during release. Subsequent code changes (the NETDEV_UNREGISTER handler in `isotp_notify()`, the callback-based `can_rx_unregister()`) introduced new concurrency without revisiting those synchronization assumptions. The deeper pattern here is the conditional-synchronization anti-pattern: any `synchronize_rcu()` gated on a variable that can be modified by an asynchronous notifier chain is a future CVE. The RCU API frames conditional use as acceptable — 'you may not need this' — which normalizes exactly the pattern that produces these races. When the guard variable itself isn't protected by its own locking discipline, the conditional becomes a maintenance-time bomb. For your own code: audit release paths for conditional `synchronize_rcu()` calls, particularly those gated on business-logic flags rather than synchronization-state variables. If the guard can be cleared by code executing in a different context (notifier chains, callbacks, interrupt handlers), the conditional is unsafe regardless of how unlikely the race appears. The fix is simple — synchronize unconditionally — and socket destruction latency is not a hot path worth optimizing at the expense of correctness.
Reviewed through automated stages and approved by a human before publication.