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: <redacted>
Reported-by: Vega <redacted>
Suggested-by: Alexei Starovoitov <redacted>
Assisted-by: LLM
Signed-off-by: Zhiling Zou <redacted>
---
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/ (local)
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