Re: [PATCH net v3] tcp: prevent cross-family skb processing after disconnect
From: Zhiyu Zhang
Date: Wed Nov 04 2026 - 15:56:01 EST
Eric Dumazet <edumazet@xxxxxxxxxx> 于2026年11月3日周二 19:03写道:
>
> We do not want to add yet another check in TCP IPv4 fast path,
> for a problem that only exists for IPv6 sockets.
>
> tcp_v6_do_rcv() already dispatches IPv4 skbs to tcp_v4_do_rcv().
>
> Simply stop changing sk->sk_backlog_rcv for v4-mapped sockets
> (tcp_v6_connect() and tcp_v6_mapped_child_init()),
> so that skbs found in the backlog are always handled by the correct path.
>
> tcp_v6_disconnect() can then test
> inet_csk(sk)->icsk_af_ops->net_header_len == sizeof(struct iphdr)
> (this also covers subflow_v6m_specific).
>
> Thanks.
>
> Untested patch:
Hi Eric,
Thanks. I applied your untested patch as-is on top of 5838f10563d5.
I agree that keeping tcp_v6_do_rcv() as the backlog handler for
AF_INET6 sockets is cleaner than adding another check to the IPv4 fast
path.
The patch fixes the reported bug in my tests. In the native IPv6 to
v4-mapped race, the stale IPv6 skb no longer reaches
tcp_v4_send_reset(). The disconnect/reconnect tests also pass for both
TCP and MPTCP.
I also checked the two races reported by Sashiko. On one v3 run with
400 reconnects in each direction, both races were hit four times.
For a native IPv6 to v4-mapped reconnect, I observed:
tcp_v6_rcv()
tcp_v6_do_rcv()
tcp_rcv_established()
inet_sk_rx_dst_set() /* IPv6 skb */
For the reverse reconnect, I observed:
tcp_v4_rcv()
tcp_v4_do_rcv()
tcp_rcv_established()
inet6_sk_rx_dst_set() /* IPv4 skb */
I added probes after the rcu_assign_pointer(sk->sk_rx_dst, dst)
instructions and confirmed that the mismatched dst was actually stored.
Both cases can also be reproduced with your patch.
So the receive paths and the cross-family dst assignments are real.
However, I have not reproduced the Critical outcome suggested by the
review. I saw no warning, oops or panic, and did not observe an IPv6
skb reaching ip_local_deliver() or an IPv4 skb reaching ip6_input().
For the local IPv4 input route in this test, the bytes overlapping
rt6_info::sernum are non-zero due to rtable::rt_type/rt_is_input, so
the invalid rt->from dereference did not occur.
Given that, I think your patch is still the right fix for the reported
header.h6/header.h4 bug. I would post it as v4 with that scope, and
handle the stale skb/sk_rx_dst race separately instead of adding the
IPv4 fast-path check back.
Does that sound like the right split, or do you think the sk_rx_dst
race should be addressed before v4 or should not even take care?
Thanks,
Zhiyu