tcp: fix splice() and tcp collapsing interaction
Under unusual circumstances, TCP collapse can split a big GRO TCP packet while its being used in a splice(socket->pipe) operation. skb_splice_bits() releases the socket lock before calling splice_to_pipe(). [ 1081.353685] WARNING: at net/ipv4/tcp.c:1330 tcp_cleanup_rbuf+0x4d/0xfc() [ 1081.371956] Hardware name: System x3690 X5 -[7148Z68]- [ 1081.391820] cleanup rbuf bug: copied AD3BCF1 seq AD370AF rcvnxt AD3CF13 To fix this problem, we must eat skbs in tcp_recv_skb(). Remove the inline keyword from tcp_recv_skb() definition since it has three call sites. Reported-by: Christian Becker <c.becker@traviangames.com> Cc: Willy Tarreau <w@1wt.eu> Signed-off-by: Eric Dumazet <edumazet@google.com> Tested-by: Willy Tarreau <w@1wt.eu> Signed-off-by: David S. Miller <davem@davemloft.net>hifive-unleashed-5.1
parent
ff905b1e4a
commit
f26845b43c
|
@ -1428,12 +1428,12 @@ static void tcp_service_net_dma(struct sock *sk, bool wait)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
|
static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
|
|
||||||
skb_queue_walk(&sk->sk_receive_queue, skb) {
|
while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
|
||||||
offset = seq - TCP_SKB_CB(skb)->seq;
|
offset = seq - TCP_SKB_CB(skb)->seq;
|
||||||
if (tcp_hdr(skb)->syn)
|
if (tcp_hdr(skb)->syn)
|
||||||
offset--;
|
offset--;
|
||||||
|
@ -1441,6 +1441,11 @@ static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
|
||||||
*off = offset;
|
*off = offset;
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
/* This looks weird, but this can happen if TCP collapsing
|
||||||
|
* splitted a fat GRO packet, while we released socket lock
|
||||||
|
* in skb_splice_bits()
|
||||||
|
*/
|
||||||
|
sk_eat_skb(sk, skb, false);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1520,8 +1525,10 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
||||||
tcp_rcv_space_adjust(sk);
|
tcp_rcv_space_adjust(sk);
|
||||||
|
|
||||||
/* Clean up data we have read: This will do ACK frames. */
|
/* Clean up data we have read: This will do ACK frames. */
|
||||||
if (copied > 0)
|
if (copied > 0) {
|
||||||
|
tcp_recv_skb(sk, seq, &offset);
|
||||||
tcp_cleanup_rbuf(sk, copied);
|
tcp_cleanup_rbuf(sk, copied);
|
||||||
|
}
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tcp_read_sock);
|
EXPORT_SYMBOL(tcp_read_sock);
|
||||||
|
|
Loading…
Reference in New Issue