Ver Fonte

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
Srinivas Dasari há 4 anos atrás
pai
commit
376de8f82f

+ 8 - 5
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);

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