Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2688286pxj; Mon, 31 May 2021 08:17:14 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzrwxHt5LM5YoXOj/z92UV3mUYgkMox23shtZOCj5mjlQfl0CiBoDqjLLarrvacp+b3kyNs X-Received: by 2002:a92:cd04:: with SMTP id z4mr16379410iln.39.1622474234423; Mon, 31 May 2021 08:17:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622474234; cv=none; d=google.com; s=arc-20160816; b=I7BtQXHgDb1g7ZTu2X8oTzJ43gbFWdWIlUeZ8ZjfKEHih4XK3stAnkqYe4XaW+/+LN YB2Bl9VvecpLY+U/wCv97JtM+4DiFfUU6xKOiq8AyXOL6IW3UsfE8OLdw6y7XU+pMs0Y szwvTu09Q6tqwHWWCj20qjmEueR55gmUVTqq8V7WS1IGkB2nATGx++HPcuFrg2f3r/I5 Q4e6Pmdbie5OivwUjRup/Sc0lsx8UCnjtflh9iEEUhEBRYRiGWDtNssPt1pN/0KeV7vC N0D7BF5l6Q8abY/0klRb8yKBdiZYZUKBw/fg3IbVIgcTl7JT7FuzPfJwZrxxGtPVo8fG mNjw== 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=9iAe00twBvAuhlwNtGsnRUUP95QB2D7r3EsKr4Ijlt8=; b=v1dKfnrhsUlwywlCXiZiTC8+eKz1U6H3PPX9JadAf52H0XBLbDtBtvyzS+VE4YUqve 2QWwauQOlya8Ve0mjs8VPKHLzBNUw/Xf0xpwqODzMlxDzft1Mfx4tGzi+6/t3nwkyhVH x/F5egBtpC3MrxFc1dX72PC+wlvA1t9HM8GiHMoVyxbCrI52zMjblOAlvRBly6Wh9GTj cxc8jN4xKflh3w0dDtT1s7PockuGdOPhclGHYSMWYGadFkznx8iI06Y3JlqNykxrZJFh 6zBBy2LWVIowvYC0lI5QVopbonXsnGxZYZEwJZswmAZMesbe02CvQ6L3UjRnBoXDj4Gm WnTA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=fKm6EeEf; 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 q205si14743133ioq.7.2021.05.31.08.16.59; Mon, 31 May 2021 08:17:14 -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=fKm6EeEf; 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 S233023AbhEaPRD (ORCPT + 99 others); Mon, 31 May 2021 11:17:03 -0400 Received: from mail.kernel.org ([198.145.29.99]:43310 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233333AbhEaONj (ORCPT ); Mon, 31 May 2021 10:13:39 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7F2F361992; Mon, 31 May 2021 13:42:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1622468528; bh=uYvsM+dYdx4w17xeKWn1rbQyhao6tj9BgGKMpf/F4xw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fKm6EeEfvpmWIitHE4JhBYoqe90x2TUc2vESenQQbIIZY0U6+huRetNQBS2Tzg4iU i2UGnaaOLSvL6pL8Rwvf9zdm6yo7Sp/lYlGDU4igcPskzEQY2DApVc7Bg1gFF6vTVO licizrhe4fv3MhScHtKCKgMquwfMTqliEnEVWwhU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Wen Gong , Jouni Malinen , Johannes Berg Subject: [PATCH 5.4 024/177] ath10k: add CCMP PN replay protection for fragmented frames for PCIe Date: Mon, 31 May 2021 15:13:01 +0200 Message-Id: <20210531130648.753682794@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210531130647.887605866@linuxfoundation.org> References: <20210531130647.887605866@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: Wen Gong commit a1166b2653db2f3de7338b9fb8a0f6e924b904ee upstream. PN replay check for not fragmented frames is finished in the firmware, but this was not done for fragmented frames when ath10k is used with QCA6174/QCA6377 PCIe. mac80211 has the function ieee80211_rx_h_defragment() for PN replay check for fragmented frames, but this does not get checked with QCA6174 due to the ieee80211_has_protected() condition not matching the cleared Protected bit case. Validate the PN of received fragmented frames within ath10k when CCMP is used and drop the fragment if the PN is not correct (incremented by exactly one from the previous fragment). This applies only for QCA6174/QCA6377 PCIe. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.9ba2664866a4.I756e47b67e210dba69966d989c4711ffc02dc6bc@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/htt.h | 1 drivers/net/wireless/ath/ath10k/htt_rx.c | 99 +++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -835,6 +835,7 @@ enum htt_security_types { #define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2 #define ATH10K_TXRX_NUM_EXT_TIDS 19 +#define ATH10K_TXRX_NON_QOS_TID 16 enum htt_security_flags { #define HTT_SECURITY_TYPE_MASK 0x7F --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1739,16 +1739,87 @@ static void ath10k_htt_rx_h_csum_offload msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); } +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr; + u64 pn = 0; + u8 *ehdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control); + + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) { + pn = ehdr[0]; + pn |= (u64)ehdr[1] << 8; + pn |= (u64)ehdr[4] << 16; + pn |= (u64)ehdr[5] << 24; + pn |= (u64)ehdr[6] << 32; + pn |= (u64)ehdr[7] << 40; + } + return pn; +} + +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, + struct sk_buff *skb, + u16 peer_id, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ath10k_peer *peer; + union htt_rx_pn_t *last_pn, new_pn = {0}; + struct ieee80211_hdr *hdr; + bool more_frags; + u8 tid, frag_number; + u32 seq; + + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n"); + return false; + } + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = ieee80211_get_tid(hdr); + else + tid = ATH10K_TXRX_NON_QOS_TID; + + last_pn = &peer->frag_tids_last_pn[tid]; + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype); + more_frags = ieee80211_has_morefrags(hdr->frame_control); + frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + if (frag_number == 0) { + last_pn->pn48 = new_pn.pn48; + peer->frag_tids_seq[tid] = seq; + } else { + if (seq != peer->frag_tids_seq[tid]) + return false; + + if (new_pn.pn48 != last_pn->pn48 + 1) + return false; + + last_pn->pn48 = new_pn.pn48; + } + + return true; +} + static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *status, bool fill_crypt_header, u8 *rx_hdr, - enum ath10k_pkt_rx_err *err) + enum ath10k_pkt_rx_err *err, + u16 peer_id, + bool frag) { struct sk_buff *first; struct sk_buff *last; - struct sk_buff *msdu; + struct sk_buff *msdu, *temp; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum htt_rx_mpdu_encrypt_type enctype; @@ -1761,6 +1832,7 @@ static void ath10k_htt_rx_h_mpdu(struct bool is_decrypted; bool is_mgmt; u32 attention; + bool frag_pn_check = true; if (skb_queue_empty(amsdu)) return; @@ -1859,6 +1931,24 @@ static void ath10k_htt_rx_h_mpdu(struct } skb_queue_walk(amsdu, msdu) { + if (frag && !fill_crypt_header && is_decrypted && + enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) + frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar, + msdu, + peer_id, + 0, + enctype); + + if (!frag_pn_check) { + /* Discard the fragment with invalid PN */ + temp = msdu->prev; + __skb_unlink(msdu, amsdu); + dev_kfree_skb_any(msdu); + msdu = temp; + frag_pn_check = true; + continue; + } + ath10k_htt_rx_h_csum_offload(msdu); ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, is_decrypted); @@ -2064,7 +2154,8 @@ static int ath10k_htt_rx_handle_amsdu(st ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter); - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0, + false); msdus_to_queue = skb_queue_len(&amsdu); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); @@ -3014,7 +3105,7 @@ static int ath10k_htt_rx_in_ord_ind(stru ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL, - NULL); + NULL, peer_id, frag); ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: