From 4a59d8de1cd9cbd75335fa377e40b11e98633bb3 Mon Sep 17 00:00:00 2001 From: Manoj Ekbote Date: Wed, 14 Feb 2018 10:13:27 -0800 Subject: [PATCH] qcacmn: Fix issues leading to use-after-free 1. After mem_free() is done for a vdev without peers, set it to NULL so that later check can catch it.If not, it could be used to increment stats. 2. After a bss peer is freed, mark it as NULL so that it is not used again to update stats. Change-Id: I82e73c29c1409aac1af735ab849e8b07d387acf2 --- dp/wifi3.0/dp_main.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index f17f93c2c5e6..70df6204d96a 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3802,6 +3802,7 @@ void dp_peer_unref_delete(void *peer_handle) struct dp_peer *tmppeer; int found = 0; uint16_t peer_id; + uint16_t vdev_id; /* * Hold the lock all the way from checking if the peer ref count @@ -3819,6 +3820,7 @@ void dp_peer_unref_delete(void *peer_handle) peer, qdf_atomic_read(&peer->ref_cnt)); if (qdf_atomic_dec_and_test(&peer->ref_cnt)) { peer_id = peer->peer_ids[0]; + vdev_id = vdev->vdev_id; /* * Make sure that the reference to the peer in @@ -3875,9 +3877,9 @@ void dp_peer_unref_delete(void *peer_handle) " - its last peer is done"), vdev, vdev->mac_addr.raw); /* all peers are gone, go ahead and delete it */ - dp_tx_flow_pool_unmap_handler(pdev, vdev->vdev_id, + dp_tx_flow_pool_unmap_handler(pdev, vdev_id, FLOW_TYPE_VDEV, - vdev->vdev_id); + vdev_id); dp_tx_vdev_detach(vdev); QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, @@ -3885,6 +3887,7 @@ void dp_peer_unref_delete(void *peer_handle) vdev, vdev->mac_addr.raw); qdf_mem_free(vdev); + vdev = NULL; if (vdev_delete_cb) vdev_delete_cb(vdev_delete_context); } @@ -3892,21 +3895,30 @@ void dp_peer_unref_delete(void *peer_handle) qdf_spin_unlock_bh(&soc->peer_ref_mutex); } + if (vdev) { + if (vdev->vap_bss_peer == peer) { + vdev->vap_bss_peer = NULL; + } + } + if (soc->cdp_soc.ol_ops->peer_unref_delete) { soc->cdp_soc.ol_ops->peer_unref_delete(pdev->osif_pdev, - vdev->vdev_id, peer->mac_addr.raw); + vdev_id, peer->mac_addr.raw); } + + if (!vdev || !vdev->vap_bss_peer) { + goto free_peer; + } + #ifdef notyet qdf_mempool_free(soc->osdev, soc->mempool_ol_ath_peer, peer); #else - if (!vdev || !vdev->vap_bss_peer) - goto free_peer; - bss_peer = vdev->vap_bss_peer; DP_UPDATE_STATS(bss_peer, peer); free_peer: qdf_mem_free(peer); + #endif } else { qdf_spin_unlock_bh(&soc->peer_ref_mutex);