Commit 9a0dddfb authored by Manish Dharanenthiran's avatar Manish Dharanenthiran Committed by Jeff Johnson
Browse files

wifi: ath12k: Fix invalid data access in ath12k_dp_rx_h_undecap_nwifi



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: default avatarManish Dharanenthiran <quic_mdharane@quicinc.com>
Signed-off-by: default avatarTamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Link: https://patch.msgid.link/20250211090302.4105141-1-tamizh.raja@oss.qualcomm.com


Signed-off-by: default avatarJeff Johnson <jeff.johnson@oss.qualcomm.com>
parent d2d9c9b8
Loading
Loading
Loading
Loading
+40 −2
Original line number Diff line number Diff line
@@ -2548,6 +2548,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);
}

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,
				     struct sk_buff *msdu,
				     struct sk_buff_head *msdu_list,
@@ -2606,6 +2629,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_mpdu(ar, msdu, rx_desc, rx_status);

@@ -2996,6 +3024,9 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer
		    RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
	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_undecap(ar, msdu, rx_desc,
			       HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
@@ -3738,6 +3769,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_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_mpdu(ar, msdu, desc, status);
@@ -3782,7 +3816,7 @@ static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu,
	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 ath12k_base *ab = ar->ab;
@@ -3800,6 +3834,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_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);

	status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
@@ -3807,6 +3844,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,
			       HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
	return false;
}

static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar,  struct sk_buff *msdu,
@@ -3825,7 +3863,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:
		err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
		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;
		}
		fallthrough;