Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tcp: fix tcp_cleanup_rbuf() for tcp_read_skb()

tcp_cleanup_rbuf() retrieves the skb from sk_receive_queue, it
assumes the skb is not yet dequeued. This is no longer true for
tcp_read_skb() case where we dequeue the skb first.

Fix this by introducing a helper __tcp_cleanup_rbuf() which does
not require any skb and calling it in tcp_read_skb().

Fixes: 04919bed948d ("tcp: Introduce tcp_read_skb()")
Cc: Eric Dumazet <edumazet@google.com>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Cong Wang and committed by
Jakub Kicinski
c457985a e9c6e797

+14 -10
+14 -10
net/ipv4/tcp.c
··· 1567 1567 * calculation of whether or not we must ACK for the sake of 1568 1568 * a window update. 1569 1569 */ 1570 - void tcp_cleanup_rbuf(struct sock *sk, int copied) 1570 + static void __tcp_cleanup_rbuf(struct sock *sk, int copied) 1571 1571 { 1572 1572 struct tcp_sock *tp = tcp_sk(sk); 1573 1573 bool time_to_ack = false; 1574 - 1575 - struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); 1576 - 1577 - WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), 1578 - "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", 1579 - tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); 1580 1574 1581 1575 if (inet_csk_ack_scheduled(sk)) { 1582 1576 const struct inet_connection_sock *icsk = inet_csk(sk); ··· 1615 1621 } 1616 1622 if (time_to_ack) 1617 1623 tcp_send_ack(sk); 1624 + } 1625 + 1626 + void tcp_cleanup_rbuf(struct sock *sk, int copied) 1627 + { 1628 + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); 1629 + struct tcp_sock *tp = tcp_sk(sk); 1630 + 1631 + WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), 1632 + "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", 1633 + tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); 1634 + __tcp_cleanup_rbuf(sk, copied); 1618 1635 } 1619 1636 1620 1637 static void tcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) ··· 1776 1771 copied += used; 1777 1772 1778 1773 if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { 1779 - consume_skb(skb); 1780 1774 ++seq; 1781 1775 break; 1782 1776 } 1783 - consume_skb(skb); 1784 1777 break; 1785 1778 } 1779 + consume_skb(skb); 1786 1780 WRITE_ONCE(tp->copied_seq, seq); 1787 1781 1788 1782 tcp_rcv_space_adjust(sk); 1789 1783 1790 1784 /* Clean up data we have read: This will do ACK frames. */ 1791 1785 if (copied > 0) 1792 - tcp_cleanup_rbuf(sk, copied); 1786 + __tcp_cleanup_rbuf(sk, copied); 1793 1787 1794 1788 return copied; 1795 1789 }