wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/684-ath12k-Check-skb_headroom-before-using-skb_push.patch
John Crispin 144c5d00f4 ipq95xx/mac80211: update to ATH12.3-CS
Signed-off-by: John Crispin <john@phrozen.org>
2024-02-28 18:56:21 +01:00

137 lines
4.9 KiB
Diff

From c8fa79e48e36b54641204812f6976c2d8375b315 Mon Sep 17 00:00:00 2001
From: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
Date: Fri, 4 Nov 2022 12:54:36 +0530
Subject: [PATCH] ath12k: Check skb_headroom before using skb_push
Kernel panic may occur if there is no
skb_headroom available for performing skb_push.
Added check to perform length calculation to
prevent skb_push if the length is overrides the
skb headroom.
Signed-off-by: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
---
drivers/net/wireless/ath/ath12k/dp_rx.c | 41 +++++++++++++++++++++++++
1 file changed, 41 insertions(+)
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -2305,6 +2305,7 @@ static void ath12k_dp_rx_h_undecap_nwifi
u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN];
struct ieee80211_hdr *hdr;
size_t hdr_len;
+ int expand_by = 0;
u8 *crypto_hdr;
u16 qos_ctl = 0;
@@ -2331,15 +2332,31 @@ static void ath12k_dp_rx_h_undecap_nwifi
/* 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)) {
+ expand_by = ath12k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu);
+ if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+ return;
+ }
crypto_hdr = skb_push(msdu, ath12k_dp_rx_crypto_param_len(ar, enctype));
ath12k_dp_rx_desc_get_crypto_header(ar->ab,
rxcb->rx_desc, crypto_hdr,
enctype);
}
+ if (skb_headroom(msdu) < IEEE80211_QOS_CTL_LEN) {
+ expand_by = IEEE80211_QOS_CTL_LEN - skb_headroom(msdu);
+ if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+ return;
+ }
memcpy(skb_push(msdu,
IEEE80211_QOS_CTL_LEN), &qos_ctl,
IEEE80211_QOS_CTL_LEN);
+
+ 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);
}
@@ -2414,16 +2431,27 @@ static void ath12k_get_dot11_hdr_from_rx
struct ieee80211_hdr *hdr;
u16 qos_ctl = 0;
__le16 fc;
+ int expand_by;
u8 *crypto_hdr;
if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
crypto_len = ath12k_dp_rx_crypto_param_len(ar, enctype);
+ if (skb_headroom(msdu) < crypto_len) {
+ expand_by = crypto_len - skb_headroom(msdu);
+ if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+ return;
+ }
crypto_hdr = skb_push(msdu, crypto_len);
ath12k_dp_rx_desc_get_crypto_header(ab, rx_desc, crypto_hdr, enctype);
}
fc = cpu_to_le16(ath12k_dp_rxdesc_get_mpdu_frame_ctrl(ab, rx_desc));
hdr_len = ieee80211_hdrlen(fc);
+ 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;
+ }
skb_push(msdu, hdr_len);
hdr = (struct ieee80211_hdr *)msdu->data;
hdr->frame_control = fc;
@@ -2455,6 +2483,7 @@ static void ath12k_dp_rx_h_undecap_eth(s
struct ethhdr *eth;
u8 da[ETH_ALEN];
u8 sa[ETH_ALEN];
+ int expand_by;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
struct ath12k_dp_rx_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}};
@@ -2463,6 +2492,11 @@ static void ath12k_dp_rx_h_undecap_eth(s
ether_addr_copy(sa, eth->h_source);
rfc.snap_type = eth->h_proto;
skb_pull(msdu, sizeof(struct ethhdr));
+ if (skb_headroom(msdu) < sizeof(struct ath12k_dp_rx_rfc1042_hdr)) {
+ expand_by = sizeof(struct ath12k_dp_rx_rfc1042_hdr) - skb_headroom(msdu);
+ if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+ return;
+ }
memcpy(skb_push(msdu, sizeof(struct ath12k_dp_rx_rfc1042_hdr)), &rfc,
sizeof(struct ath12k_dp_rx_rfc1042_hdr));
ath12k_get_dot11_hdr_from_rx_desc(ar, msdu, rxcb, status, enctype);
@@ -2860,6 +2894,7 @@ static void ath12k_dp_rx_deliver_msdu(st
struct ath12k_peer *peer;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
u8 decap = DP_RX_DECAP_TYPE_RAW;
+ int expand_by;
bool is_mcbc = rxcb->is_mcbc;
bool is_eapol = rxcb->is_eapol;
struct ath12k_link_sta *arsta = NULL;
@@ -2867,6 +2902,11 @@ static void ath12k_dp_rx_deliver_msdu(st
if (status->encoding == RX_ENC_HE && !(status->flag & RX_FLAG_RADIOTAP_HE) &&
!(status->flag & RX_FLAG_SKIP_MONITOR)) {
+ if (skb_headroom(msdu) < sizeof(known)) {
+ expand_by = sizeof(known) - skb_headroom(msdu);
+ if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+ goto exit;
+ }
he = skb_push(msdu, sizeof(known));
memcpy(he, &known, sizeof(known));
status->flag |= RX_FLAG_RADIOTAP_HE;
@@ -2924,6 +2964,7 @@ static void ath12k_dp_rx_deliver_msdu(st
!(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
rx_status->flag |= RX_FLAG_8023;
+exit:
ieee80211_rx_napi(ar->ah->hw, pubsta, msdu, napi);
if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) {