mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-21 19:31:55 +00:00
142 lines
4.7 KiB
Diff
142 lines
4.7 KiB
Diff
From ceb2fcfd062fc4ab8180019b00e62fc292ece4d2 Mon Sep 17 00:00:00 2001
|
|
From: Manish Dharanenthiran <quic_mdharane@quicinc.com>
|
|
Date: Fri, 4 Nov 2022 10:23:58 +0530
|
|
Subject: [PATCH] ath12k: [WAR] Add warning to detect buffer overflow
|
|
|
|
During Mesh 4 node testing, ath12k receives
|
|
SKB with header length greater than the MAX
|
|
native wifi header length. Because of which,
|
|
buffer overflow happens during undecap wifi.
|
|
|
|
To prevent overflow, added warning before
|
|
decap and stopped processing the SKB. Also,
|
|
dumped the msdu data for debugging purpose.
|
|
|
|
Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
|
|
---
|
|
drivers/net/wireless/ath/ath12k/dp_rx.c | 57 +++++++++++++++++++++++--
|
|
1 file changed, 54 insertions(+), 3 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
|
|
@@ -2239,6 +2239,31 @@ static int ath12k_dp_rx_crypto_icv_len(s
|
|
return 0;
|
|
}
|
|
|
|
+static int ath12k_dp_rx_check_msdu_header_len(struct ath12k *ar,
|
|
+ struct hal_rx_desc *rx_desc,
|
|
+ struct sk_buff *msdu)
|
|
+{
|
|
+ struct ath12k_base *ab = ar->ab;
|
|
+ struct ieee80211_hdr *hdr;
|
|
+ u32 hdr_len;
|
|
+ u8 decap_type;
|
|
+
|
|
+ decap_type = ath12k_dp_rx_h_decap_type(ab, rx_desc);
|
|
+ if (decap_type == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
|
|
+ hdr = (struct ieee80211_hdr *)msdu->data;
|
|
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
|
+ if (unlikely(hdr_len > DP_MAX_NWIFI_HDR_LEN)) {
|
|
+ ab->soc_stats.invalid_rbm++;
|
|
+ ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "msdu_data",
|
|
+ msdu->data, msdu->len);
|
|
+ ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "rx_desc",
|
|
+ rx_desc, sizeof(*rx_desc));
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
static void ath12k_dp_rx_h_undecap_nwifi(struct ath12k *ar,
|
|
struct sk_buff *msdu,
|
|
enum hal_encrypt_type enctype,
|
|
@@ -2246,7 +2271,7 @@ 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];
|
|
+ u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN] = {0};
|
|
struct ieee80211_hdr *hdr;
|
|
size_t hdr_len;
|
|
u8 *crypto_hdr;
|
|
@@ -2270,8 +2295,13 @@ 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);
|
|
+ if (hdr_len > DP_MAX_NWIFI_HDR_LEN) {
|
|
+ ath12k_err(ab, "hdr len received in %s is greater than MAX LEN [%u > %d]\n",
|
|
+ __func__, (unsigned int)hdr_len, DP_MAX_NWIFI_HDR_LEN);
|
|
+ } else {
|
|
+ /* 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)) {
|
|
@@ -2284,7 +2314,8 @@ static void ath12k_dp_rx_h_undecap_nwifi
|
|
memcpy(skb_push(msdu,
|
|
IEEE80211_QOS_CTL_LEN), &qos_ctl,
|
|
IEEE80211_QOS_CTL_LEN);
|
|
- memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len);
|
|
+ memcpy(skb_push(msdu, hdr_len), decap_hdr[0] ? decap_hdr : (uint8_t *)hdr,
|
|
+ hdr_len);
|
|
}
|
|
|
|
static void ath12k_dp_rx_h_undecap_raw(struct ath12k *ar, struct sk_buff *msdu,
|
|
@@ -2935,6 +2966,11 @@ static int ath12k_dp_rx_process_msdu(str
|
|
}
|
|
}
|
|
|
|
+ if (ath12k_dp_rx_check_msdu_header_len(ar, rx_desc, msdu)) {
|
|
+ ret = -EINVAL;
|
|
+ goto free_out;
|
|
+ }
|
|
+
|
|
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status, fast_rx);
|
|
if (*fast_rx)
|
|
return 0;
|
|
@@ -3288,6 +3324,9 @@ mic_fail:
|
|
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
|
|
skb_pull(msdu, hal_rx_desc_sz);
|
|
|
|
+ if (ath12k_dp_rx_check_msdu_header_len(ar, rx_desc, msdu))
|
|
+ return -EINVAL;
|
|
+
|
|
ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
|
|
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
|
|
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
|
|
@@ -3999,6 +4038,10 @@ static int ath12k_dp_rx_h_null_q_desc(st
|
|
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
|
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
|
}
|
|
+
|
|
+ if (ath12k_dp_rx_check_msdu_header_len(ar, desc, msdu))
|
|
+ return -EINVAL;
|
|
+
|
|
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
|
fast_rx = false;
|
|
ath12k_dp_rx_h_mpdu(ar, msdu, desc, status, &fast_rx);
|
|
@@ -4084,6 +4127,9 @@ static bool ath12k_dp_rx_h_tkip_mic_err(
|
|
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
|
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
|
|
|
+ if (ath12k_dp_rx_check_msdu_header_len(ar, desc, msdu))
|
|
+ return true;
|
|
+
|
|
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
|
|
|
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
|
|
@@ -4125,6 +4171,9 @@ static bool ath12k_dp_rx_h_4addr_null_fr
|
|
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
|
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
|
|
|
+ if (ath12k_dp_rx_check_msdu_header_len(ar, rx_desc, msdu))
|
|
+ return true;
|
|
+
|
|
ath12k_dp_rx_h_ppdu(ar, rx_desc, status);
|
|
|
|
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, status, &fast_rx);
|