Reject truncated raw frames before removing the FCS trailer. Without this check, subtracting FCS_LEN from a shorter skb underflows and leaves the FCS untrimmed. Also verify that the frame contains enough data for the 802.11 header and the crypto header before moving the header to make room for the crypto parameters. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Lorenzo Bianconi --- drivers/net/wireless/ath/ath12k/dp_rx.c | 46 ++++++++++++++++++--------- drivers/net/wireless/ath/ath12k/dp_rx.h | 10 +++--- drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 22 +++++++++---- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 36be543b7c50..40b8da34268f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -999,11 +999,11 @@ static void ath12k_dp_rx_h_undecap_nwifi(struct ath12k_pdev_dp *dp_pdev, memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); } -static void ath12k_dp_rx_h_undecap_raw(struct ath12k_pdev_dp *dp_pdev, - struct sk_buff *msdu, - enum hal_encrypt_type enctype, - struct ieee80211_rx_status *status, - bool decrypted) +static int ath12k_dp_rx_h_undecap_raw(struct ath12k_pdev_dp *dp_pdev, + struct sk_buff *msdu, + enum hal_encrypt_type enctype, + struct ieee80211_rx_status *status, + bool decrypted) { struct ath12k_dp *dp = dp_pdev->dp; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); @@ -1014,13 +1014,16 @@ static void ath12k_dp_rx_h_undecap_raw(struct ath12k_pdev_dp *dp_pdev, if (!rxcb->is_first_msdu || !(rxcb->is_first_msdu && rxcb->is_last_msdu)) { WARN_ON_ONCE(1); - return; + return 0; } + if (msdu->len < FCS_LEN) + return -EINVAL; + skb_trim(msdu, msdu->len - FCS_LEN); if (!decrypted) - return; + return 0; hdr = (void *)msdu->data; @@ -1054,9 +1057,14 @@ static void ath12k_dp_rx_h_undecap_raw(struct ath12k_pdev_dp *dp_pdev, hdr_len = ieee80211_hdrlen(hdr->frame_control); crypto_len = ath12k_dp_rx_crypto_param_len(dp_pdev, enctype); + if (msdu->len < hdr_len + crypto_len) + return -EINVAL; + memmove(msdu->data + crypto_len, msdu->data, hdr_len); skb_pull(msdu, crypto_len); } + + return 0; } static void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k_pdev_dp *dp_pdev, @@ -1143,11 +1151,11 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev, ether_addr_copy(ieee80211_get_SA(hdr), sa); } -void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, - enum hal_encrypt_type enctype, - bool decrypted, - struct hal_rx_desc_data *rx_info, - struct ath12k_dp_peer *peer) +int ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, + enum hal_encrypt_type enctype, + bool decrypted, + struct hal_rx_desc_data *rx_info, + struct ath12k_dp_peer *peer) { enum ath12k_dp_rx_decap_type decap_type = rx_info->decap_type; struct ethhdr *ehdr; @@ -1156,10 +1164,16 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu case DP_RX_DECAP_TYPE_NATIVE_WIFI: ath12k_dp_rx_h_undecap_nwifi(dp_pdev, msdu, enctype, rx_info); break; - case DP_RX_DECAP_TYPE_RAW: - ath12k_dp_rx_h_undecap_raw(dp_pdev, msdu, enctype, rx_info->rx_status, - decrypted); + case DP_RX_DECAP_TYPE_RAW: { + int err; + + err = ath12k_dp_rx_h_undecap_raw(dp_pdev, msdu, enctype, + rx_info->rx_status, + decrypted); + if (err) + return err; break; + } case DP_RX_DECAP_TYPE_ETHERNET2_DIX: ehdr = (struct ethhdr *)msdu->data; @@ -1201,6 +1215,8 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu } rx_info->rx_status->flag |= RX_FLAG_8023; } + + return 0; } EXPORT_SYMBOL(ath12k_dp_rx_h_undecap); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 82700474548a..68b80932e046 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -187,11 +187,11 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal, hal->ops->extract_rx_desc_data(rx_info, rx_desc, ldesc); } -void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, - enum hal_encrypt_type enctype, - bool decrypted, - struct hal_rx_desc_data *rx_info, - struct ath12k_dp_peer *peer); +int ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, + enum hal_encrypt_type enctype, + bool decrypted, + struct hal_rx_desc_data *rx_info, + struct ath12k_dp_peer *peer); void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struct *napi, struct sk_buff *msdu, struct hal_rx_desc_data *rx_info); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index a32c804403e8..e7afadf2bf2c 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -344,6 +344,7 @@ static int ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, struct ath12k_dp_peer *peer; struct ieee80211_rx_status *rx_status = rx_info->rx_status; u32 err_bitmap = rx_info->err_bitmap; + int err; RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "dp_rx_h_mpdu called without rcu lock"); @@ -409,8 +410,10 @@ static int ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, } ath12k_wifi7_dp_rx_h_csum_offload(msdu, rx_info); - ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info, - peer); + err = ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, + rx_info, peer); + if (err) + return err; if (!is_decrypted || rx_info->is_mcbc) return 0; @@ -1064,9 +1067,12 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev, } ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); - ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true, - rx_info, NULL); - ieee80211_rx(ath12k_pdev_dp_to_hw(dp_pdev), msdu); + if (!ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, + true, rx_info, NULL)) + ieee80211_rx(ath12k_pdev_dp_to_hw(dp_pdev), msdu); + else + dev_kfree_skb_any(msdu); + return -EINVAL; } @@ -1715,8 +1721,10 @@ static bool ath12k_wifi7_dp_rx_h_tkip_mic_err(struct ath12k_pdev_dp *dp_pdev, rx_info->rx_status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR | RX_FLAG_DECRYPTED); - ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, false, - rx_info, NULL); + if (ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, + false, rx_info, NULL)) + return true; + return false; } -- 2.56.0