Răsfoiți Sursa

qcacmn: Increment skb users for TSO pkt before enqueue of first segment

TSO packet segments are enqueued to the HW individually.
The skb users count is incremented for each additional
segment, so that it is freed only when the TX completion
for the last segment is received.

Currently the skb users is incremented for the additional
TSO segments after the previous segment has been enqueued
to the HW. Due to this, there is a chance for the tx
completion for the first TSO segment to be received even
before the skb users is incremented to account for the
remaining TSO segments, thereby leading to use-after-free
scenarios.

Fix this by incrementing the skb users for additional
TSO segment before enqueueing the previous TSO segment
to the HW.

Change-Id: Idebc28719ba6f0223d5454e15c3cde349803816e
CRs-Fixed: 2801777
Rakesh Pillai 4 ani în urmă
părinte
comite
b91fda62d9
1 a modificat fișierele cu 35 adăugiri și 22 ștergeri
  1. 35 22
      dp/wifi3.0/dp_tx.c

+ 35 - 22
dp/wifi3.0/dp_tx.c

@@ -2166,6 +2166,30 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 			HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1);
 		}
 
+		/*
+		 * For frames with multiple segments (TSO, ME), jump to next
+		 * segment.
+		 */
+		if (msdu_info->frm_type == dp_tx_frm_tso) {
+			if (msdu_info->u.tso_info.curr_seg->next) {
+				msdu_info->u.tso_info.curr_seg =
+					msdu_info->u.tso_info.curr_seg->next;
+
+				/*
+				 * If this is a jumbo nbuf, then increment the
+				 * number of nbuf users for each additional
+				 * segment of the msdu. This will ensure that
+				 * the skb is freed only after receiving tx
+				 * completion for all segments of an nbuf
+				 */
+				qdf_nbuf_inc_users(nbuf);
+
+				/* Check with MCL if this is needed */
+				/* nbuf = msdu_info->u.tso_info.curr_seg->nbuf;
+				 */
+			}
+		}
+
 		/*
 		 * Enqueue the Tx MSDU descriptor to HW for transmit
 		 */
@@ -2210,6 +2234,17 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 				i++;
 				continue;
 			}
+
+			/*
+			 * For TSO frames, the nbuf users increment done for
+			 * the current segment has to be reverted, since the
+			 * hw enqueue for this segment failed
+			 */
+			if (msdu_info->frm_type == dp_tx_frm_tso &&
+			    msdu_info->u.tso_info.curr_seg) {
+				qdf_nbuf_free(nbuf);
+			}
+
 			goto done;
 		}
 
@@ -2220,28 +2255,6 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 		 * can be combined into 1
 		 */
 
-		/*
-		 * For frames with multiple segments (TSO, ME), jump to next
-		 * segment.
-		 */
-		if (msdu_info->frm_type == dp_tx_frm_tso) {
-			if (msdu_info->u.tso_info.curr_seg->next) {
-				msdu_info->u.tso_info.curr_seg =
-					msdu_info->u.tso_info.curr_seg->next;
-
-				/*
-				 * If this is a jumbo nbuf, then increment the number of
-				 * nbuf users for each additional segment of the msdu.
-				 * This will ensure that the skb is freed only after
-				 * receiving tx completion for all segments of an nbuf
-				 */
-				qdf_nbuf_inc_users(nbuf);
-
-				/* Check with MCL if this is needed */
-				/* nbuf = msdu_info->u.tso_info.curr_seg->nbuf; */
-			}
-		}
-
 		/*
 		 * For Multicast-Unicast converted packets,
 		 * each converted frame (for a client) is represented as