* [PATCH ath-next 1/2] wifi: ath11k: fix invalid data access in ath11k_dp_rx_h_undecap_nwifi
2026-05-12 2:23 [PATCH ath-next 0/2] wifi: ath11k: dp rx sanity checks for invalid length in error paths Miaoqing Pan
@ 2026-05-12 2:23 ` Miaoqing Pan
2026-05-12 2:23 ` [PATCH ath-next 2/2] wifi: ath11k: add MSDU length validation for TKIP MIC error Miaoqing Pan
1 sibling, 0 replies; 3+ messages in thread
From: Miaoqing Pan @ 2026-05-12 2:23 UTC (permalink / raw)
To: jjohnson; +Cc: ath11k, linux-wireless, linux-kernel, Miaoqing Pan
In certain cases, hardware might provide packets with a
length greater than the maximum native Wi-Fi header length.
This can lead to accessing and modifying fields in the header
within the ath11k_dp_rx_h_undecap_nwifi() function for the
DP_RX_DECAP_TYPE_NATIVE_WIFI decap type and
potentially result in invalid data access and memory corruption.
Kernel stack is corrupted in: ath11k_dp_rx_h_undecap+0x6b0/0x6b0 [ath11k]
Call trace:
ath11k_dp_rx_h_mpdu+0x0/0x2e8 [ath11k]
ath11k_dp_rx_h_mpdu+0x1e0/0x2e8 [ath11k]
ath11k_dp_rx_wbm_err+0x1e0/0x450 [ath11k]
ath11k_dp_rx_process_wbm_err+0x2fc/0x460 [ath11k]
ath11k_dp_service_srng+0x2e0/0x348 [ath11k]
Add a sanity check before processing the SKB to prevent invalid
data access in the undecap native Wi-Fi function for the
DP_RX_DECAP_TYPE_NATIVE_WIFI decap type.
This adapted from the discussion/patch of the ath12k driver [1].
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1
Link: https://lore.kernel.org/linux-wireless/20250211090302.4105141-1-tamizh.raja@oss.qualcomm.com/ # [1]
Signed-off-by: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath11k/dp_rx.c | 50 +++++++++++++++++++++++--
1 file changed, 47 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index fe79109adc70..fbe2061a544d 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -2502,6 +2502,29 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
}
+static bool ath11k_dp_rx_check_nwifi_hdr_len_valid(struct ath11k_base *ab,
+ struct hal_rx_desc *rx_desc,
+ struct sk_buff *msdu)
+{
+ struct ieee80211_hdr *hdr;
+ u8 decap_type;
+ u32 hdr_len;
+
+ decap_type = ath11k_dp_rx_h_msdu_start_decap_type(ab, rx_desc);
+ if (decap_type != DP_RX_DECAP_TYPE_NATIVE_WIFI)
+ return true;
+
+ hdr = (struct ieee80211_hdr *)msdu->data;
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+ if ((likely(hdr_len <= DP_MAX_NWIFI_HDR_LEN)))
+ return true;
+
+ ab->soc_stats.invalid_rbm++;
+ WARN_ON_ONCE(1);
+ return false;
+}
+
static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
struct sk_buff *msdu,
struct sk_buff_head *msdu_list,
@@ -2572,6 +2595,11 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
}
}
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
+ ret = -EINVAL;
+ goto free_out;
+ }
+
ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
@@ -3261,6 +3289,12 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, rx_desc,
+ msdu))) {
+ dev_kfree_skb_any(msdu);
+ return -EINVAL;
+ }
+
ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
@@ -3953,6 +3987,10 @@ static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
}
+
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, desc, msdu)))
+ return -EINVAL;
+
ath11k_dp_rx_h_ppdu(ar, desc, status);
ath11k_dp_rx_h_mpdu(ar, msdu, desc, status);
@@ -3997,7 +4035,7 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu,
return drop;
}
-static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
+static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
u16 msdu_len;
@@ -4005,6 +4043,7 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
u8 l3pad_bytes;
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
+ struct ath11k_base *ab = ar->ab;
rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc);
rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc);
@@ -4014,6 +4053,9 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
+ return true;
+
ath11k_dp_rx_h_ppdu(ar, desc, status);
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
@@ -4021,19 +4063,21 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
ath11k_dp_rx_h_undecap(ar, msdu, desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
+
+ return false;
}
static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
- bool drop = false;
+ bool drop;
ar->ab->soc_stats.rxdma_error[rxcb->err_code]++;
switch (rxcb->err_code) {
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
- ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
+ drop = ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
break;
default:
/* TODO: Review other rxdma error code to check if anything is
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH ath-next 2/2] wifi: ath11k: add MSDU length validation for TKIP MIC error
2026-05-12 2:23 [PATCH ath-next 0/2] wifi: ath11k: dp rx sanity checks for invalid length in error paths Miaoqing Pan
2026-05-12 2:23 ` [PATCH ath-next 1/2] wifi: ath11k: fix invalid data access in ath11k_dp_rx_h_undecap_nwifi Miaoqing Pan
@ 2026-05-12 2:23 ` Miaoqing Pan
1 sibling, 0 replies; 3+ messages in thread
From: Miaoqing Pan @ 2026-05-12 2:23 UTC (permalink / raw)
To: jjohnson; +Cc: ath11k, linux-wireless, linux-kernel, Miaoqing Pan
In the WBM error path, while processing TKIP MIC errors, MSDU length
is fetched from the hal_rx_desc's msdu_end. This MSDU length is
directly passed to skb_put() without validation. In stress test
scenarios, the WBM error ring may receive invalid descriptors, which
could lead to an invalid MSDU length.
To fix this, add a check to drop the skb when the calculated MSDU
length is greater than the skb size.
This is adapted from the discussion/patch of the ath12k driver [1].
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1
Link: https://lore.kernel.org/linux-wireless/20250416021903.3178962-1-nithyanantham.paramasivam@oss.qualcomm.com/ # [1]
Signed-off-by: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath11k/dp_rx.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index fbe2061a544d..9c31bb7efcc8 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -4050,6 +4050,15 @@ static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
+
+ if (unlikely(hal_rx_desc_sz + l3pad_bytes + msdu_len > DP_RX_BUFFER_SIZE)) {
+ ath11k_dbg(ab, ATH11K_DBG_DATA,
+ "invalid msdu len in tkip mic err %u\n", msdu_len);
+ ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", desc,
+ sizeof(*desc));
+ return true;
+ }
+
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread