Commit 867f816badc01e6da655028810d468c9f935b37c

Authored by Soheil Hassas Yeganeh
Committed by David S. Miller
1 parent b718e8c8f4

tcp: limit sk_rcvlowat by the maximum receive buffer

The user-provided value to setsockopt(SO_RCVLOWAT) can be
larger than the maximum possible receive buffer. Such values
mute POLLIN signals on the socket which can stall progress
on the socket.

Limit the user-provided value to half of the maximum receive
buffer, i.e., half of sk_rcvbuf when the receive buffer size
is set by the user, or otherwise half of sysctl_tcp_rmem[2].

Fixes: d1361840f8c5 ("tcp: fix SO_RCVLOWAT and RCVBUF autotuning")
Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 7 additions and 5 deletions Side-by-side Diff

... ... @@ -1694,6 +1694,13 @@
1694 1694 /* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */
1695 1695 int tcp_set_rcvlowat(struct sock *sk, int val)
1696 1696 {
  1697 + int cap;
  1698 +
  1699 + if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
  1700 + cap = sk->sk_rcvbuf >> 1;
  1701 + else
  1702 + cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1;
  1703 + val = min(val, cap);
1697 1704 sk->sk_rcvlowat = val ? : 1;
1698 1705  
1699 1706 /* Check if we need to signal EPOLLIN right now */
1700 1707  
... ... @@ -1702,12 +1709,7 @@
1702 1709 if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
1703 1710 return 0;
1704 1711  
1705   - /* val comes from user space and might be close to INT_MAX */
1706 1712 val <<= 1;
1707   - if (val < 0)
1708   - val = INT_MAX;
1709   -
1710   - val = min(val, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
1711 1713 if (val > sk->sk_rcvbuf) {
1712 1714 sk->sk_rcvbuf = val;
1713 1715 tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val);