CVE-2026-97611: net: openvswitch: fix use-after-free of the flow table mask array
In the Linux kernel, the following vulnerability has been resolved:
net: openvswitch: fix use-after-free of the flow table mask array
tblmaskarrayrealloc() retires the old maskarray before it stops being reachable:
old = ovsldereference(tbl->maskarray); if (old) { ... callrcu(&old->rcu, maskarrayrcucb); }
rcuassignpointer(tbl->maskarray, new);
callrcu() only waits for read-side critical sections already in flight. tbl->maskarray still points at old between the callrcu() and the rcuassignpointer(), so a reader entering ovsflowtbllookupstats() in that window picks up old in a fresh critical section that the pending grace period does not cover.
tblmaskarrayrealloc() runs in process context under ovsmutex, so the window is preemptible and can outlast the grace period. Then maskarrayrcucb() frees old before the swap runs:
BUG: KASAN: slab-use-after-free in flowlookup.constprop.0+0x2bf/0x2f0 Read of size 8 at addr ffff888020b3e018 by task poc/741 flowlookup.constprop.0+0x2bf/0x2f0 ovsflowtbllookupstats+0x4a3/0x5c0 ovsdpprocesspacket+0x19c/0x710 ovsvportreceive+0x243/0x390 internaldevxmit+0x81/0x170 Freed by task 728: kfree+0x16a/0x4e0 rcucore+0x853/0x1030
Publish the new array before retiring the old one. The kfreercu() that callrcu() replaced ran after the swap.
Affected Software
Event History
Frequently Asked Questions
What runtime condition is required to trigger the fault?
The issue requires tbl_mask_array_realloc() to retire an existing mask array while a new ovs_flow_tbl_lookup_stats() reader enters after call_rcu() has been scheduled but before tbl->mask_array is updated. The reallocation runs in preemptible process context under ovs_mutex, allowing that window to persist long enough for the old array to be freed.
How can an affected system be identified?
The reported symptom is a KASAN slab-use-after-free during flow_lookup, with ovs_flow_tbl_lookup_stats(), ovs_dp_process_packet(), ovs_vport_receive(), and internal_dev_xmit() in the read-side stack. The freeing path includes mask_array_rcu_cb(), kfree(), and rcu_core.