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.