[RFC PATCH] ath10k-ct: backport upstream fixes for FragAttacks

Hauke Mehrtens hauke at hauke-m.de
Sun May 16 08:16:09 PDT 2021


This applies the FragAttack patches also to ath10k-ct.

Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---

I do not have a ath10k device close here at the moment, it would be nice 
if someone could check if this works fine.

 package/kernel/ath10k-ct/Makefile             |   2 +-
 ...PN-replay-protection-for-fragmented-.patch | 180 ++++++++++++++++++
 ...fragments-with-multicast-DA-for-PCIe.patch |  66 +++++++
 ...fragments-with-multicast-DA-for-SDIO.patch |  40 ++++
 ...-which-has-discard-flag-set-by-firmw.patch |  54 ++++++
 ...IP-Michael-MIC-verification-for-PCIe.patch |  48 +++++
 ...first-subframe-of-A-MSDU-before-proc.patch | 109 +++++++++++
 7 files changed, 498 insertions(+), 1 deletion(-)
 create mode 100644 package/kernel/ath10k-ct/patches/300-ath10k-add-CCMP-PN-replay-protection-for-fragmented-.patch
 create mode 100644 package/kernel/ath10k-ct/patches/301-ath10k-drop-fragments-with-multicast-DA-for-PCIe.patch
 create mode 100644 package/kernel/ath10k-ct/patches/302-ath10k-drop-fragments-with-multicast-DA-for-SDIO.patch
 create mode 100644 package/kernel/ath10k-ct/patches/303-ath10k-drop-MPDU-which-has-discard-flag-set-by-firmw.patch
 create mode 100644 package/kernel/ath10k-ct/patches/304-ath10k-Fix-TKIP-Michael-MIC-verification-for-PCIe.patch
 create mode 100644 package/kernel/ath10k-ct/patches/305-ath10k-Validate-first-subframe-of-A-MSDU-before-proc.patch

diff --git a/package/kernel/ath10k-ct/Makefile b/package/kernel/ath10k-ct/Makefile
index a225bd8b191f..d6ad53fb5871 100644
--- a/package/kernel/ath10k-ct/Makefile
+++ b/package/kernel/ath10k-ct/Makefile
@@ -1,7 +1,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ath10k-ct
-PKG_RELEASE=2
+PKG_RELEASE=3
 
 PKG_LICENSE:=GPLv2
 PKG_LICENSE_FILES:=
diff --git a/package/kernel/ath10k-ct/patches/300-ath10k-add-CCMP-PN-replay-protection-for-fragmented-.patch b/package/kernel/ath10k-ct/patches/300-ath10k-add-CCMP-PN-replay-protection-for-fragmented-.patch
new file mode 100644
index 000000000000..89d4237d3409
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/300-ath10k-add-CCMP-PN-replay-protection-for-fragmented-.patch
@@ -0,0 +1,180 @@
+From: Wen Gong <wgong at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:52 +0200
+Subject: [PATCH] ath10k: add CCMP PN replay protection for fragmented
+ frames for PCIe
+
+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 at vger.kernel.org
+Signed-off-by: Wen Gong <wgong at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt.h
++++ b/ath10k-5.10/htt.h
+@@ -853,6 +853,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 0x3F
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -1841,16 +1841,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;
+@@ -1863,6 +1934,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;
+@@ -1970,6 +2042,24 @@ static void ath10k_htt_rx_h_mpdu(struct
+ #ifdef CONFIG_ATH10K_DEBUGFS
+ 		ar->debug.rx_bytes += msdu->len;
+ #endif
++		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);
+@@ -2186,7 +2276,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);
+ 
+@@ -3291,7 +3382,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:
diff --git a/package/kernel/ath10k-ct/patches/301-ath10k-drop-fragments-with-multicast-DA-for-PCIe.patch b/package/kernel/ath10k-ct/patches/301-ath10k-drop-fragments-with-multicast-DA-for-PCIe.patch
new file mode 100644
index 000000000000..129cd894c072
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/301-ath10k-drop-fragments-with-multicast-DA-for-PCIe.patch
@@ -0,0 +1,66 @@
+From: Wen Gong <wgong at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:53 +0200
+Subject: [PATCH] ath10k: drop fragments with multicast DA for PCIe
+
+Fragmentation is not used with multicast frames. Discard unexpected
+fragments with multicast DA. This fixes CVE-2020-26145.
+
+Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1
+
+Cc: stable at vger.kernel.org
+Signed-off-by: Wen Gong <wgong at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -1863,6 +1863,16 @@ static u64 ath10k_htt_rx_h_get_pn(struct
+ 	return pn;
+ }
+ 
++static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar,
++						 struct sk_buff *skb,
++						 u16 offset)
++{
++	struct ieee80211_hdr *hdr;
++
++	hdr = (struct ieee80211_hdr *)(skb->data + offset);
++	return !is_multicast_ether_addr(hdr->addr1);
++}
++
+ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
+ 					  struct sk_buff *skb,
+ 					  u16 peer_id,
+@@ -1934,7 +1944,7 @@ static void ath10k_htt_rx_h_mpdu(struct
+ 	bool is_decrypted;
+ 	bool is_mgmt;
+ 	u32 attention;
+-	bool frag_pn_check = true;
++	bool frag_pn_check = true, multicast_check = true;
+ 
+ 	if (skb_queue_empty(amsdu))
+ 		return;
+@@ -2050,13 +2060,20 @@ static void ath10k_htt_rx_h_mpdu(struct
+ 								      0,
+ 								      enctype);
+ 
+-		if (!frag_pn_check) {
+-			/* Discard the fragment with invalid PN */
++		if (frag)
++			multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar,
++									       msdu,
++									       0);
++
++		if (!frag_pn_check || !multicast_check) {
++			/* Discard the fragment with invalid PN or multicast DA
++			 */
+ 			temp = msdu->prev;
+ 			__skb_unlink(msdu, amsdu);
+ 			dev_kfree_skb_any(msdu);
+ 			msdu = temp;
+ 			frag_pn_check = true;
++			multicast_check = true;
+ 			continue;
+ 		}
+ 
diff --git a/package/kernel/ath10k-ct/patches/302-ath10k-drop-fragments-with-multicast-DA-for-SDIO.patch b/package/kernel/ath10k-ct/patches/302-ath10k-drop-fragments-with-multicast-DA-for-SDIO.patch
new file mode 100644
index 000000000000..cfd7365f1a43
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/302-ath10k-drop-fragments-with-multicast-DA-for-SDIO.patch
@@ -0,0 +1,40 @@
+From: Wen Gong <wgong at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:54 +0200
+Subject: [PATCH] ath10k: drop fragments with multicast DA for SDIO
+
+Fragmentation is not used with multicast frames. Discard unexpected
+fragments with multicast DA. This fixes CVE-2020-26145.
+
+Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00049
+
+Cc: stable at vger.kernel.org
+Signed-off-by: Wen Gong <wgong at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -2732,6 +2732,13 @@ static bool ath10k_htt_rx_proc_rx_frag_i
+ 	rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len);
+ 	rx_desc_info = __le32_to_cpu(rx_desc->info);
+ 
++	hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
++
++	if (is_multicast_ether_addr(hdr->addr1)) {
++		/* Discard the fragment with multicast DA */
++		goto err;
++	}
++
+ 	if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) {
+ 		spin_unlock_bh(&ar->data_lock);
+ 		return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
+@@ -2739,8 +2746,6 @@ static bool ath10k_htt_rx_proc_rx_frag_i
+ 						    HTT_RX_NON_TKIP_MIC);
+ 	}
+ 
+-	hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
+-
+ 	if (ieee80211_has_retry(hdr->frame_control))
+ 		goto err;
+ 
diff --git a/package/kernel/ath10k-ct/patches/303-ath10k-drop-MPDU-which-has-discard-flag-set-by-firmw.patch b/package/kernel/ath10k-ct/patches/303-ath10k-drop-MPDU-which-has-discard-flag-set-by-firmw.patch
new file mode 100644
index 000000000000..311b57a12e54
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/303-ath10k-drop-MPDU-which-has-discard-flag-set-by-firmw.patch
@@ -0,0 +1,54 @@
+From: Wen Gong <wgong at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:55 +0200
+Subject: [PATCH] ath10k: drop MPDU which has discard flag set by firmware
+ for SDIO
+
+When the discard flag is set by the firmware for an MPDU, it should be
+dropped. This allows a mitigation for CVE-2020-24588 to be implemented
+in the firmware.
+
+Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00049
+
+Cc: stable at vger.kernel.org
+Signed-off-by: Wen Gong <wgong at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -2427,6 +2427,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl
+ 	fw_desc = &rx->fw_desc;
+ 	rx_desc_len = fw_desc->len;
+ 
++	if (fw_desc->u.bits.discard) {
++		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt discard mpdu\n");
++		goto err;
++	}
++
+ 	/* I have not yet seen any case where num_mpdu_ranges > 1.
+ 	 * qcacld does not seem handle that case either, so we introduce the
+ 	 * same limitiation here as well.
+--- a/ath10k-5.10/rx_desc.h
++++ b/ath10k-5.10/rx_desc.h
+@@ -1283,7 +1283,19 @@ struct fw_rx_desc_base {
+ #define FW_RX_DESC_UDP              (1 << 6)
+ 
+ struct fw_rx_desc_hl {
+-	u8 info0;
++	union {
++		struct {
++		u8 discard:1,
++		   forward:1,
++		   any_err:1,
++		   dup_err:1,
++		   reserved:1,
++		   inspect:1,
++		   extension:2;
++		} bits;
++		u8 info0;
++	} u;
++
+ 	u8 version;
+ 	u8 len;
+ 	u8 flags;
diff --git a/package/kernel/ath10k-ct/patches/304-ath10k-Fix-TKIP-Michael-MIC-verification-for-PCIe.patch b/package/kernel/ath10k-ct/patches/304-ath10k-Fix-TKIP-Michael-MIC-verification-for-PCIe.patch
new file mode 100644
index 000000000000..f556e58eb198
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/304-ath10k-Fix-TKIP-Michael-MIC-verification-for-PCIe.patch
@@ -0,0 +1,48 @@
+From: Wen Gong <wgong at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:56 +0200
+Subject: [PATCH] ath10k: Fix TKIP Michael MIC verification for PCIe
+
+TKIP Michael MIC was not verified properly for PCIe cases since the
+validation steps in ieee80211_rx_h_michael_mic_verify() in mac80211 did
+not get fully executed due to unexpected flag values in
+ieee80211_rx_status.
+
+Fix this by setting the flags property to meet mac80211 expectations for
+performing Michael MIC validation there. This fixes CVE-2020-26141. It
+does the same as ath10k_htt_rx_proc_rx_ind_hl() for SDIO which passed
+MIC verification case. This applies only to QCA6174/QCA9377 PCIe.
+
+Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1
+
+Cc: stable at vger.kernel.org
+Signed-off-by: Wen Gong <wgong at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -2078,6 +2078,11 @@ static void ath10k_htt_rx_h_mpdu(struct
+ 		}
+ 
+ 		ath10k_htt_rx_h_csum_offload(msdu);
++
++		if (frag && !fill_crypt_header &&
++		    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
++			status->flag &= ~RX_FLAG_MMIC_STRIPPED;
++
+ 		ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
+ 					is_decrypted);
+ 
+@@ -2095,6 +2100,11 @@ static void ath10k_htt_rx_h_mpdu(struct
+ 
+ 		hdr = (void *)msdu->data;
+ 		hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
++
++		if (frag && !fill_crypt_header &&
++		    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
++			status->flag &= ~RX_FLAG_IV_STRIPPED &
++					~RX_FLAG_MMIC_STRIPPED;
+ 	}
+ }
+ 
diff --git a/package/kernel/ath10k-ct/patches/305-ath10k-Validate-first-subframe-of-A-MSDU-before-proc.patch b/package/kernel/ath10k-ct/patches/305-ath10k-Validate-first-subframe-of-A-MSDU-before-proc.patch
new file mode 100644
index 000000000000..ae1a5c9df95d
--- /dev/null
+++ b/package/kernel/ath10k-ct/patches/305-ath10k-Validate-first-subframe-of-A-MSDU-before-proc.patch
@@ -0,0 +1,109 @@
+From: Sriram R <srirrama at codeaurora.org>
+Date: Tue, 11 May 2021 20:02:57 +0200
+Subject: [PATCH] ath10k: Validate first subframe of A-MSDU before
+ processing the list
+
+In certain scenarios a normal MSDU can be received as an A-MSDU when
+the A-MSDU present bit of a QoS header gets flipped during reception.
+Since this bit is unauthenticated, the hardware crypto engine can pass
+the frame to the driver without any error indication.
+
+This could result in processing unintended subframes collected in the
+A-MSDU list. Hence, validate A-MSDU list by checking if the first frame
+has a valid subframe header.
+
+Comparing the non-aggregated MSDU and an A-MSDU, the fields of the first
+subframe DA matches the LLC/SNAP header fields of a normal MSDU.
+In order to avoid processing such frames, add a validation to
+filter such A-MSDU frames where the first subframe header DA matches
+with the LLC/SNAP header pattern.
+
+Tested-on: QCA9984 hw1.0 PCI 10.4-3.10-00047
+
+Cc: stable at vger.kernel.org
+Signed-off-by: Sriram R <srirrama at codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/ath10k-5.10/htt_rx.c
++++ b/ath10k-5.10/htt_rx.c
+@@ -2217,14 +2217,62 @@ static void ath10k_htt_rx_h_unchain(stru
+ 	ath10k_unchain_msdu(ar, amsdu, unchain_cnt);
+ }
+ 
++static bool ath10k_htt_rx_validate_amsdu(struct ath10k *ar,
++					 struct sk_buff_head *amsdu)
++{
++	u8 *subframe_hdr;
++	struct sk_buff *first;
++	bool is_first, is_last;
++	struct htt_rx_desc *rxd;
++	struct ieee80211_hdr *hdr;
++	size_t hdr_len, crypto_len;
++	enum htt_rx_mpdu_encrypt_type enctype;
++	int bytes_aligned = ar->hw_params.decap_align_bytes;
++
++	first = skb_peek(amsdu);
++
++	rxd = (void *)first->data - sizeof(*rxd);
++	hdr = (void *)rxd->rx_hdr_status;
++
++	is_first = !!(rxd->msdu_end.common.info0 &
++		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
++	is_last = !!(rxd->msdu_end.common.info0 &
++		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
++
++	/* Return in case of non-aggregated msdu */
++	if (is_first && is_last)
++		return true;
++
++	/* First msdu flag is not set for the first msdu of the list */
++	if (!is_first)
++		return false;
++
++	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
++		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
++
++	hdr_len = ieee80211_hdrlen(hdr->frame_control);
++	crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
++
++	subframe_hdr = (u8 *)hdr + round_up(hdr_len, bytes_aligned) +
++		       crypto_len;
++
++	/* Validate if the amsdu has a proper first subframe.
++	 * There are chances a single msdu can be received as amsdu when
++	 * the unauthenticated amsdu flag of a QoS header
++	 * gets flipped in non-SPP AMSDU's, in such cases the first
++	 * subframe has llc/snap header in place of a valid da.
++	 * return false if the da matches rfc1042 pattern
++	 */
++	if (ether_addr_equal(subframe_hdr, rfc1042_header))
++		return false;
++
++	return true;
++}
++
+ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
+ 					struct sk_buff_head *amsdu,
+ 					struct ieee80211_rx_status *rx_status)
+ {
+-	/* FIXME: It might be a good idea to do some fuzzy-testing to drop
+-	 * invalid/dangerous frames.
+-	 */
+-
+ 	if (!rx_status->freq) {
+ 		ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n");
+ #ifdef CONFIG_ATH10K_DEBUGFS
+@@ -2241,6 +2289,11 @@ static bool ath10k_htt_rx_amsdu_allowed(
+ 		return false;
+ 	}
+ 
++	if (!ath10k_htt_rx_validate_amsdu(ar, amsdu)) {
++		ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid amsdu received\n");
++		return false;
++	}
++
+ 	return true;
+ }
+ 
-- 
2.30.2




More information about the openwrt-devel mailing list