qcacmn: fix dp vdev use after free for monitor mode
Crash scenario: a. monitor mode dp_vdev is freed in dp_vdev_detach_wifi3 without checking whether any dp_peer is associated. b. monitor mode self dp_peer do peer clean up when HTT peer unmap MSG received, invalid accessing to dp_vdev as it has been freed in step (a). Check if there is dp_peer associated for monitor mode dp_vdev, skip dp_vdev free, when all dp_peer is freed, dp_delete_pending_vdev will free dp_vdev. Change-Id: Iea4b0efc6e7bbd4109d9cd0b109dfddf727a9fff CRs-Fixed: 2576604
This commit is contained in:
@@ -5036,9 +5036,6 @@ static void dp_vdev_detach_wifi3(struct cdp_vdev *vdev_handle,
|
|||||||
|
|
||||||
soc->vdev_id_map[vdev->vdev_id] = NULL;
|
soc->vdev_id_map[vdev->vdev_id] = NULL;
|
||||||
|
|
||||||
if (wlan_op_mode_monitor == vdev->opmode)
|
|
||||||
goto free_vdev;
|
|
||||||
|
|
||||||
if (wlan_op_mode_sta == vdev->opmode)
|
if (wlan_op_mode_sta == vdev->opmode)
|
||||||
dp_peer_delete_wifi3(vdev->vap_self_peer, 0);
|
dp_peer_delete_wifi3(vdev->vap_self_peer, 0);
|
||||||
|
|
||||||
@@ -5069,6 +5066,9 @@ static void dp_vdev_detach_wifi3(struct cdp_vdev *vdev_handle,
|
|||||||
}
|
}
|
||||||
qdf_spin_unlock_bh(&soc->peer_ref_mutex);
|
qdf_spin_unlock_bh(&soc->peer_ref_mutex);
|
||||||
|
|
||||||
|
if (wlan_op_mode_monitor == vdev->opmode)
|
||||||
|
goto free_vdev;
|
||||||
|
|
||||||
qdf_spin_lock_bh(&pdev->neighbour_peer_mutex);
|
qdf_spin_lock_bh(&pdev->neighbour_peer_mutex);
|
||||||
if (!soc->hw_nac_monitor_support) {
|
if (!soc->hw_nac_monitor_support) {
|
||||||
TAILQ_FOREACH(peer, &pdev->neighbour_peers_list,
|
TAILQ_FOREACH(peer, &pdev->neighbour_peers_list,
|
||||||
@@ -5092,14 +5092,13 @@ static void dp_vdev_detach_wifi3(struct cdp_vdev *vdev_handle,
|
|||||||
dp_rx_vdev_detach(vdev);
|
dp_rx_vdev_detach(vdev);
|
||||||
/* remove the vdev from its parent pdev's list */
|
/* remove the vdev from its parent pdev's list */
|
||||||
TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem);
|
TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem);
|
||||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH,
|
|
||||||
FL("deleting vdev object %pK (%pM)"), vdev, vdev->mac_addr.raw);
|
|
||||||
|
|
||||||
qdf_spin_unlock_bh(&pdev->vdev_list_lock);
|
qdf_spin_unlock_bh(&pdev->vdev_list_lock);
|
||||||
|
|
||||||
free_vdev:
|
free_vdev:
|
||||||
if (wlan_op_mode_monitor == vdev->opmode)
|
if (wlan_op_mode_monitor == vdev->opmode)
|
||||||
pdev->monitor_vdev = NULL;
|
pdev->monitor_vdev = NULL;
|
||||||
|
|
||||||
|
dp_info("deleting vdev object %pK (%pM)", vdev, vdev->mac_addr.raw);
|
||||||
qdf_mem_free(vdev);
|
qdf_mem_free(vdev);
|
||||||
|
|
||||||
if (callback)
|
if (callback)
|
||||||
@@ -5927,9 +5926,8 @@ static void dp_delete_pending_vdev(struct dp_pdev *pdev, struct dp_vdev *vdev,
|
|||||||
vdev_delete_cb = vdev->delete.callback;
|
vdev_delete_cb = vdev->delete.callback;
|
||||||
vdev_delete_context = vdev->delete.context;
|
vdev_delete_context = vdev->delete.context;
|
||||||
|
|
||||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH,
|
dp_info("deleting vdev object %pK (%pM)- its last peer is done",
|
||||||
FL("deleting vdev object %pK (%pM)- its last peer is done"),
|
vdev, vdev->mac_addr.raw);
|
||||||
vdev, vdev->mac_addr.raw);
|
|
||||||
/* all peers are gone, go ahead and delete it */
|
/* all peers are gone, go ahead and delete it */
|
||||||
dp_tx_flow_pool_unmap_handler(pdev, vdev_id,
|
dp_tx_flow_pool_unmap_handler(pdev, vdev_id,
|
||||||
FLOW_TYPE_VDEV, vdev_id);
|
FLOW_TYPE_VDEV, vdev_id);
|
||||||
@@ -5937,13 +5935,16 @@ static void dp_delete_pending_vdev(struct dp_pdev *pdev, struct dp_vdev *vdev,
|
|||||||
|
|
||||||
pdev->soc->vdev_id_map[vdev_id] = NULL;
|
pdev->soc->vdev_id_map[vdev_id] = NULL;
|
||||||
|
|
||||||
qdf_spin_lock_bh(&pdev->vdev_list_lock);
|
if (wlan_op_mode_monitor == vdev->opmode) {
|
||||||
TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem);
|
pdev->monitor_vdev = NULL;
|
||||||
qdf_spin_unlock_bh(&pdev->vdev_list_lock);
|
} else {
|
||||||
|
qdf_spin_lock_bh(&pdev->vdev_list_lock);
|
||||||
|
TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem);
|
||||||
|
qdf_spin_unlock_bh(&pdev->vdev_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH,
|
dp_info("deleting vdev object %pK (%pM)",
|
||||||
FL("deleting vdev object %pK (%pM)"),
|
vdev, vdev->mac_addr.raw);
|
||||||
vdev, vdev->mac_addr.raw);
|
|
||||||
qdf_mem_free(vdev);
|
qdf_mem_free(vdev);
|
||||||
vdev = NULL;
|
vdev = NULL;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user