Ver Fonte

qcacld-3.0: Use vdev argument to release reference

In several functions of HDD, reference of vdev is acquired and released
with hdd_objmgr_get_vdev() and hdd_objmgr_put_vdev() respectively.

Both hdd_objmgr_get_vdev() and hdd_objmgr_put_vdev() use adapter input
argument to get the access to vdev pointer: adapter->vdev.

When acquiring vdev reference "adapter->vdev" can be valid but when
releasing vdev reference "adapter->vdev" can be NULL, leading to
reference leak. This can happen only when hdd_vdev_destroy() invoked
from another thread concurrently.

To address this issue, use the input argument vdev pointer to release
the reference in hdd_objmgr_put_vdev().

Change-Id: I89166a471b6c82a95ae0c70ae025608f2f19e5ca
CRs-Fixed: 2399777
Rajeev Kumar Sirasanagandla há 6 anos atrás
pai
commit
25bdfadf87

+ 2 - 2
core/hdd/src/wlan_hdd_assoc.c

@@ -3809,7 +3809,7 @@ static QDF_STATUS wlan_hdd_set_key_helper(struct hdd_adapter *adapter,
 		return QDF_STATUS_E_FAILURE;
 	ret = wlan_cfg80211_crypto_add_key(vdev,
 					   WLAN_CRYPTO_KEY_TYPE_UNICAST, 0);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	if (ret != 0) {
 		hdd_err("crypto add key fail, status: %d", ret);
 		return QDF_STATUS_E_FAILURE;
@@ -3918,7 +3918,7 @@ roam_roam_connect_status_update_handler(struct hdd_adapter *adapter,
 				return QDF_STATUS_E_FAILURE;
 			wlan_crypto_update_set_key_peer(vdev, true, 0,
 							&roam_info->peerMac);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 
 			hdd_debug("New peer joined set PTK encType=%d",
 				 encr_type);

+ 17 - 17
core/hdd/src/wlan_hdd_cfg80211.c

@@ -4950,7 +4950,7 @@ void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter,
 	if (!vdev)
 		goto end;
 	status = ucfg_pmo_cache_gtk_offload_req(vdev, gtk_req);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	if (status != QDF_STATUS_SUCCESS)
 		hdd_err("Failed to cache GTK Offload");
 
@@ -5471,7 +5471,7 @@ static int wlan_hdd_handle_restrict_offchan_config(struct hdd_adapter *adapter,
 		ret_val = -EINVAL;
 		hdd_err("Invalid RESTRICT_OFFCHAN setting");
 	}
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	return ret_val;
 }
 
@@ -5814,7 +5814,7 @@ static int hdd_config_modulated_dtim(struct hdd_adapter *adapter,
 
 	status = ucfg_pmo_config_modulated_dtim(vdev, modulated_dtim);
 
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return qdf_status_to_os_return(status);
 }
@@ -5839,7 +5839,7 @@ static int hdd_config_listen_interval(struct hdd_adapter *adapter,
 
 	status = ucfg_pmo_config_listen_interval(vdev, listen_interval);
 
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return qdf_status_to_os_return(status);
 }
@@ -13924,7 +13924,7 @@ static int __wlan_hdd_change_station(struct wiphy *wiphy,
 			if (!vdev)
 				return -EINVAL;
 			ret = wlan_cfg80211_tdls_update_peer(vdev, mac, params);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 #endif
 		}
 	}
@@ -14023,7 +14023,7 @@ static int wlan_hdd_add_key_ibss(struct hdd_adapter *adapter,
 					     key_index);
 	if (errno) {
 		hdd_err("add_ibss_key failed, errno: %d", errno);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return errno;
 	}
 	/* Save the keys here and call set_key for setting
@@ -14031,7 +14031,7 @@ static int wlan_hdd_add_key_ibss(struct hdd_adapter *adapter,
 	 */
 	wlan_cfg80211_store_key(vdev, key_index, WLAN_CRYPTO_KEY_TYPE_UNICAST,
 				mac_addr, params);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	adapter->session.station.ibss_enc_key_installed = 1;
 
 	return 0;
@@ -14054,7 +14054,7 @@ static int wlan_hdd_add_key_sap(struct hdd_adapter *adapter,
 					     WLAN_CRYPTO_KEY_TYPE_UNICAST :
 					     WLAN_CRYPTO_KEY_TYPE_GROUP),
 					     key_index);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return errno;
 }
@@ -14092,7 +14092,7 @@ static int wlan_hdd_add_key_sta(struct hdd_adapter *adapter,
 					     WLAN_CRYPTO_KEY_TYPE_UNICAST :
 					     WLAN_CRYPTO_KEY_TYPE_GROUP),
 					     key_index);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	if (!errno && adapter->send_mode_change) {
 		wlan_hdd_send_mode_change_event();
 		adapter->send_mode_change = false;
@@ -14163,7 +14163,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy,
 					WLAN_CRYPTO_KEY_TYPE_UNICAST :
 					WLAN_CRYPTO_KEY_TYPE_GROUP),
 					mac_address.bytes, params);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	if (errno)
 		return errno;
 	switch (adapter->device_mode) {
@@ -15687,7 +15687,7 @@ static int wlan_hdd_cfg80211_connect_start(struct hdd_adapter *adapter,
 		goto ret_status;
 	}
 	hdd_notify_teardown_tdls_links(vdev);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	qdf_mem_zero(&hdd_sta_ctx->conn_info.conn_flag,
 		     sizeof(hdd_sta_ctx->conn_info.conn_flag));
@@ -15837,7 +15837,7 @@ static int wlan_hdd_cfg80211_connect_start(struct hdd_adapter *adapter,
 			goto conn_failure;
 		}
 		ucfg_pmo_flush_gtk_offload_req(vdev);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		roam_profile->csrPersona = adapter->device_mode;
 
 		if (operatingChannel) {
@@ -16757,7 +16757,7 @@ static void hdd_set_crypto_key_mgmt_param(struct hdd_adapter *adapter)
 		HDD_SET_BIT(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT);
 
 	wlan_crypto_set_vdev_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT, key_mgmt);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 }
 
 #else
@@ -17229,7 +17229,7 @@ static int wlan_hdd_cfg80211_set_privacy(struct hdd_adapter *adapter,
 	if (!vdev)
 		return -EINVAL;
 	hdd_populate_crypto_params(vdev, req);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	/*set authentication type */
 	status = wlan_hdd_cfg80211_set_auth_type(adapter, req->auth_type);
@@ -18103,7 +18103,7 @@ static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy,
 		/* First clean up the tdls peers if any */
 		hdd_notify_sta_disconnect(adapter->vdev_id,
 					  false, true, vdev);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 
 		hdd_info("Disconnect from userspace; reason:%d (%s)",
 			 reason, hdd_ieee80211_reason_code_to_str(reason));
@@ -19028,7 +19028,7 @@ static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
 			if (vdev) {
 				status = wlan_cfg80211_tdls_add_peer(vdev,
 								     mac);
-				hdd_objmgr_put_vdev(adapter);
+				hdd_objmgr_put_vdev(vdev);
 			}
 		}
 	}
@@ -19637,7 +19637,7 @@ int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy,
 		goto out;
 	}
 	status = ucfg_pmo_cache_gtk_offload_req(vdev, gtk_req);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 	if (status != QDF_STATUS_SUCCESS) {
 		hdd_err("Failed to cache GTK Offload");
 		result = qdf_status_to_os_return(status);

+ 10 - 10
core/hdd/src/wlan_hdd_main.c

@@ -779,7 +779,7 @@ static int __hdd_netdev_notifier_call(struct notifier_block *nb,
 					adapter->vdev_id, INVALID_SCAN_ID,
 					true);
 		}
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		cds_flush_work(&adapter->scan_block_work);
 		/* Need to clean up blocked scan request */
 		wlan_hdd_cfg80211_scan_block_cb(&adapter->scan_block_work);
@@ -4006,13 +4006,13 @@ int hdd_vdev_ready(struct hdd_adapter *adapter)
 
 	status = pmo_vdev_ready(vdev);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return qdf_status_to_os_return(status);
 	}
 
 	status = ucfg_reg_11d_vdev_created_update(vdev);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return qdf_status_to_os_return(status);
 	}
 
@@ -4021,7 +4021,7 @@ int hdd_vdev_ready(struct hdd_adapter *adapter)
 	else
 		status = ucfg_pmo_enhanced_mc_filter_disable(vdev);
 
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return qdf_status_to_os_return(status);
 }
@@ -4050,7 +4050,7 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
 	ucfg_pmo_del_wow_pattern(vdev);
 	status = ucfg_reg_11d_vdev_delete_update(vdev);
 	ucfg_scan_vdev_set_disable(vdev, REASON_VDEV_DOWN);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	/* close sme session (destroy vdev in firmware via legacy API) */
 	qdf_event_reset(&adapter->qdf_session_close_event);
@@ -4256,7 +4256,7 @@ int hdd_vdev_create(struct hdd_adapter *adapter,
 		if (!vdev)
 			goto hdd_vdev_destroy_procedure;
 		wlan_vdev_set_max_peer_count(vdev, HDD_MAX_VDEV_PEER_COUNT);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 	}
 
 	hdd_store_nss_chains_cfg_in_vdev(adapter);
@@ -5474,7 +5474,7 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 			vdev = hdd_objmgr_get_vdev(adapter);
 			if (vdev) {
 				wlan_cfg80211_sched_scan_stop(vdev);
-				hdd_objmgr_put_vdev(adapter);
+				hdd_objmgr_put_vdev(vdev);
 			}
 		}
 
@@ -5616,7 +5616,7 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 		if (vdev) {
 			if (policy_mgr_is_dnsc_set(vdev))
 				wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 		}
 
 #ifdef WLAN_OPEN_SOURCE
@@ -5705,7 +5705,7 @@ static void hdd_reset_scan_operation(struct hdd_context *hdd_ctx,
 			vdev = hdd_objmgr_get_vdev(adapter);
 			if (vdev) {
 				wlan_cfg80211_sched_scan_stop(vdev);
-				hdd_objmgr_put_vdev(adapter);
+				hdd_objmgr_put_vdev(vdev);
 			}
 		}
 		break;
@@ -5772,7 +5772,7 @@ QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx)
 			vdev = hdd_objmgr_get_vdev(adapter);
 			if (vdev) {
 				hdd_notify_tdls_reset_adapter(vdev);
-				hdd_objmgr_put_vdev(adapter);
+				hdd_objmgr_put_vdev(vdev);
 			}
 			adapter->session.station.hdd_reassoc_scenario = false;
 		}

+ 4 - 7
core/hdd/src/wlan_hdd_object_manager.c

@@ -351,17 +351,14 @@ struct wlan_objmgr_vdev *__hdd_objmgr_get_vdev(struct hdd_adapter *adapter,
 	return vdev;
 }
 
-void __hdd_objmgr_put_vdev(struct hdd_adapter *adapter, const char *func)
+void __hdd_objmgr_put_vdev(struct wlan_objmgr_vdev *vdev, const char *func)
 {
-	if (!adapter) {
-		hdd_err("Adapter is NULL (via %s)", func);
+	if (!vdev) {
+		hdd_err("VDEV is NULL (via %s)", func);
 		return;
 	}
 
-	qdf_spin_lock_bh(&adapter->vdev_lock);
-	if (adapter->vdev)
-		wlan_objmgr_vdev_release_ref(adapter->vdev, WLAN_OSIF_ID);
-	qdf_spin_unlock_bh(&adapter->vdev_lock);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
 }
 
 int hdd_objmgr_set_peer_mlme_auth_state(struct wlan_objmgr_vdev *vdev,

+ 8 - 7
core/hdd/src/wlan_hdd_object_manager.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -146,16 +146,17 @@ struct wlan_objmgr_vdev *__hdd_objmgr_get_vdev(struct hdd_adapter *adapter,
 					       const char *func);
 
 /**
- * hdd_objmgr_put_vdev() - Release reference of vdev from adapter
- * @adapter: hdd adapter
+ * hdd_objmgr_put_vdev() - Release reference of vdev object
+ * @vdev: pointer to vdev object
  *
- * This API releases vdev object reference from hdd adapter
+ * This API releases vdev object reference which was acquired using
+ * hdd_objmgr_get_vdev().
  *
  * Return: void
  */
-#define hdd_objmgr_put_vdev(adapter) \
-	__hdd_objmgr_put_vdev(adapter, __func__)
-void __hdd_objmgr_put_vdev(struct hdd_adapter *adapter, const char *func);
+#define hdd_objmgr_put_vdev(vdev) \
+	__hdd_objmgr_put_vdev(vdev, __func__)
+void __hdd_objmgr_put_vdev(struct wlan_objmgr_vdev *vdev, const char *func);
 
 /**
  * hdd_objmgr_set_peer_mlme_auth_state() - set the peer mlme auth state

+ 3 - 3
core/hdd/src/wlan_hdd_scan.c

@@ -688,7 +688,7 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
 		ucfg_p2p_status_scan(vdev);
 
 	status = wlan_cfg80211_scan(vdev, request, &params);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 error:
 	if (params.default_ie.ptr)
 		qdf_mem_free(params.default_ie.ptr);
@@ -1312,7 +1312,7 @@ static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
 			ucfg_get_scan_backoff_multiplier(hdd_ctx->psoc);
 	ret = wlan_cfg80211_sched_scan_start(vdev, request,
 					     scan_backoff_multiplier);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return ret;
 }
@@ -1371,7 +1371,7 @@ int wlan_hdd_sched_scan_stop(struct net_device *dev)
 	if (!vdev)
 		return -EINVAL;
 	ret = wlan_cfg80211_sched_scan_stop(vdev);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return ret;
 }

+ 8 - 8
core/hdd/src/wlan_hdd_tdls.c

@@ -101,7 +101,7 @@ int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter,
 		return len;
 	}
 	ret = wlan_cfg80211_tdls_get_all_peers(vdev, buf, buflen);
-	hdd_objmgr_put_vdev(adapter);
+	hdd_objmgr_put_vdev(vdev);
 
 	return ret;
 }
@@ -249,7 +249,7 @@ __wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy,
 			return -EINVAL;
 		ret = wlan_cfg80211_tdls_configure_mode(vdev,
 							trigger_mode);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return ret;
 	}
 
@@ -500,7 +500,7 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 					      action_code, dialog_token,
 					      status_code, peer_capability,
 					      buf, len);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return ret;
 	}
 
@@ -654,7 +654,7 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
 		if (!vdev)
 			return -EINVAL;
 		status = wlan_cfg80211_tdls_oper(vdev, peer, oper);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		hdd_exit();
 		return status;
 	}
@@ -705,7 +705,7 @@ int hdd_set_tdls_offchannel(struct hdd_context *hdd_ctx,
 		if (vdev) {
 			status = ucfg_set_tdls_offchannel(vdev,
 							  offchannel);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 		}
 	}
 	return qdf_status_to_os_return(status);
@@ -723,7 +723,7 @@ int hdd_set_tdls_secoffchanneloffset(struct hdd_context *hdd_ctx,
 		if (vdev) {
 			status = ucfg_set_tdls_secoffchanneloffset(vdev,
 								 offchanoffset);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 		}
 	}
 	return qdf_status_to_os_return(status);
@@ -741,7 +741,7 @@ int hdd_set_tdls_offchannelmode(struct hdd_context *hdd_ctx,
 		if (vdev) {
 			status = ucfg_set_tdls_offchan_mode(vdev,
 							    offchanmode);
-			hdd_objmgr_put_vdev(adapter);
+			hdd_objmgr_put_vdev(vdev);
 		}
 	}
 	return qdf_status_to_os_return(status);
@@ -795,7 +795,7 @@ int wlan_hdd_tdls_antenna_switch(struct hdd_context *hdd_ctx,
 		if (!vdev)
 			return -EINVAL;
 		ret = wlan_tdls_antenna_switch(vdev, mode);
-		hdd_objmgr_put_vdev(adapter);
+		hdd_objmgr_put_vdev(vdev);
 		return ret;
 	}