Commit 9b7177b1 authored by John Fastabend's avatar John Fastabend Committed by Daniel Borkmann

bpf: tcp_read_skb needs to pop skb regardless of seq

Before fix e5c6de5f tcp_read_skb() would increment the tp->copied-seq
value. This (as described in the commit) would cause an error for apps
because once that is incremented the application might believe there is no
data to be read. Then some apps would stall or abort believing no data is
available.

However, the fix is incomplete because it introduces another issue in
the skb dequeue. The loop does tcp_recv_skb() in a while loop to consume
as many skbs as possible. The problem is the call is ...

  tcp_recv_skb(sk, seq, &offset)

... where 'seq' is:

  u32 seq = tp->copied_seq;

Now we can hit a case where we've yet incremented copied_seq from BPF side,
but then tcp_recv_skb() fails this test ...

 if (offset < skb->len || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))

... so that instead of returning the skb we call tcp_eat_recv_skb() which
frees the skb. This is because the routine believes the SKB has been collapsed
per comment:

 /* This looks weird, but this can happen if TCP collapsing
  * splitted a fat GRO packet, while we released socket lock
  * in skb_splice_bits()
  */

This can't happen here we've unlinked the full SKB and orphaned it. Anyways
it would confuse any BPF programs if the data were suddenly moved underneath
it.

To fix this situation do simpler operation and just skb_peek() the data
of the queue followed by the unlink. It shouldn't need to check this
condition and tcp_read_skb() reads entire skbs so there is no need to
handle the 'offset!=0' case as we would see in tcp_read_sock().

Fixes: e5c6de5f ("bpf, sockmap: Incorrectly handling copied_seq")
Fixes: 04919bed ("tcp: Introduce tcp_read_skb()")
Signed-off-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Reviewed-by: default avatarJakub Sitnicki <jakub@cloudflare.com>
Link: https://lore.kernel.org/bpf/20230926035300.135096-2-john.fastabend@gmail.com
parent 81335f90
...@@ -1621,16 +1621,13 @@ EXPORT_SYMBOL(tcp_read_sock); ...@@ -1621,16 +1621,13 @@ EXPORT_SYMBOL(tcp_read_sock);
int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
{ {
struct tcp_sock *tp = tcp_sk(sk);
u32 seq = tp->copied_seq;
struct sk_buff *skb; struct sk_buff *skb;
int copied = 0; int copied = 0;
u32 offset;
if (sk->sk_state == TCP_LISTEN) if (sk->sk_state == TCP_LISTEN)
return -ENOTCONN; return -ENOTCONN;
while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
u8 tcp_flags; u8 tcp_flags;
int used; int used;
...@@ -1643,13 +1640,10 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) ...@@ -1643,13 +1640,10 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
copied = used; copied = used;
break; break;
} }
seq += used;
copied += used; copied += used;
if (tcp_flags & TCPHDR_FIN) { if (tcp_flags & TCPHDR_FIN)
++seq;
break; break;
}
} }
return copied; return copied;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment