wifi: ath12k: Fix invalid data access in ath12k_dp_rx_h_undecap_nwifi
[ Upstream commit 9a0dddfb30f120db3851627935851d262e4e7acb ] 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 ath12k_dp_rx_h_undecap_nwifi function for DP_RX_DECAP_TYPE_NATIVE_WIFI decap type and potentially resulting in invalid data access and memory corruption. 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. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1 Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com> Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com> Link: https://patch.msgid.link/20250211090302.4105141-1-tamizh.raja@oss.qualcomm.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
1833e16500
commit
3abe15e756
@@ -2470,6 +2470,29 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
|
|||||||
ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
|
ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
|
||||||
|
struct hal_rx_desc *rx_desc,
|
||||||
|
struct sk_buff *msdu)
|
||||||
|
{
|
||||||
|
struct ieee80211_hdr *hdr;
|
||||||
|
u8 decap_type;
|
||||||
|
u32 hdr_len;
|
||||||
|
|
||||||
|
decap_type = ath12k_dp_rx_h_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 ath12k_dp_rx_process_msdu(struct ath12k *ar,
|
static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
|
||||||
struct sk_buff *msdu,
|
struct sk_buff *msdu,
|
||||||
struct sk_buff_head *msdu_list,
|
struct sk_buff_head *msdu_list,
|
||||||
@@ -2528,6 +2551,11 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_out;
|
||||||
|
}
|
||||||
|
|
||||||
ath12k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
|
ath12k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
|
||||||
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
|
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
|
||||||
|
|
||||||
@@ -2880,6 +2908,9 @@ mic_fail:
|
|||||||
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
|
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
|
||||||
skb_pull(msdu, hal_rx_desc_sz);
|
skb_pull(msdu, hal_rx_desc_sz);
|
||||||
|
|
||||||
|
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
|
ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
|
||||||
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
|
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
|
||||||
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
|
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
|
||||||
@@ -3600,6 +3631,9 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
|
|||||||
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
||||||
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
||||||
}
|
}
|
||||||
|
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
||||||
|
|
||||||
ath12k_dp_rx_h_mpdu(ar, msdu, desc, status);
|
ath12k_dp_rx_h_mpdu(ar, msdu, desc, status);
|
||||||
@@ -3644,7 +3678,7 @@ static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu,
|
|||||||
return drop;
|
return drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
static bool ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||||
struct ieee80211_rx_status *status)
|
struct ieee80211_rx_status *status)
|
||||||
{
|
{
|
||||||
struct ath12k_base *ab = ar->ab;
|
struct ath12k_base *ab = ar->ab;
|
||||||
@@ -3662,6 +3696,9 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
|||||||
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
|
||||||
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
|
||||||
|
|
||||||
|
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
|
||||||
|
return true;
|
||||||
|
|
||||||
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
ath12k_dp_rx_h_ppdu(ar, desc, status);
|
||||||
|
|
||||||
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
|
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
|
||||||
@@ -3669,6 +3706,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
|
|||||||
|
|
||||||
ath12k_dp_rx_h_undecap(ar, msdu, desc,
|
ath12k_dp_rx_h_undecap(ar, msdu, desc,
|
||||||
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
|
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
|
static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
|
||||||
@@ -3687,7 +3725,7 @@ static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
|
|||||||
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
|
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
|
||||||
err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
|
err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
|
||||||
if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
|
if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
|
||||||
ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status);
|
drop = ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fallthrough;
|
fallthrough;
|
||||||
|
|||||||
Reference in New Issue
Block a user