tcp_bpf_recvmsg_parser() snapshots tcp->copied_seq before processing queued data and waiting for more. tcp_data_ready() and tcp_msg_wait_data() can release the socket lock. While it is released, a sockmap verdict can drop or redirect data and advance copied_seq. At exit, writing back the old snapshot plus copied_from_self rewinds that progress, leaving ordinary TCP receive behind queued data. Keep copied_from_self as the count of bytes consumed from this socket, but add it to the current tcp->copied_seq at exit instead of writing back a stale snapshot. Count the FIN byte in copied_from_self as well. Fixes: e5c6de5fa025 ("bpf, sockmap: Incorrectly handling copied_seq") Cc: stable@vger.kernel.org Reported-by: Vega Suggested-by: Alexei Starovoitov Assisted-by: LLM Signed-off-by: Zhiling Zou --- changes in v2: - Update copied_seq relative to its current value at exit, preserving progress made while tcp_msg_wait_data() releases the socket lock. - Count the FIN sequence byte in copied_from_self. - v1 Link: https://lore.kernel.org/all/af73f81ba5060272e63bfe3757295fb09f5c6198.1792733621.git.zhilinz@nebusec.ai/ net/ipv4/tcp_bpf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 2e234d155b5e6..fee7bd72cc272 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -228,7 +228,6 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, struct tcp_sock *tcp; int copied_from_self = 0; int copied = 0; - u32 seq; if (unlikely(flags & MSG_ERRQUEUE)) return inet_recv_error(sk, msg, len); @@ -242,7 +241,6 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, lock_sock(sk); tcp = tcp_sk(sk); - seq = tcp->copied_seq; /* We may have received data on the sk_receive_queue pre-accept and * then we can not use read_skb in this context because we haven't * assigned a sk_socket yet so have no link to the ops. The work-around @@ -274,11 +272,10 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, if (is_fin) { copied = 0; - seq++; + copied_from_self++; goto out; } } - seq += copied_from_self; if (!copied) { long timeo; int data; @@ -321,7 +318,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, } out: if (!peek) - WRITE_ONCE(tcp->copied_seq, seq); + WRITE_ONCE(tcp->copied_seq, tcp->copied_seq + copied_from_self); tcp_rcv_space_adjust(sk); if (copied > 0) __tcp_cleanup_rbuf(sk, copied); -- 2.55.0