Skip to content

Commit

Permalink
ath11k: Avoid NULL ptr access during mgmt tx cleanup
Browse files Browse the repository at this point in the history
[ Upstream commit a93789a ]

Currently 'ar' reference is not added in skb_cb during
WMI mgmt tx. Though this is generally not used during tx completion
callbacks, on interface removal the remaining idr cleanup callback
uses the ar ptr from skb_cb from mgmt txmgmt_idr. Hence
fill them during tx call for proper usage.

Also free the skb which is missing currently in these
callbacks.

Crash_info:

[19282.489476] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[19282.489515] pgd = 91eb8000
[19282.496702] [00000000] *pgd=00000000
[19282.502524] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[19282.783728] PC is at ath11k_mac_vif_txmgmt_idr_remove+0x28/0xd8 [ath11k]
[19282.789170] LR is at idr_for_each+0xa0/0xc8

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1637832614-13831-1-git-send-email-quic_srirrama@quicinc.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Sriram R authored and gregkh committed Jan 27, 2022
1 parent ab523ea commit adbe148
Showing 1 changed file with 20 additions and 15 deletions.
35 changes: 20 additions & 15 deletions drivers/net/wireless/ath/ath11k/mac.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/

#include <net/mac80211.h>
Expand Down Expand Up @@ -3883,23 +3884,32 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
return 0;
}

int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
{
struct sk_buff *msdu = skb;
struct sk_buff *msdu;
struct ieee80211_tx_info *info;
struct ath11k *ar = ctx;
struct ath11k_base *ab = ar->ab;

spin_lock_bh(&ar->txmgmt_idr_lock);
idr_remove(&ar->txmgmt_idr, buf_id);
msdu = idr_remove(&ar->txmgmt_idr, buf_id);
spin_unlock_bh(&ar->txmgmt_idr_lock);
dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,

if (!msdu)
return;

dma_unmap_single(ar->ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
DMA_TO_DEVICE);

info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));

ieee80211_free_txskb(ar->hw, msdu);
}

int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
{
struct ath11k *ar = ctx;

ath11k_mac_tx_mgmt_free(ar, buf_id);

return 0;
}
Expand All @@ -3908,17 +3918,10 @@ static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
{
struct ieee80211_vif *vif = ctx;
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
struct sk_buff *msdu = skb;
struct ath11k *ar = skb_cb->ar;
struct ath11k_base *ab = ar->ab;

if (skb_cb->vif == vif) {
spin_lock_bh(&ar->txmgmt_idr_lock);
idr_remove(&ar->txmgmt_idr, buf_id);
spin_unlock_bh(&ar->txmgmt_idr_lock);
dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len,
DMA_TO_DEVICE);
}
if (skb_cb->vif == vif)
ath11k_mac_tx_mgmt_free(ar, buf_id);

return 0;
}
Expand All @@ -3933,6 +3936,8 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
int buf_id;
int ret;

ATH11K_SKB_CB(skb)->ar = ar;

spin_lock_bh(&ar->txmgmt_idr_lock);
buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
Expand Down

0 comments on commit adbe148

Please sign in to comment.