Pārlūkot izejas kodu

qcacmn: Fix use after free in management Rx REO module

In some cases, the current frame and its associated rx_params/reo_params
may get freed immediately after the frame is queued to the egress list.
Hence accessing the reo_params after the frame is queued to the
egress list could lead to a use after free. Store a copy of "reo_params"
in the frame descriptor and access the copy after the frame is
queued to the egress list.

CRs-Fixed: 3516454
Change-Id: Ia87455b25d71f7de8f5b9c94fb6de05e94922b04
Edayilliam Jayadev 2 gadi atpakaļ
vecāks
revīzija
ab8ef68f2f

+ 26 - 3
umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo.c

@@ -3385,7 +3385,18 @@ mgmt_rx_reo_update_ingress_list(struct mgmt_rx_reo_ingress_list *ingress_list,
 	}
 	*is_queued = false;
 
-	ts_new = mgmt_rx_reo_get_global_ts(frame_desc->rx_params);
+	/**
+	 * In some cases, the current frame and its associated
+	 * rx_params/reo_params may get freed immediately after the frame
+	 * is queued to egress list. Hence fetching the global time stamp from
+	 * "frame_desc->rx_params->reo_params" could lead to use after free.
+	 * Store a copy of "reo_params" in the frame descriptor and access
+	 * the copy after the frame is queued to egress list.
+	 *
+	 * TODO:- Fix this cleanly using refcount mechanism or structure
+	 * duplication.
+	 */
+	ts_new = frame_desc->reo_params_copy.global_timestamp;
 
 	frame_desc->ingress_list_size_rx =
 				qdf_list_size(&reo_ingress_list->list);
@@ -3484,8 +3495,20 @@ mgmt_rx_reo_update_ingress_list(struct mgmt_rx_reo_ingress_list *ingress_list,
 			uint8_t frame_link_id;
 			struct mgmt_rx_reo_wait_count *wait_count;
 
-			frame_link_id =
-				mgmt_rx_reo_get_link_id(frame_desc->rx_params);
+			/**
+			 * In some cases, the current frame and its associated
+			 * rx_params/reo_params may get freed immediately after
+			 * the frame is queued to egress list. Hence fetching
+			 * the link ID from
+			 * "frame_desc->rx_params->reo_params" could lead to
+			 * use after free. Store a copy of "reo_params" in the
+			 * frame descriptor and access the copy after the frame
+			 * is queued to egress list.
+			 *
+			 * TODO:- Fix this cleanly using refcount mechanism or
+			 * structure duplication.
+			 */
+			frame_link_id = frame_desc->reo_params_copy.link_id;
 			wait_count = &cur->wait_count;
 			if (wait_count->per_link_count[frame_link_id]) {
 				uint32_t old_wait_count;

+ 2 - 0
umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo_i.h

@@ -1001,6 +1001,7 @@ struct mgmt_rx_reo_context {
  * wait count of frames already part of the reorder list.
  * @last_delivered_frame: Stores the information about the last frame delivered
  * to the upper layer
+ * @reo_params_copy: Copy of @rx_params->reo_params struture
  */
 struct mgmt_rx_reo_frame_descriptor {
 	enum mgmt_rx_reo_frame_descriptor_type type;
@@ -1025,6 +1026,7 @@ struct mgmt_rx_reo_frame_descriptor {
 	int pkt_ctr_delta;
 	bool reo_required;
 	struct mgmt_rx_reo_frame_info last_delivered_frame;
+	struct mgmt_rx_reo_params reo_params_copy;
 };
 
 /**

+ 2 - 0
umac/cmn_services/mgmt_txrx/dispatcher/src/wlan_mgmt_txrx_rx_reo_tgt_api.c

@@ -154,6 +154,7 @@ tgt_mgmt_rx_reo_enter_algo_without_buffer(
 
 	desc.nbuf = NULL; /* No frame buffer */
 	desc.rx_params = &mgmt_rx_params;
+	desc.reo_params_copy = *mgmt_rx_params.reo_params;
 	desc.type = type;
 	desc.ingress_timestamp = qdf_get_log_timestamp();
 	desc.ingress_list_size_rx = -1;
@@ -363,6 +364,7 @@ QDF_STATUS tgt_mgmt_rx_reo_frame_handler(
 	desc.type = MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME;
 	desc.nbuf = buf;
 	desc.rx_params = mgmt_rx_params;
+	desc.reo_params_copy = *mgmt_rx_params->reo_params;
 	desc.ingress_timestamp = qdf_get_log_timestamp();
 	desc.ingress_list_size_rx = -1;
 	desc.ingress_list_insertion_pos = -1;