فهرست منبع

qcacmn: Fix use after free in mgmt Rx REO debug infrastructure

Management Rx event parameters structure is  are accessed for debug
logging, after the frame is queued in the egress/ingress list. The queued
frame might get dropped in the mean time and this may lead to the
freeing of the management Rx event parameters structure. Fix the issue
by splitting the logging into two parts. Required fields of management Rx
event parameter structure are logged before updating the ingress/egress
list.

Change-Id: If7847fa3a7aca1298216aef91f089aa77d94e6a9
CRs-Fixed: 3489094
Edayilliam Jayadev 2 سال پیش
والد
کامیت
6f869404f6
1فایلهای تغییر یافته به همراه85 افزوده شده و 34 حذف شده
  1. 85 34
      umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo.c

+ 85 - 34
umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo.c

@@ -4271,26 +4271,74 @@ mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
 }
 
 /**
- * mgmt_rx_reo_log_ingress_frame() - Log the information about a frame entering
- * the reorder algorithm.
+ * log_ingress_frame_before_list_update() - Log the information about a frame
+ * entering the reorder algorithm, before updating the ingress/egress list.
+ * @reo_ctx: management rx reorder context
+ * @desc: Pointer to frame descriptor
+ *
+ * Return: QDF_STATUS of operation
+ */
+static QDF_STATUS
+log_ingress_frame_before_list_update(struct mgmt_rx_reo_context *reo_ctx,
+				     struct mgmt_rx_reo_frame_descriptor *desc)
+{
+	struct reo_ingress_debug_info *ingress_frame_debug_info;
+	struct reo_ingress_debug_frame_info *cur_frame_debug_info;
+
+	if (!reo_ctx || !desc)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	ingress_frame_debug_info = &reo_ctx->ingress_frame_debug_info;
+
+	if (!mgmt_rx_reo_ingress_frame_debug_info_enabled
+						(ingress_frame_debug_info))
+		return QDF_STATUS_SUCCESS;
+
+	cur_frame_debug_info = &ingress_frame_debug_info->frame_list
+			[ingress_frame_debug_info->next_index];
+
+	cur_frame_debug_info->link_id =
+				mgmt_rx_reo_get_link_id(desc->rx_params);
+	cur_frame_debug_info->mgmt_pkt_ctr =
+				mgmt_rx_reo_get_pkt_counter(desc->rx_params);
+	cur_frame_debug_info->global_timestamp =
+				mgmt_rx_reo_get_global_ts(desc->rx_params);
+	cur_frame_debug_info->start_timestamp =
+				mgmt_rx_reo_get_start_ts(desc->rx_params);
+	cur_frame_debug_info->end_timestamp =
+				mgmt_rx_reo_get_end_ts(desc->rx_params);
+	cur_frame_debug_info->duration_us =
+				mgmt_rx_reo_get_duration_us(desc->rx_params);
+	cur_frame_debug_info->desc_type = desc->type;
+	cur_frame_debug_info->frame_type = desc->frame_type;
+	cur_frame_debug_info->frame_subtype = desc->frame_subtype;
+	cur_frame_debug_info->cpu_id = qdf_get_smp_processor_id();
+	cur_frame_debug_info->reo_required = desc->reo_required;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * log_ingress_frame_after_list_update() - Log the information about a frame
+ * entering the reorder algorithm, after updating the ingress/egress list.
  * @reo_ctx: management rx reorder context
  * @desc: Pointer to frame descriptor
  * @is_queued: Indicates whether this frame is queued to reorder list
  * @is_error: Indicates whether any error occurred during processing this frame
  * @context_id: context identifier
+ * @link_id: Link ID
  *
  * Return: QDF_STATUS of operation
  */
 static QDF_STATUS
-mgmt_rx_reo_log_ingress_frame(struct mgmt_rx_reo_context *reo_ctx,
-			      struct mgmt_rx_reo_frame_descriptor *desc,
-			      bool is_queued, bool is_error,
-			      int32_t context_id)
+log_ingress_frame_after_list_update(struct mgmt_rx_reo_context *reo_ctx,
+				    struct mgmt_rx_reo_frame_descriptor *desc,
+				    bool is_queued, bool is_error,
+				    int32_t context_id, uint8_t link_id)
 {
 	struct reo_ingress_debug_info *ingress_frame_debug_info;
 	struct reo_ingress_debug_frame_info *cur_frame_debug_info;
 	struct reo_ingress_frame_stats *stats;
-	uint8_t link_id;
 	enum mgmt_rx_reo_list_type queued_list;
 
 	if (!reo_ctx || !desc)
@@ -4299,7 +4347,6 @@ mgmt_rx_reo_log_ingress_frame(struct mgmt_rx_reo_context *reo_ctx,
 	ingress_frame_debug_info = &reo_ctx->ingress_frame_debug_info;
 
 	stats = &ingress_frame_debug_info->stats;
-	link_id = mgmt_rx_reo_get_link_id(desc->rx_params);
 	queued_list = desc->queued_list;
 	stats->ingress_count[link_id][desc->type]++;
 	if (desc->reo_required)
@@ -4326,20 +4373,6 @@ mgmt_rx_reo_log_ingress_frame(struct mgmt_rx_reo_context *reo_ctx,
 	cur_frame_debug_info = &ingress_frame_debug_info->frame_list
 			[ingress_frame_debug_info->next_index];
 
-	cur_frame_debug_info->link_id = link_id;
-	cur_frame_debug_info->mgmt_pkt_ctr =
-				mgmt_rx_reo_get_pkt_counter(desc->rx_params);
-	cur_frame_debug_info->global_timestamp =
-				mgmt_rx_reo_get_global_ts(desc->rx_params);
-	cur_frame_debug_info->start_timestamp =
-				mgmt_rx_reo_get_start_ts(desc->rx_params);
-	cur_frame_debug_info->end_timestamp =
-				mgmt_rx_reo_get_end_ts(desc->rx_params);
-	cur_frame_debug_info->duration_us =
-				mgmt_rx_reo_get_duration_us(desc->rx_params);
-	cur_frame_debug_info->desc_type = desc->type;
-	cur_frame_debug_info->frame_type = desc->frame_type;
-	cur_frame_debug_info->frame_subtype = desc->frame_subtype;
 	cur_frame_debug_info->wait_count = desc->wait_count;
 	qdf_mem_copy(cur_frame_debug_info->shared_snapshots,
 		     desc->shared_snapshots,
@@ -4367,8 +4400,6 @@ mgmt_rx_reo_log_ingress_frame(struct mgmt_rx_reo_context *reo_ctx,
 					desc->egress_list_size_rx;
 	cur_frame_debug_info->egress_list_insertion_pos =
 					desc->egress_list_insertion_pos;
-	cur_frame_debug_info->cpu_id = qdf_get_smp_processor_id();
-	cur_frame_debug_info->reo_required = desc->reo_required;
 	cur_frame_debug_info->context_id = context_id;
 
 	ingress_frame_debug_info->next_index++;
@@ -4604,21 +4635,37 @@ mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
 }
 
 /**
- * mgmt_rx_reo_log_ingress_frame() - Log the information about a frame entering
- * the reorder algorithm.
+ * log_ingress_frame_before_list_update() - Log the information about a frame
+ * entering the reorder algorithm, before updating the ingress/egress list.
+ * @reo_ctx: management rx reorder context
+ * @desc: Pointer to frame descriptor
+ *
+ * Return: QDF_STATUS of operation
+ */
+static QDF_STATUS
+log_ingress_frame_before_list_update(struct mgmt_rx_reo_context *reo_ctx,
+				     struct mgmt_rx_reo_frame_descriptor *desc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * log_ingress_frame_after_list_update() - Log the information about a frame
+ * entering the reorder algorithm, after updating the ingress/egress list.
  * @reo_ctx: management rx reorder context
  * @desc: Pointer to frame descriptor
  * @is_queued: Indicates whether this frame is queued to reorder list
  * @is_error: Indicates whether any error occurred during processing this frame
  * @context_id: context identifier
+ * @link_id: Link ID
  *
  * Return: QDF_STATUS of operation
  */
 static QDF_STATUS
-mgmt_rx_reo_log_ingress_frame(struct mgmt_rx_reo_context *reo_ctx,
-			      struct mgmt_rx_reo_frame_descriptor *desc,
-			      bool is_queued, bool is_error,
-			      int32_t context_id)
+log_ingress_frame_after_list_update(struct mgmt_rx_reo_context *reo_ctx,
+				    struct mgmt_rx_reo_frame_descriptor *desc,
+				    bool is_queued, bool is_error,
+				    int32_t context_id, uint8_t link_id)
 {
 	return QDF_STATUS_SUCCESS;
 }
@@ -4767,6 +4814,10 @@ wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 	    desc->type == MGMT_RX_REO_FRAME_DESC_FW_CONSUMED_FRAME)
 		qdf_assert_always(desc->rx_params->reo_params->duration_us);
 
+	ret = log_ingress_frame_before_list_update(reo_ctx, desc);
+	if (QDF_IS_STATUS_ERROR(ret))
+		goto failure;
+
 	/* Update the Host snapshot */
 	ret = wlan_mgmt_rx_reo_update_host_snapshot(pdev, desc);
 	if (QDF_IS_STATUS_ERROR(ret))
@@ -4785,8 +4836,8 @@ wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 		goto failure;
 
 	context_id = qdf_atomic_inc_return(&reo_ctx->context_id);
-	ret = mgmt_rx_reo_log_ingress_frame(reo_ctx, desc, *is_queued, false,
-					    context_id);
+	ret = log_ingress_frame_after_list_update(reo_ctx, desc, *is_queued,
+						  false, context_id, cur_link);
 	if (QDF_IS_STATUS_ERROR(ret)) {
 		qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
 		return ret;
@@ -4811,8 +4862,8 @@ failure:
 	 * Ignore the return value of this function call, return
 	 * the actual reason for failure.
 	 */
-	mgmt_rx_reo_log_ingress_frame(reo_ctx, desc, *is_queued, true,
-				      context_id);
+	log_ingress_frame_after_list_update(reo_ctx, desc, *is_queued, true,
+					    context_id, cur_link);
 
 	qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);