From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-eopbgr720093.outbound.protection.outlook.com ([40.107.72.93]:21257 "EHLO NAM05-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731100AbeIXUuu (ORCPT ); Mon, 24 Sep 2018 16:50:50 -0400 From: Sasha Levin To: "stable@vger.kernel.org" , "linux-kernel@vger.kernel.org" CC: Sara Sharon , Johannes Berg , Sasha Levin Subject: [PATCH AUTOSEL 4.18 23/76] mac80211: avoid kernel panic when building AMSDU from non-linear SKB Date: Mon, 24 Sep 2018 14:48:14 +0000 Message-ID: <20180924144751.164410-23-alexander.levin@microsoft.com> References: <20180924144751.164410-1-alexander.levin@microsoft.com> In-Reply-To: <20180924144751.164410-1-alexander.levin@microsoft.com> Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org List-ID: From: Sara Sharon [ Upstream commit 166ac9d55b0ab70b644e429be1f217fe8393cbd7 ] When building building AMSDU from non-linear SKB, we hit a kernel panic when trying to push the padding to the tail. Instead, put the padding at the head of the next subframe. This also fixes the A-MSDU subframes to not have the padding accounted in the length field and not have pad at all for the last subframe, both required by the spec. Fixes: 6e0456b54545 ("mac80211: add A-MSDU tx support") Signed-off-by: Sara Sharon Reviewed-by: Lorenzo Bianconi Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/tx.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index fa1f1e63a264..667a73d6eb5c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3073,27 +3073,18 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta= ) } =20 static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, - struct sk_buff *skb, int headroom, - int *subframe_len) + struct sk_buff *skb, int headroom) { - int amsdu_len =3D *subframe_len + sizeof(struct ethhdr); - int padding =3D (4 - amsdu_len) & 3; - - if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { + if (skb_headroom(skb) < headroom) { I802_DEBUG_INC(local->tx_expand_skb_head); =20 - if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { wiphy_debug(local->hw.wiphy, "failed to reallocate TX buffer\n"); return false; } } =20 - if (padding) { - *subframe_len +=3D padding; - skb_put_zero(skb, padding); - } - return true; } =20 @@ -3117,8 +3108,7 @@ static bool ieee80211_amsdu_prepare_head(struct ieee8= 0211_sub_if_data *sdata, if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) return true; =20 - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr), - &subframe_len)) + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr))) return false; =20 data =3D skb_push(skb, sizeof(*amsdu_hdr)); @@ -3184,7 +3174,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee8021= 1_sub_if_data *sdata, void *data; bool ret =3D false; unsigned int orig_len; - int n =3D 1, nfrags; + int n =3D 1, nfrags, pad =3D 0; + u16 hdrlen; =20 if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) return false; @@ -3235,8 +3226,19 @@ static bool ieee80211_amsdu_aggregate(struct ieee802= 11_sub_if_data *sdata, if (max_frags && nfrags > max_frags) goto out; =20 - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, - &subframe_len)) + /* + * Pad out the previous subframe to a multiple of 4 by adding the + * padding to the next one, that's being added. Note that head->len + * is the length of the full A-MSDU, but that works since each time + * we add a new subframe we pad out the previous one to a multiple + * of 4 and thus it no longer matters in the next round. + */ + hdrlen =3D fast_tx->hdr_len - sizeof(rfc1042_header); + if ((head->len - hdrlen) & 3) + pad =3D 4 - ((head->len - hdrlen) & 3); + + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + + 2 + pad)) goto out; =20 ret =3D true; @@ -3248,6 +3250,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee8021= 1_sub_if_data *sdata, memcpy(data, &len, 2); memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); =20 + memset(skb_push(skb, pad), 0, pad); + head->len +=3D skb->len; head->data_len +=3D skb->len; *frag_tail =3D skb; --=20 2.17.1