Re: [PATCH net] tcp: fix AO info use-after-free in tcp_ao_connect_init()
Eric Dumazet <[email protected]>
| Newsgroups | org.kernel.vger.linux-kernel,org.kernel.vger.netdev,org.kernel.vger.stable |
|---|---|
| Message-ID | <CANn89iLBDiwaLZ-1cp50HQahgrDD8ZDw8mix6C+Ukf3v-4xXxQ@mail.gmail.com> |
On Tue, Aug 18, 2026 at 6:21 PM Qing Ming <[email protected]> wrote: > > tcp_v4_connect() adds a SYN-SENT socket to the ehash before calling > tcp_connect(). If TCP-AO is configured, tcp_connect() first verifies that > a key matches the peer and the bound device's current L3 master. > tcp_ao_connect_init() later resolves the L3 master again and removes keys > which do not match it. > > The socket lock does not stabilize the bound device's VRF membership. > Detaching the device from its VRF between the initial validation and the > L3-master calculation in tcp_ao_connect_init() can therefore make the > validation succeed while initialization observes the default L3 domain and > removes the only key. The subsequent AO lookup then fails, so the no-key > path clears tp->ao_info and frees it directly. > > The receive path can find the socket in the ehash and load tp->ao_info > under RCU before acquiring the socket lock. A reader which loaded the old > pointer can thus continue into tcp_inbound_ao_hash() after the direct free. > > The issue was found during a static audit of TCP-AO object lifetime. An > unprivileged reproducer in self-created user and network namespaces raced > connect() with detaching a veth from its VRF while sending TCP-AO segments. > It triggered the same KASAN report on two fresh boots: > > BUG: KASAN: slab-use-after-free in tcp_inbound_ao_hash+0x585/0x19f0 > Write of size 8 at addr ffff88800bf88128 by task tcp_ao_vrf_race/232 > > Call Trace: > tcp_inbound_ao_hash+0x585/0x19f0 > tcp_inbound_hash+0x677/0xa80 > tcp_v4_rcv+0x1c3e/0x3ab0 > > Allocated by task 235: > tcp_ao_alloc_info+0x43/0xf0 > tcp_ao_add_cmd+0xdf7/0x13b0 > do_tcp_setsockopt+0x168c/0x2640 > > Freed by task 235: > kfree+0x1b8/0x550 > tcp_connect+0x252/0x4f00 > tcp_v4_connect+0x1114/0x1720 > > The bad address is 40 bytes inside the freed 128-byte object, matching the > tcp_ao_info counters.key_not_found field. The two runs used 1000 attempts > each, reached the no-key path 366 and 411 times, and produced one and two > KASAN reports respectively. With this change, the same reproducer reached > the no-key path 366 times in 1000 attempts without a KASAN report or oops. > > Use tcp_ao_destroy_sock() for the no-key path. It unpublishes the AO info, > updates the socket memory and static-key accounting, and defers the free > until after an RCU grace period. > > Fixes: 248411b8cb89 ("net/tcp: Wire up l3index to TCP-AO") > Cc: [email protected] > Assisted-by: Codex:gpt-5 > Signed-off-by: Qing Ming <[email protected]> > --- > net/ipv4/tcp_ao.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c > index e4ec60a33496..4dc5910da076 100644 > --- a/net/ipv4/tcp_ao.c > +++ b/net/ipv4/tcp_ao.c > @@ -1191,8 +1191,7 @@ void tcp_ao_connect_init(struct sock *sk) > * at least one tcp-ao key that matches the remote peer. > */ > WARN_ON_ONCE(1); > - rcu_assign_pointer(tp->ao_info, NULL); > - kfree(ao_info); > + tcp_ao_destroy_sock(sk, false); > } Why keeping WARN_ON_ONCE(1) then? This will crash with panic_on_warn=1. pw-bot: cr Please wait ~24 hours before sending a new version.