Преглед изворни кода

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
Zhu Jianmin пре 6 година
родитељ
комит
9952304979
1 измењених фајлова са 9 додато и 4 уклоњено
  1. 9 4
      core/dp/txrx/ol_txrx.c

+ 9 - 4
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)