Преглед на файлове

qcacmn: Fix bss peer use after free in crypto

wlan_vdev_get_bsspeer() return bss peer without taking the ref count
of the peer and thus if peer is deleted after wlan_vdev_get_bsspeer()
returns a valid peer, the caller will have stale entry of the peer.
Stale entry of peer can lead to Assert.

Use wlan_objmgr_vdev_try_get_bsspeer API for crypto to get the BSS
peer which increment the refcount if peer is valid. With this the
peer won't be deleted till the caller release the ref count of the
peer.

Change-Id: I5472c80d267a6639acaff2d47dbc09e37963bc93
CRs-Fixed: 2447249
sheenam monga преди 6 години
родител
ревизия
1273bcec05
променени са 1 файла, в които са добавени 16 реда и са изтрити 9 реда
  1. 16 9
      umac/cmn_services/crypto/src/wlan_crypto_global_api.c

+ 16 - 9
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -646,10 +646,9 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 			key = crypto_priv->key[req_key->keyix];
 		}
 		if (vdev_mode == QDF_STA_MODE) {
-			peer = wlan_vdev_get_bsspeer(vdev);
-			if (!(peer && (QDF_STATUS_SUCCESS
-				== wlan_objmgr_peer_try_get_ref(peer,
-							WLAN_CRYPTO_ID)))) {
+			peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
+								WLAN_CRYPTO_ID);
+			if (!peer) {
 				crypto_err("peer %pK failed", peer);
 				if (IS_MGMT_CIPHER(req_key->type)) {
 					crypto_priv->igtk_key[igtk_idx] = NULL;
@@ -3115,6 +3114,7 @@ QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
 	uint8_t *mac_addr;
 	int i;
 	enum QDF_OPMODE opmode;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	if (!vdev)
 		return QDF_STATUS_E_NULL_VALUE;
@@ -3148,7 +3148,7 @@ QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 
 	if (opmode == QDF_STA_MODE) {
-		peer = wlan_vdev_get_bsspeer(vdev);
+		peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CRYPTO_ID);
 		if (!peer) {
 			crypto_err("peer NULL");
 			return QDF_STATUS_E_INVAL;
@@ -3158,7 +3158,8 @@ QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
 	wlan_crypto_peer_get_comp_params(peer, &sta_crypto_priv);
 	if (!sta_crypto_priv) {
 		crypto_err("sta priv is null");
-		return QDF_STATUS_E_INVAL;
+		status = QDF_STATUS_E_INVAL;
+		goto exit;
 	}
 
 	for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
@@ -3173,8 +3174,10 @@ QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
 			if (cipher_table->cipher == WLAN_CRYPTO_CIPHER_WEP) {
 				sta_key = qdf_mem_malloc(
 						sizeof(struct wlan_crypto_key));
-				if (!sta_key)
-					return QDF_STATUS_E_NOMEM;
+				if (!sta_key) {
+					status = QDF_STATUS_E_NOMEM;
+					goto exit;
+				}
 
 				sta_crypto_priv->key[i] = sta_key;
 				qdf_mem_copy(sta_key, key,
@@ -3209,7 +3212,11 @@ QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
 		}
 	}
 
-	return QDF_STATUS_SUCCESS;
+exit:
+	if (opmode == QDF_STA_MODE)
+		wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
+
+	return status;
 }
 
 /**