ath11k.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control
@ 2020-11-19 15:42 Sven Eckelmann
  2020-11-19 15:42 ` [PATCH v2 2/3] ath11k: Reset ath11k_skb_cb before setting new flags Sven Eckelmann
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Sven Eckelmann @ 2020-11-19 15:42 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless, Sven Eckelmann

The driver_data area of ieee80211_tx_info is used in ath11k for
ath11k_skb_cb. The first function in the TX patch which rewrites it to
ath11k_skb_cb is already ath11k_mac_op_tx. No one else in the code path
must use it for something else before it reinitializes it. Otherwise the
data has to be considered uninitialized or corrupt.

But the ieee80211_tx_info.control shares exactly the same area as
ieee80211_tx_info.driver_data and ath11k is still using it. This results in
best case in a

  ath11k c000000.wifi1: no vif found for mgmt frame, flags 0x0

or (slightly worse) in a kernel oops.

Instead, the interesting data must be moved first into the ath11k_skb_cb
and ieee80211_tx_info.control must then not be used anymore.

Tested-on: IPQ8074 hw2.0 WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2

Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
v2:
- added cipher to cb to handle HAL_TCL_ENCAP_TYPE_RAW in ath11k_dp_tx

  + used u32 for the cipher instead of 8 byte point (aarch64) to save some
    space

 drivers/net/wireless/ath/ath11k/core.h  |  2 ++
 drivers/net/wireless/ath/ath11k/dp_tx.c |  5 ++---
 drivers/net/wireless/ath/ath11k/mac.c   | 26 ++++++++++++++++---------
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 18b97420f0d8..5a7915f75e1e 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -75,12 +75,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
 
 enum ath11k_skb_flags {
 	ATH11K_SKB_HW_80211_ENCAP = BIT(0),
+	ATH11K_SKB_CIPHER_SET = BIT(1),
 };
 
 struct ath11k_skb_cb {
 	dma_addr_t paddr;
 	u8 eid;
 	u8 flags;
+	u32 cipher;
 	struct ath11k *ar;
 	struct ieee80211_vif *vif;
 } __packed;
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index 3d962eee4d61..21dfd08d3deb 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -84,7 +84,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
 	struct ath11k_dp *dp = &ab->dp;
 	struct hal_tx_info ti = {0};
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_key_conf *key = info->control.hw_key;
 	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
 	struct hal_srng *tcl_ring;
 	struct ieee80211_hdr *hdr = (void *)skb->data;
@@ -149,9 +148,9 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
 	ti.meta_data_flags = arvif->tcl_metadata;
 
 	if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) {
-		if (key) {
+		if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) {
 			ti.encrypt_type =
-				ath11k_dp_tx_get_encrypt_type(key->cipher);
+				ath11k_dp_tx_get_encrypt_type(skb_cb->cipher);
 
 			if (ieee80211_has_protected(hdr->frame_control))
 				skb_put(skb, IEEE80211_CCMP_MIC_LEN);
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 7f8dd47d2333..05ed6ec99b55 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -3977,21 +3977,20 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
 static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
 {
 	struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work);
-	struct ieee80211_tx_info *info;
+	struct ath11k_skb_cb *skb_cb;
 	struct ath11k_vif *arvif;
 	struct sk_buff *skb;
 	int ret;
 
 	while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
-		info = IEEE80211_SKB_CB(skb);
-		if (!info->control.vif) {
-			ath11k_warn(ar->ab, "no vif found for mgmt frame, flags 0x%x\n",
-				    info->control.flags);
+		skb_cb = ATH11K_SKB_CB(skb);
+		if (!skb_cb->vif) {
+			ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
 			ieee80211_free_txskb(ar->hw, skb);
 			continue;
 		}
 
-		arvif = ath11k_vif_to_arvif(info->control.vif);
+		arvif = ath11k_vif_to_arvif(skb_cb->vif);
 		if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
 		    arvif->is_started) {
 			ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
@@ -4004,8 +4003,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
 			}
 		} else {
 			ath11k_warn(ar->ab,
-				    "dropping mgmt frame for vdev %d, flags 0x%x is_started %d\n",
-				    arvif->vdev_id, info->control.flags,
+				    "dropping mgmt frame for vdev %d, is_started %d\n",
+				    arvif->vdev_id,
 				    arvif->is_started);
 			ieee80211_free_txskb(ar->hw, skb);
 		}
@@ -4053,10 +4052,19 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
 	struct ieee80211_vif *vif = info->control.vif;
 	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_key_conf *key = info->control.hw_key;
+	u32 info_flags = info->flags;
 	bool is_prb_rsp;
 	int ret;
 
-	if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
+	skb_cb->vif = vif;
+
+	if (key) {
+		skb_cb->cipher = key->cipher;
+		skb_cb->flags |= ATH11K_SKB_CIPHER_SET;
+	}
+
+	if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
 		skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
 	} else if (ieee80211_is_mgmt(hdr->frame_control)) {
 		is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
-- 
2.29.2


-- 
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] ath11k: Reset ath11k_skb_cb before setting new flags
  2020-11-19 15:42 [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Sven Eckelmann
@ 2020-11-19 15:42 ` Sven Eckelmann
  2020-11-19 15:42 ` [PATCH v2 3/3] ath11k: Build check size of ath11k_skb_cb Sven Eckelmann
  2020-12-02 18:19 ` [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Kalle Valo
  2 siblings, 0 replies; 4+ messages in thread
From: Sven Eckelmann @ 2020-11-19 15:42 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless, Sven Eckelmann

It was observed that the codepath for the ATH11K_SKB_HW_80211_ENCAP was
used even when the IEEE80211_TX_CTRL_HW_80211_ENCAP was not enabled for a
an skbuff. This became even more prominent when the QCAs wlan-open patchset
for ath11k [1] was applied and a sane looking fix just caused crashes when
injecting frames via a monitor interface (for example with ratechecker):

  [   86.963152] Unable to handle kernel NULL pointer dereference at virtual address 00000338
  [   86.963192] pgd = ffffffc0008f0000
  [   86.971034] [00000338] *pgd=0000000051706003, *pud=0000000051706003, *pmd=0000000051707003, *pte=00e800000b000707
  [   86.984292] Internal error: Oops: 96000006 [#1] PREEMPT SMP
  [...]
  [   87.713339] [<ffffffbffc802480>] ieee80211_tx_status_8023+0xf8/0x220 [mac80211]
  [   87.715654] [<ffffffbffc98bad4>] ath11k_dp_tx_completion_handler+0x42c/0xa10 [ath11k]
  [   87.722924] [<ffffffbffc989190>] ath11k_dp_service_srng+0x70/0x3c8 [ath11k]
  [   87.730831] [<ffffffbffca03460>] 0xffffffbffca03460
  [   87.737599] [<ffffffc00046ef58>] net_rx_action+0xf8/0x288
  [   87.742462] [<ffffffc000097554>] __do_softirq+0xfc/0x220
  [   87.748014] [<ffffffc000097900>] irq_exit+0x98/0xe8
  [   87.753396] [<ffffffc0000cf188>] __handle_domain_irq+0x90/0xb8
  [   87.757999] [<ffffffc000081ca4>] gic_handle_irq+0x6c/0xc8
  [   87.763899] Exception stack(0xffffffc00081bdc0 to 0xffffffc00081bef0)

Problem is that the state of ath11k_skb_cb->flags must be considered
unknown and could contain anything when it is not manually initialized. So
it could also contain ATH11K_SKB_HW_80211_ENCAP. And this can result in the
code to assume that the ath11k_skb_cb->vif is set - even when this is not
always the case for non ATH11K_SKB_HW_80211_ENCAP transmissions.

Tested-on: IPQ8074 hw2.0 WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2

[1] https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches?h=NHSS.QSDK.11.4.r3
    (162 patches at the moment which are often not upstreamed but essential
     to get ath11k working)

Fixes: e7f33e0c52c0 ("ath11k: add tx hw 802.11 encapsulation offloading support")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
v2:
- nothing changed

 drivers/net/wireless/ath/ath11k/mac.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 05ed6ec99b55..591c4c57b61e 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4057,6 +4057,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
 	bool is_prb_rsp;
 	int ret;
 
+	memset(skb_cb, 0, sizeof(*skb_cb));
 	skb_cb->vif = vif;
 
 	if (key) {
-- 
2.29.2


-- 
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] ath11k: Build check size of ath11k_skb_cb
  2020-11-19 15:42 [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Sven Eckelmann
  2020-11-19 15:42 ` [PATCH v2 2/3] ath11k: Reset ath11k_skb_cb before setting new flags Sven Eckelmann
@ 2020-11-19 15:42 ` Sven Eckelmann
  2020-12-02 18:19 ` [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Kalle Valo
  2 siblings, 0 replies; 4+ messages in thread
From: Sven Eckelmann @ 2020-11-19 15:42 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless, Sven Eckelmann

It is rather easy to add more entries to ath11k_skb_cb while forgetting the
size limit of ieee80211_tx_info->driver_data. So just check this during the
build to reduce the change of accidental buffer overflow in the skbuff->cb.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
v2:
- new patch

 drivers/net/wireless/ath/ath11k/core.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 5a7915f75e1e..b5ca4455b2e0 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -909,6 +909,8 @@ static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state)
 
 static inline struct ath11k_skb_cb *ATH11K_SKB_CB(struct sk_buff *skb)
 {
+	BUILD_BUG_ON(sizeof(struct ath11k_skb_cb) >
+		     IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
 	return (struct ath11k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
 }
 
-- 
2.29.2


-- 
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control
  2020-11-19 15:42 [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Sven Eckelmann
  2020-11-19 15:42 ` [PATCH v2 2/3] ath11k: Reset ath11k_skb_cb before setting new flags Sven Eckelmann
  2020-11-19 15:42 ` [PATCH v2 3/3] ath11k: Build check size of ath11k_skb_cb Sven Eckelmann
@ 2020-12-02 18:19 ` Kalle Valo
  2 siblings, 0 replies; 4+ messages in thread
From: Kalle Valo @ 2020-12-02 18:19 UTC (permalink / raw)
  To: Sven Eckelmann; +Cc: linux-wireless, ath11k

Sven Eckelmann <sven@narfation.org> wrote:

> The driver_data area of ieee80211_tx_info is used in ath11k for
> ath11k_skb_cb. The first function in the TX patch which rewrites it to
> ath11k_skb_cb is already ath11k_mac_op_tx. No one else in the code path
> must use it for something else before it reinitializes it. Otherwise the
> data has to be considered uninitialized or corrupt.
> 
> But the ieee80211_tx_info.control shares exactly the same area as
> ieee80211_tx_info.driver_data and ath11k is still using it. This results in
> best case in a
> 
>   ath11k c000000.wifi1: no vif found for mgmt frame, flags 0x0
> 
> or (slightly worse) in a kernel oops.
> 
> Instead, the interesting data must be moved first into the ath11k_skb_cb
> and ieee80211_tx_info.control must then not be used anymore.
> 
> Tested-on: IPQ8074 hw2.0 WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2
> 
> Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
> Signed-off-by: Sven Eckelmann <sven@narfation.org>
> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>

3 patches applied to ath-next branch of ath.git, thanks.

f4d291b43f80 ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control
5da7acfec5ec ath11k: Reset ath11k_skb_cb before setting new flags
d35d1375493b ath11k: Build check size of ath11k_skb_cb

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20201119154235.263250-1-sven@narfation.org/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


-- 
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-12-02 18:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-19 15:42 [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Sven Eckelmann
2020-11-19 15:42 ` [PATCH v2 2/3] ath11k: Reset ath11k_skb_cb before setting new flags Sven Eckelmann
2020-11-19 15:42 ` [PATCH v2 3/3] ath11k: Build check size of ath11k_skb_cb Sven Eckelmann
2020-12-02 18:19 ` [PATCH v2 1/3] ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).