Commit 867f816badc01e6da655028810d468c9f935b37c
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
net/ipv4/tcp.c
... | ... | @@ -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); |