From b5d7239d873fa775420d6f36c9703999a95c032c Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 21 Jun 2023 14:55:11 +0530 Subject: [PATCH 1/2] wifi: ath12k: fix array out of bound in undecap native wifi frame path Randomly in undecap native wifi path, msdu header frame control has QoS data. which is wrong because QoS not present in native wifi frame. so when we take a copy of native wifi header, the destination array get out of bound access due to the addition of unexpected QoS length from source. Fix this issue by reset the QoS length, Order length and recalculate the header length then proceed the undecap procedure without the local array and remove the unused define. Signed-off-by: Karthikeyan Periyasamy --- drivers/net/wireless/ath/ath12k/dp_rx.c | 33 ++++++++++++++----------- drivers/net/wireless/ath/ath12k/dp_rx.h | 3 --- 2 files changed, 18 insertions(+), 18 deletions(-) --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2407,23 +2407,27 @@ static void ath12k_dp_rx_h_undecap_nwifi { struct ath12k_base *ab = ar->ab; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN]; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr hdr; size_t hdr_len; int expand_by = 0; u8 *crypto_hdr; - u16 qos_ctl = 0; + u16 qos_ctl; /* pull decapped header */ - hdr = (struct ieee80211_hdr *)msdu->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); + hdr = *((struct ieee80211_hdr *)msdu->data); + hdr_len = ieee80211_hdrlen(hdr.frame_control); skb_pull(msdu, hdr_len); - /* Rebuild qos header */ - hdr->frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + /* FIXME Nwifi header should not exceed struct ieee80211_hdr size (30) */ + WARN_ON_ONCE(hdr_len > sizeof(hdr)); - /* Reset the order bit as the HT_Control header is stripped */ - hdr->frame_control &= ~(__cpu_to_le16(IEEE80211_FCTL_ORDER)); + /* + * Reset the QoS bit since it is nwifi frame + * Reset the order bit as the HT_Control header is stripped + */ + hdr.frame_control &= ~(__cpu_to_le16(IEEE80211_STYPE_QOS_DATA) | + __cpu_to_le16(IEEE80211_FCTL_ORDER)); + hdr_len = ieee80211_hdrlen(hdr.frame_control); qos_ctl = rxcb->tid; @@ -2432,9 +2436,6 @@ static void ath12k_dp_rx_h_undecap_nwifi /* TODO Add other QoS ctl fields when required */ - /* copy decap header before overwriting for reuse below */ - memcpy(decap_hdr, (uint8_t *)hdr, hdr_len); - /* Rebuild crypto header for mac80211 use */ if (!(status->flag & RX_FLAG_IV_STRIPPED)) { if (skb_headroom(msdu) < ath12k_dp_rx_crypto_param_len(ar, enctype)) { @@ -2453,16 +2454,21 @@ static void ath12k_dp_rx_h_undecap_nwifi if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) return; } + + /* Rebuild qos header */ memcpy(skb_push(msdu, IEEE80211_QOS_CTL_LEN), &qos_ctl, IEEE80211_QOS_CTL_LEN); + hdr.frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + if (skb_headroom(msdu) < hdr_len) { expand_by = hdr_len - skb_headroom(msdu); if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) return; } - memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); + + memcpy(skb_push(msdu, hdr_len), &hdr, hdr_len); } static void ath12k_dp_rx_h_undecap_raw(struct ath12k *ar, struct sk_buff *msdu, @@ -3164,7 +3170,7 @@ static bool ath12k_dp_rx_check_max_nwifi hdr = (struct ieee80211_hdr *)msdu->data; hdr_len = ieee80211_hdrlen(hdr->frame_control); - if (unlikely(hdr_len > DP_MAX_NWIFI_HDR_LEN)) { + if (unlikely(hdr_len > sizeof(*hdr))) { ab->soc_stats.invalid_rbm++; ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "msdu_data", msdu->data, msdu->len); --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -10,9 +10,6 @@ #include "rx_desc.h" #include "debug.h" -#define DP_MAX_NWIFI_HDR_LEN 30 - - /* different supported pkt types for routing */ enum ath12k_routing_pkt_type { ATH12K_PKT_TYPE_ARP_IPV4,