Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp2353904pxb; Mon, 20 Sep 2021 19:52:47 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwyJ3sp6NVMBLacSn1AgQRhqeLI9PzX08b9+nG6a4z1GdRPMNqNsWFAX2eDydUZ7JJZDB9e X-Received: by 2002:a05:6638:13d5:: with SMTP id i21mr21931068jaj.55.1632192767741; Mon, 20 Sep 2021 19:52:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632192767; cv=none; d=google.com; s=arc-20160816; b=AJ44GqkIaCaE623HqtpamhJa6YKM8600rwwQWQzfEpnB8E0cQVeefIgysF8WKaYk+z j3oc9id1dL9WQHnIzm0cXVlKu8P84tcVEX4xkfoCsJvM1I0rXpa9ynVLISqFiOYTrvqx 0o5qIcKgudWd+vqTgb5EGOW7sM8PfZa1nE2P+3W7nGiDiGwKr3VdExW+r6fVEQIYYHYh XTveyYQuyyobbWjh7Xz8LPZq8PkOXO7HU9umKTsafuxdkECjtOIyCtBuBMorHVRsSnRc Zhxq+yQ9qRgcnGWU0QpF23rgZAg7/LD5x4FvvXPgUlgT4nBvhKkqfOFJJxa7OlZlsXTg OeZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=l/QBhGrjqloUcTyAooq4G0fReINHzoaBVsSJ2WCr3YY=; b=Lm/Iw0MwrJ9lpCwhelcRCVo4CsFt0oNys9kP7ICuWeVSBEr2lMx+akVJiwwWX84rNw O4df+369dguE3DJVh4OEGorsAk3shzBbgCymPweVdRg6cIEN+SetO0Ga8agEme4HfXjv Y+lS7brYRdUJzcTguHCxvHUrOmCNjxZ61RyyUh1qcc+5FXAoHj+UsW92w8z8uqpNQq6R jSH7Fua8ErnIKUS3EWXuoR86nQkdPXwXA3ugyi41rPnBWkhL2gglld9O2JzSnnzhtZ7h AD2g4gl5uBCpivkZ/xMu5kwAZYJo/YUr215DyL32IC+9uxASOlpgKcxtOS1w+oMXABPx 9ufw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=LHsihNOw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id j11si14574667ilu.130.2021.09.20.19.52.36; Mon, 20 Sep 2021 19:52:47 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=LHsihNOw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1387314AbhITS5G (ORCPT + 99 others); Mon, 20 Sep 2021 14:57:06 -0400 Received: from mail.kernel.org ([198.145.29.99]:33542 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1384656AbhITSsd (ORCPT ); Mon, 20 Sep 2021 14:48:33 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id E291B6336A; Mon, 20 Sep 2021 17:34:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632159259; bh=jCgFchMhrEFWJTw//iknOW6XerRyT1Awbe0hGFmAHks=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LHsihNOwQXnmO3Ec5gqkj5WYr6TpQpTSt6/sLX42lcNamXj0BWNbsXRj3uFxNDc9Y XbNqB2XKekApO9HRBnk+6e+2eo8gbpUs91ZUi8VLmSjMX9M3AUGmUtJM3iGlEwd+Ox AdPDSHOyOE1ZUAtsahyigA9R+recM2SXB8wRct/Q= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Florian Westphal , Paolo Abeni , Mat Martineau , Jakub Kicinski , Sasha Levin Subject: [PATCH 5.14 149/168] mptcp: fix possible divide by zero Date: Mon, 20 Sep 2021 18:44:47 +0200 Message-Id: <20210920163926.556501207@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210920163921.633181900@linuxfoundation.org> References: <20210920163921.633181900@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Paolo Abeni [ Upstream commit 1094c6fe7280e17e0e87934add5ad2585e990def ] Florian noted that if mptcp_alloc_tx_skb() allocation fails in __mptcp_push_pending(), we can end-up invoking mptcp_push_release()/tcp_push() with a zero mss, causing a divide by 0 error. This change addresses the issue refactoring the skb allocation code checking if skb collapsing will happen for sure and doing the skb allocation only after such check. Skb allocation will now happen only after the call to tcp_send_mss() which correctly initializes mss_now. As side bonuses we now fill the skb tx cache only when needed, and this also clean-up a bit the output path. v1 -> v2: - use lockdep_assert_held_once() - Jakub - fix indentation - Jakub Reported-by: Florian Westphal Fixes: 724cfd2ee8aa ("mptcp: allocate TX skbs in msk context") Signed-off-by: Paolo Abeni Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/mptcp/protocol.c | 76 ++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a88924947815..c018b591db0b 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -994,6 +994,13 @@ static void mptcp_wmem_uncharge(struct sock *sk, int size) msk->wmem_reserved += size; } +static void __mptcp_mem_reclaim_partial(struct sock *sk) +{ + lockdep_assert_held_once(&sk->sk_lock.slock); + __mptcp_update_wmem(sk); + sk_mem_reclaim_partial(sk); +} + static void mptcp_mem_reclaim_partial(struct sock *sk) { struct mptcp_sock *msk = mptcp_sk(sk); @@ -1069,12 +1076,8 @@ static void __mptcp_clean_una(struct sock *sk) } out: - if (cleaned) { - if (tcp_under_memory_pressure(sk)) { - __mptcp_update_wmem(sk); - sk_mem_reclaim_partial(sk); - } - } + if (cleaned && tcp_under_memory_pressure(sk)) + __mptcp_mem_reclaim_partial(sk); if (snd_una == READ_ONCE(msk->snd_nxt)) { if (msk->timer_ival && !mptcp_data_fin_enabled(msk)) @@ -1154,6 +1157,7 @@ struct mptcp_sendmsg_info { u16 limit; u16 sent; unsigned int flags; + bool data_lock_held; }; static int mptcp_check_allowed_size(struct mptcp_sock *msk, u64 data_seq, @@ -1225,17 +1229,17 @@ static bool __mptcp_alloc_tx_skb(struct sock *sk, struct sock *ssk, gfp_t gfp) return false; } -static bool mptcp_must_reclaim_memory(struct sock *sk, struct sock *ssk) +static bool mptcp_alloc_tx_skb(struct sock *sk, struct sock *ssk, bool data_lock_held) { - return !ssk->sk_tx_skb_cache && - tcp_under_memory_pressure(sk); -} + gfp_t gfp = data_lock_held ? GFP_ATOMIC : sk->sk_allocation; -static bool mptcp_alloc_tx_skb(struct sock *sk, struct sock *ssk) -{ - if (unlikely(mptcp_must_reclaim_memory(sk, ssk))) - mptcp_mem_reclaim_partial(sk); - return __mptcp_alloc_tx_skb(sk, ssk, sk->sk_allocation); + if (unlikely(tcp_under_memory_pressure(sk))) { + if (data_lock_held) + __mptcp_mem_reclaim_partial(sk); + else + mptcp_mem_reclaim_partial(sk); + } + return __mptcp_alloc_tx_skb(sk, ssk, gfp); } /* note: this always recompute the csum on the whole skb, even @@ -1259,7 +1263,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, bool zero_window_probe = false; struct mptcp_ext *mpext = NULL; struct sk_buff *skb, *tail; - bool can_collapse = false; + bool must_collapse = false; int size_bias = 0; int avail_size; size_t ret = 0; @@ -1279,16 +1283,24 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, * SSN association set here */ mpext = skb_ext_find(skb, SKB_EXT_MPTCP); - can_collapse = (info->size_goal - skb->len > 0) && - mptcp_skb_can_collapse_to(data_seq, skb, mpext); - if (!can_collapse) { + if (!mptcp_skb_can_collapse_to(data_seq, skb, mpext)) { TCP_SKB_CB(skb)->eor = 1; - } else { + goto alloc_skb; + } + + must_collapse = (info->size_goal - skb->len > 0) && + (skb_shinfo(skb)->nr_frags < sysctl_max_skb_frags); + if (must_collapse) { size_bias = skb->len; avail_size = info->size_goal - skb->len; } } +alloc_skb: + if (!must_collapse && !ssk->sk_tx_skb_cache && + !mptcp_alloc_tx_skb(sk, ssk, info->data_lock_held)) + return 0; + /* Zero window and all data acked? Probe. */ avail_size = mptcp_check_allowed_size(msk, data_seq, avail_size); if (avail_size == 0) { @@ -1318,7 +1330,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, if (skb == tail) { TCP_SKB_CB(tail)->tcp_flags &= ~TCPHDR_PSH; mpext->data_len += ret; - WARN_ON_ONCE(!can_collapse); WARN_ON_ONCE(zero_window_probe); goto out; } @@ -1470,15 +1481,6 @@ static void __mptcp_push_pending(struct sock *sk, unsigned int flags) if (ssk != prev_ssk || !prev_ssk) lock_sock(ssk); - /* keep it simple and always provide a new skb for the - * subflow, even if we will not use it when collapsing - * on the pending one - */ - if (!mptcp_alloc_tx_skb(sk, ssk)) { - mptcp_push_release(sk, ssk, &info); - goto out; - } - ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info); if (ret <= 0) { mptcp_push_release(sk, ssk, &info); @@ -1512,7 +1514,9 @@ out: static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk) { struct mptcp_sock *msk = mptcp_sk(sk); - struct mptcp_sendmsg_info info; + struct mptcp_sendmsg_info info = { + .data_lock_held = true, + }; struct mptcp_data_frag *dfrag; struct sock *xmit_ssk; int len, copied = 0; @@ -1538,13 +1542,6 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk) goto out; } - if (unlikely(mptcp_must_reclaim_memory(sk, ssk))) { - __mptcp_update_wmem(sk); - sk_mem_reclaim_partial(sk); - } - if (!__mptcp_alloc_tx_skb(sk, ssk, GFP_ATOMIC)) - goto out; - ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info); if (ret <= 0) goto out; @@ -2296,9 +2293,6 @@ static void __mptcp_retrans(struct sock *sk) info.sent = 0; info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len : dfrag->already_sent; while (info.sent < info.limit) { - if (!mptcp_alloc_tx_skb(sk, ssk)) - break; - ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info); if (ret <= 0) break; -- 2.30.2