From 3b51b87b4e9ff7ef150c168cad07e6d041f2edb7 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Tue, 6 Oct 2020 16:14:39 +0530 Subject: [PATCH] qcacld-3.0: Fetch vdev from psoc in TDLS handlers Currently, if the TDLS timer expires while the scheduler thread is processing something(e.g., station vdev destroy), the handler would be in wait queue and it gets called once the scheduler thread is done with its current task(i.e., vdev deletion). TDLS handler tries to use the vdev even it has just got freed, which leads to use-after-free. This happens because of the below, 1. vdev destroy notification has no knowledge of the TDLS timer expiry as timer_stop is used to stop the timer. 2. vdev is passed to TDLS handler as part of registration. Fix: 1. Use timer_stop_sync in vdev_destroy_notification to make sure the handler is posted to scheduler thread if the timer had expired. 2. Get the vdev in handler from psoc instead of passing it to the timer handler. This can make sure the vdev is referred only if it exists. Change-Id: I186fd0d44b2364ebb375a8445dd1239368543e7b CRs-Fixed: 2792020 --- components/tdls/core/src/wlan_tdls_ct.c | 13 ++++++++----- components/tdls/core/src/wlan_tdls_main.c | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/components/tdls/core/src/wlan_tdls_ct.c b/components/tdls/core/src/wlan_tdls_ct.c index 046cc90b307e..8ead54eddb72 100644 --- a/components/tdls/core/src/wlan_tdls_ct.c +++ b/components/tdls/core/src/wlan_tdls_ct.c @@ -85,13 +85,17 @@ void tdls_discovery_timeout_peer_cb(void *user_data) struct tdls_peer *peer; QDF_STATUS status; struct tdls_vdev_priv_obj *tdls_vdev; + struct wlan_objmgr_vdev *vdev; if (!user_data) { tdls_err("discovery time out data is null"); return; } - tdls_vdev = (struct tdls_vdev_priv_obj *) user_data; + vdev = tdls_get_vdev(user_data, WLAN_TDLS_NB_ID); + if (!vdev) + return; + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { head = &tdls_vdev->peer_list[i]; @@ -112,6 +116,7 @@ void tdls_discovery_timeout_peer_cb(void *user_data) } } tdls_vdev->discovery_sent_cnt = 0; + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); /* add tdls power save prohibited */ @@ -928,10 +933,8 @@ void tdls_ct_handler(void *user_data) if (!user_data) return; - vdev = (struct wlan_objmgr_vdev *)user_data; - - if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev, - WLAN_TDLS_NB_ID)) + vdev = tdls_get_vdev(user_data, WLAN_TDLS_NB_ID); + if (!vdev) return; tdls_ct_process_handler(vdev); diff --git a/components/tdls/core/src/wlan_tdls_main.c b/components/tdls/core/src/wlan_tdls_main.c index faeb202ee71e..ec418679d65e 100644 --- a/components/tdls/core/src/wlan_tdls_main.c +++ b/components/tdls/core/src/wlan_tdls_main.c @@ -215,17 +215,17 @@ static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj) WLAN_TDLS_PEER_SUB_LIST_SIZE); } qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW, - tdls_ct_handler, vdev_obj->vdev); + tdls_ct_handler, soc_obj->soc); qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW, - tdls_discovery_timeout_peer_cb, vdev_obj); + tdls_discovery_timeout_peer_cb, soc_obj->soc); return QDF_STATUS_SUCCESS; } static void tdls_vdev_deinit(struct tdls_vdev_priv_obj *vdev_obj) { - qdf_mc_timer_stop(&vdev_obj->peer_update_timer); - qdf_mc_timer_stop(&vdev_obj->peer_discovery_timer); + qdf_mc_timer_stop_sync(&vdev_obj->peer_update_timer); + qdf_mc_timer_stop_sync(&vdev_obj->peer_discovery_timer); qdf_mc_timer_destroy(&vdev_obj->peer_update_timer); qdf_mc_timer_destroy(&vdev_obj->peer_discovery_timer);