From 9952304979ff2ae4d1b734134bbe9a4ee792d783 Mon Sep 17 00:00:00 2001 From: Zhu Jianmin Date: Wed, 6 Jun 2018 20:01:44 +0800 Subject: [PATCH] qcacld-3.0: Fix peer use after free in ol_txrx_clear_peer When DUT P2P Go/SAP deauth ref STA, in race condition, scheduler thread may try to clear peer data and drop pending rx packets after peer freed in peer unmap handler in soft irq context, use after free issue will happen. Error log: BUG: spinlock bad magic on CPU#1, scheduler_threa/28550 Unable to handle kernel paging request at virtual address 6b6b6b6b6b715b Stackframe: do_raw_spin_lock+0x34/0x154 _raw_spin_lock_bh+0x24/0x30 ol_txrx_clear_peer_internal+0x68/0xb0 [wlan] ol_txrx_clear_peer+0x78/0xa0 [wlan] hdd_softap_deregister_sta+0xd0/0x200 [wlan] hdd_hostapd_sap_event_cb+0xca8/0x20b8 [wlan] Change-Id: Ib8d133528f5ff22125218861206d241f96eaf0da CRs-Fixed: 2247334 --- core/dp/txrx/ol_txrx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index be58266b2887..b6e1849ac266 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -3685,10 +3685,10 @@ static QDF_STATUS ol_txrx_clear_peer(struct cdp_pdev *ppdev, uint8_t sta_id) { struct ol_txrx_peer_t *peer; struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + QDF_STATUS status; if (!pdev) { - ol_txrx_err("%s: Unable to find pdev!", - __func__); + ol_txrx_err("Unable to find pdev!"); return QDF_STATUS_E_FAILURE; } @@ -3697,7 +3697,8 @@ static QDF_STATUS ol_txrx_clear_peer(struct cdp_pdev *ppdev, uint8_t sta_id) return QDF_STATUS_E_INVAL; } - peer = ol_txrx_peer_find_by_local_id((struct cdp_pdev *)pdev, sta_id); + peer = ol_txrx_peer_get_ref_by_local_id(ppdev, sta_id, + PEER_DEBUG_ID_OL_INTERNAL); /* Return success, if the peer is already cleared by * data path via peer detach function. @@ -3705,8 +3706,12 @@ static QDF_STATUS ol_txrx_clear_peer(struct cdp_pdev *ppdev, uint8_t sta_id) if (!peer) return QDF_STATUS_SUCCESS; - return ol_txrx_clear_peer_internal(peer); + ol_txrx_dbg("Clear peer rx frames: " QDF_MAC_ADDR_STR, + QDF_MAC_ADDR_ARRAY(peer->mac_addr.raw)); + ol_txrx_clear_peer_internal(peer); + status = ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + return status; } void peer_unmap_timer_work_function(void *param)