From 319e5d13d42583ec89fae2dbcf483656f2d1e5dd Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Thu, 25 Aug 2022 19:40:04 +0530 Subject: [PATCH] ath12k: add length validation before skb_put call In the wbm_err path, while processing tkip mic error msdu_len is fetched from the hal_rx_desc's msdu_end. This msdu_len is directly passing to the skb_put without the validation. In the stretch test scenario, some of the descriptors received under wbm_err is invalid and carries junk values which leads to higher msdu_len compare to actual msdu data size. Add a check to drop the skb when the calculation msdu length is greater than the skb size and add provision to capture the dropped packet count in soc_dp_stats. 433.528769: <2> skbuff: skb_over_panic: text:00000000ae22af6c len:16634 put:16634 head:000000000f476cc4 data:00000000bd8a38f5 tail:0x413a end:0x940 dev: 433.536000: <2> ------------[ cut here ]------------ 433.549601: <2> kernel BUG at net/core/skbuff.c:137! 433.554375: <2> Internal error: Oops - BUG: 0 [#1] PREEMPT SMP 433.826006: <2> CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G W 5.4.164 #0 433.844482: <2> Hardware name: Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C4 (DT) 433.851947: <2> pstate: 40400005 (nZcv daif +PAN -UAO) 433.859153: <2> pc : skb_panic+0x48/0x4c 433.863921: <2> lr : skb_panic+0x48/0x4c 433.867654: <2> sp : ffffff801c5af9f0 433.871213: <2> x29: ffffff801c5afa00 x28: 0000000000000018 433.874427: <2> x27: 0000000000000420 x26: ffffff8023602938 433.879809: <2> x25: 00000000000000f8 x24: ffffff8034128000 433.885104: <2> x23: ffffff8034120000 x22: 00000000000000fb 433.890398: <2> x21: ffffff8023602938 x20: ffffff8026d59540 433.895694: <2> x19: ffffff802a237000 x18: 0000000000000000 433.900989: <2> x17: 0000000000000000 x16: 0000000000002cd8 433.906284: <2> x15: 0000000000002c88 x14: 4c554e3c3a766564 433.911579: <2> x13: 2030343978303a64 x12: 6e65206133313478 433.916874: <2> x11: 303a6c6961742035 x10: 6638336138646230 433.922170: <2> x9 : 303030303030303a x8 : 6174616420346363 433.927464: <2> x7 : 3637346630303030 x6 : 0000000000000001 433.932760: <2> x5 : 0000000000000000 x4 : 0000000000000000 433.938055: <2> x3 : 0000000000000000 x2 : 7634c30f3f78ed00 433.943350: <2> x1 : 0000000000000000 x0 : 000000000000008e 433.948645: <2> Call trace: 433.953938: <2> skb_panic+0x48/0x4c 433.956109: <2> skb_put+0x54/0x60 433.959591: <2> ath12k_dp_rx_h_ppdu+0x7d4/0x87c [ath12k] 433.962450: <2> ath12k_dp_rx_process_wbm_err+0x37c/0x3d0 [ath12k] 433.967573: <2> ath12k_dp_service_srng+0xb0/0x260 [ath12k] 433.973302: <2> ath12k_pci_write32+0x99c/0xb18 [ath12k] 433.978421: <2> __napi_poll+0x30/0xa4 433.983626: <2> net_rx_action+0x118/0x270 433.986840: <2> __do_softirq+0x10c/0x244 433.990571: <2> run_ksoftirqd+0x30/0x44 433.994305: <2> smpboot_thread_fn+0x234/0x254 433.997951: <2> kthread+0x140/0x150 434.001856: <2> ret_from_fork+0x10/0x18 434.005245: <2> Code: f0001d40 aa0803e1 912b2400 9406144f (d4210000) 434.008803: <2> ---[ end trace 6a0a441d397527ec ]--- Signed-off-by: P Praneesh --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/debugfs.c | 10 ++++++---- drivers/net/wireless/ath/ath12k/dp_rx.c | 28 +++++++++++++++++++++------- 3 files changed, 29 insertions(+), 11 deletions(-) --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -890,7 +890,9 @@ struct ath12k_soc_dp_stats { u32 err_ring_pkts; u32 invalid_rbm; u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; + u32 rxdma_error_drop[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; + u32 reo_error_drop[HAL_REO_DEST_RING_ERROR_CODE_MAX]; u32 hal_reo_error[DP_REO_DST_RING_MAX]; struct ath12k_soc_dp_tx_err_stats tx_err; struct ath12k_dp_ring_bp_stats bp_stats; --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -838,13 +838,15 @@ static ssize_t ath12k_debugfs_dump_soc_d soc_stats->invalid_rbm); len += scnprintf(buf + len, size - len, "RXDMA errors:\n"); for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++) - len += scnprintf(buf + len, size - len, "%s: %u\n", - rxdma_err[i], soc_stats->rxdma_error[i]); + len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n", + rxdma_err[i], soc_stats->rxdma_error[i], + soc_stats->rxdma_error_drop[i]); len += scnprintf(buf + len, size - len, "\nREO errors:\n"); for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++) - len += scnprintf(buf + len, size - len, "%s: %u\n", - reo_err[i], soc_stats->reo_error[i]); + len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n", + reo_err[i], soc_stats->reo_error[i], + soc_stats->reo_error_drop[i]); len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n"); len += scnprintf(buf + len, size - len, --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3990,8 +3990,6 @@ static bool ath12k_dp_rx_h_reo_err(struc struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); bool drop = false; - ar->ab->soc_stats.reo_error[rxcb->err_code]++; - switch (rxcb->err_code) { case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: if (ath12k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list)) @@ -4011,10 +4009,15 @@ static bool ath12k_dp_rx_h_reo_err(struc break; } + if (drop) + ar->ab->soc_stats.reo_error_drop[rxcb->err_code]++; + else + ar->ab->soc_stats.reo_error[rxcb->err_code]++; + 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; @@ -4029,6 +4032,14 @@ static void ath12k_dp_rx_h_tkip_mic_err( l3pad_bytes = ath12k_dp_rx_h_l3pad(ab, desc); msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); + + if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) { + ath12k_warn(ab, "invalid msdu len in tkip mirc err %u\n", msdu_len); + ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", desc, + sizeof(struct hal_rx_desc)); + return true; + } + skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); @@ -4039,6 +4050,7 @@ static void ath12k_dp_rx_h_tkip_mic_err( ath12k_dp_rx_h_undecap(ar, msdu, desc, HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); + return false; } static bool ath12k_dp_rx_h_4addr_null_frame_handler(struct ath12k *ar, struct sk_buff *msdu, @@ -4058,7 +4070,6 @@ static bool ath12k_dp_rx_h_4addr_null_fr msdu_len = ath12k_dp_rx_h_msdu_len(ab, rx_desc); peer_id = ath12k_dp_rx_h_peer_id(ab, rx_desc); - ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; if(!ath12k_peer_find_by_id(ab, peer_id)) { ath12k_dbg(ab, ATH12K_DBG_DATA, "invalid peer id received in wbm err pkt%d\n", @@ -4098,8 +4109,6 @@ static bool ath12k_dp_rx_h_rxdma_err(str bool drop = false; u32 err_bitmap; - ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; - switch (rxcb->err_code) { case HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR: drop = ath12k_dp_rx_h_4addr_null_frame_handler(ar, msdu, status); @@ -4108,7 +4117,7 @@ static bool ath12k_dp_rx_h_rxdma_err(str 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; @@ -4120,6 +4129,11 @@ static bool ath12k_dp_rx_h_rxdma_err(str break; } + if (drop) + ar->ab->soc_stats.rxdma_error_drop[rxcb->err_code]++; + else + ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; + return drop; }