Browse Source

qcacld-3.0: Fix sta_ds use after free

lim_is_pkt_candidate_for_drop() uses sta_ds to update last assoc
and deauth/disasocc received time without taking any lock for
sta_ds. deletion of sta_ds in pe_delete_session before accessing
sta_ds in dph_lookup_hash_entry can lead lead to Assert.
Similar is the case with sta_ds->last_assoc_received_time and
sta_ds->last_disassoc_deauth_received_time.

Fix is to use peer_priv instead of sta_ds and update
last_assoc_received_time and last_disassoc_deauth_received_time of
peer_mlme_priv_obj. In this case refcount gets increased for valid
peer and peer won't be deleted until lim_is_pkt_candidate_for_drop
releases the ref count of the peer.

Change-Id: I9daf31f9dd7b509eaf38a93078bb7418605b1c74
CRs-Fixed: 2598841
sheenam monga 5 years ago
parent
commit
1fa0514eb7

+ 4 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -57,10 +57,14 @@ struct wlan_ies {
  * struct peer_mlme_priv_obj - peer MLME component object
  * @ucast_key_cipher: unicast crypto type.
  * @is_pmf_enabled: True if PMF is enabled
+ * @last_assoc_received_time: last assoc received time
+ * @last_disassoc_deauth_received_time: last disassoc/deauth received time
  */
 struct peer_mlme_priv_obj {
 	uint32_t ucast_key_cipher;
 	bool is_pmf_enabled;
+	qdf_time_t last_assoc_received_time;
+	qdf_time_t last_disassoc_deauth_received_time;
 };
 
 /**

+ 1 - 5
core/mac/src/dph/dph_hash_table.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 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
@@ -196,8 +196,6 @@ tpDphHashNode dph_init_sta_state(struct mac_context *mac, tSirMacAddr staAddr,
 
 	sta->added = 1;
 	sta->is_disassoc_deauth_in_progress = 0;
-	sta->last_assoc_received_time = 0;
-	sta->last_disassoc_deauth_received_time = 0;
 	sta->sta_deletion_in_progress = false;
 	sta->valid = 1;
 	return sta;
@@ -334,8 +332,6 @@ QDF_STATUS dph_delete_hash_entry(struct mac_context *mac, tSirMacAddr staAddr,
 			prev->next = ptr->next;
 		ptr->added = 0;
 		ptr->is_disassoc_deauth_in_progress = 0;
-		ptr->last_assoc_received_time = 0;
-		ptr->last_disassoc_deauth_received_time = 0;
 		ptr->sta_deletion_in_progress = false;
 		ptr->next = 0;
 	} else {

+ 1 - 3
core/mac/src/include/dph_global.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 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
@@ -171,8 +171,6 @@ typedef struct sDphHashNode {
 	/* key installed for this STA or not in the firmware */
 	uint8_t is_key_installed;
 	uint8_t is_disassoc_deauth_in_progress;
-	qdf_time_t last_assoc_received_time;
-	qdf_time_t last_disassoc_deauth_received_time;
 
 	uint8_t nss;
 	int8_t del_sta_ctx_rssi;

+ 27 - 12
core/mac/src/pe/lim/lim_api.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 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
@@ -2613,9 +2613,8 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 	} else if ((subType == SIR_MAC_MGMT_ASSOC_REQ) ||
 		   (subType == SIR_MAC_MGMT_DISASSOC) ||
 		   (subType == SIR_MAC_MGMT_DEAUTH)) {
-		uint16_t assoc_id;
-		struct dph_hash_table *dph_table;
-		tDphHashNode *sta_ds;
+		struct peer_mlme_priv_obj *peer_priv;
+		struct wlan_objmgr_peer *peer;
 		qdf_time_t *timestamp;
 
 		pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
@@ -2623,20 +2622,34 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 				&sessionId);
 		if (!pe_session)
 			return eMGMT_DROP_SPURIOUS_FRAME;
-		dph_table = &pe_session->dph.dphHashTable;
-		sta_ds = dph_lookup_hash_entry(mac, pHdr->sa, &assoc_id,
-					       dph_table);
-		if (!sta_ds) {
+
+		peer = wlan_objmgr_get_peer_by_mac(mac->psoc,
+						   pHdr->sa,
+						   WLAN_LEGACY_MAC_ID);
+		if (!peer) {
+			if (subType == SIR_MAC_MGMT_ASSOC_REQ)
+				return eMGMT_DROP_NO_DROP;
+
+			return eMGMT_DROP_SPURIOUS_FRAME;
+		}
+
+		peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_MLME);
+		if (!peer_priv) {
+			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
 			if (subType == SIR_MAC_MGMT_ASSOC_REQ)
 				return eMGMT_DROP_NO_DROP;
-			else
-				return eMGMT_DROP_SPURIOUS_FRAME;
+
+			return eMGMT_DROP_SPURIOUS_FRAME;
 		}
 
 		if (subType == SIR_MAC_MGMT_ASSOC_REQ)
-			timestamp = &sta_ds->last_assoc_received_time;
+			timestamp =
+			   &peer_priv->last_assoc_received_time;
 		else
-			timestamp = &sta_ds->last_disassoc_deauth_received_time;
+			timestamp =
+			   &peer_priv->last_disassoc_deauth_received_time;
+
 		if (*timestamp > 0 &&
 		    qdf_system_time_before(qdf_get_system_timestamp(),
 					   *timestamp +
@@ -2646,10 +2659,12 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 				    (int)(qdf_get_system_timestamp() - *timestamp),
 				    "of last frame. Allow it only after",
 				    LIM_DOS_PROTECTION_TIME);
+			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
 			return eMGMT_DROP_EXCESSIVE_MGMT_FRAME;
 		}
 
 		*timestamp = qdf_get_system_timestamp();
+		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
 
 	}