From mboxrd@z Thu Jan 1 00:00:00 1970 From: Soheil Hassas Yeganeh Subject: [PATCH net] tcp: limit sk_rcvlowat by the maximum receive buffer Date: Fri, 8 Jun 2018 22:47:10 -0400 Message-ID: <20180609024710.206554-1-soheil.kdev@gmail.com> Cc: ycheng@google.com, ncardwell@google.com, edumazet@google.com, willemb@google.com, Soheil Hassas Yeganeh To: davem@davemloft.net, netdev@vger.kernel.org Return-path: Received: from mail-yb0-f194.google.com ([209.85.213.194]:34073 "EHLO mail-yb0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751476AbeFICrP (ORCPT ); Fri, 8 Jun 2018 22:47:15 -0400 Received: by mail-yb0-f194.google.com with SMTP id n23-v6so3753891ybg.1 for ; Fri, 08 Jun 2018 19:47:14 -0700 (PDT) Sender: netdev-owner@vger.kernel.org List-ID: From: Soheil Hassas Yeganeh 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 Signed-off-by: Eric Dumazet Reviewed-by: Neal Cardwell Acked-by: Willem de Bruijn --- net/ipv4/tcp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2741953adaba2..141acd92e58ae 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1694,6 +1694,13 @@ EXPORT_SYMBOL(tcp_peek_len); /* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */ int tcp_set_rcvlowat(struct sock *sk, int val) { + int cap; + + if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) + cap = sk->sk_rcvbuf >> 1; + else + cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1; + val = min(val, cap); sk->sk_rcvlowat = val ? : 1; /* Check if we need to signal EPOLLIN right now */ @@ -1702,12 +1709,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val) if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) return 0; - /* val comes from user space and might be close to INT_MAX */ val <<= 1; - if (val < 0) - val = INT_MAX; - - val = min(val, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]); if (val > sk->sk_rcvbuf) { sk->sk_rcvbuf = val; tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val); -- 2.18.0.rc1.242.g61856ae69a-goog