Sfoglia il codice sorgente

qcacld-3.0: Possible Out Of Bound reads in htt_t2h_tx_ppdu_log_print()

mpdu_bytes_array_len, mpdu_msdus_array_len, and msdu_bytes_array_len
are used to calculate the record size, as well as used as
buffer offset, without any verification. This can cause to multiple
overflows and underflow leading to OOB reads.

Add checks for each arithmetic operation with these variables.

Change-Id: Ib6ec6ac6932eb8c541bc2357d45d3feaf39fdb7d
CRs-Fixed: 2226125
jitiphil 7 anni fa
parent
commit
46e0a1354b
1 ha cambiato i file con 49 aggiunte e 8 eliminazioni
  1. 49 8
      core/dp/htt/htt_fw_stats.c

+ 49 - 8
core/dp/htt/htt_fw_stats.c

@@ -832,14 +832,37 @@ htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr,
 {
 {
 	int i;
 	int i;
 	int record_size;
 	int record_size;
+	int calculated_record_size;
 	int num_records;
 	int num_records;
 
 
-	record_size =
-		sizeof(*record) +
-		hdr->mpdu_bytes_array_len * sizeof(uint16_t) +
-		hdr->mpdu_msdus_array_len * sizeof(uint8_t) +
-		hdr->msdu_bytes_array_len * sizeof(uint16_t);
+	record_size = sizeof(*record);
+	calculated_record_size = record_size +
+				hdr->mpdu_bytes_array_len * sizeof(uint16_t);
+	if (calculated_record_size < record_size) {
+		qdf_err("Overflow due to record and hdr->mpdu_bytes_array_len %u",
+			hdr->mpdu_bytes_array_len);
+		return;
+	}
+	record_size = calculated_record_size;
+	calculated_record_size += hdr->mpdu_msdus_array_len * sizeof(uint8_t);
+	if (calculated_record_size < record_size) {
+		qdf_err("Overflow due to hdr->mpdu_msdus_array_len %u",
+			hdr->mpdu_msdus_array_len);
+		return;
+	}
+	record_size = calculated_record_size;
+	calculated_record_size += hdr->msdu_bytes_array_len * sizeof(uint16_t);
+	if (calculated_record_size < record_size) {
+		qdf_err("Overflow due to hdr->msdu_bytes_array_len %u",
+			hdr->msdu_bytes_array_len);
+		return;
+	}
+	record_size = calculated_record_size;
 	num_records = (length - sizeof(*hdr)) / record_size;
 	num_records = (length - sizeof(*hdr)) / record_size;
+	if (num_records < 0) {
+		qdf_err("Underflow due to length %d", length);
+		return;
+	}
 	qdf_debug("Tx PPDU log elements: num_records %d", num_records);
 	qdf_debug("Tx PPDU log elements: num_records %d", num_records);
 
 
 	for (i = 0; i < num_records; i++) {
 	for (i = 0; i < num_records; i++) {
@@ -871,6 +894,7 @@ htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr,
 #define BUF_SIZE 80
 #define BUF_SIZE 80
 			char buf[BUF_SIZE];
 			char buf[BUF_SIZE];
 			uint8_t *p8;
 			uint8_t *p8;
+			uint8_t *calculated_p8;
 
 
 			time_enqueue_us =
 			time_enqueue_us =
 				HTT_TICK_TO_USEC(record->timestamp_enqueue,
 				HTT_TICK_TO_USEC(record->timestamp_enqueue,
@@ -942,7 +966,12 @@ htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr,
 			}
 			}
 			/* skip the regular msg fields to reach the tail area */
 			/* skip the regular msg fields to reach the tail area */
 			p8 = (uint8_t *) record;
 			p8 = (uint8_t *) record;
-			p8 += sizeof(struct ol_fw_tx_dbg_ppdu_base);
+			calculated_p8 = p8 + sizeof(struct ol_fw_tx_dbg_ppdu_base);
+			if (calculated_p8 < p8) {
+				qdf_err("Overflow due to record %p", p8);
+				continue;
+			}
+			p8 = calculated_p8;
 			if (hdr->mpdu_bytes_array_len) {
 			if (hdr->mpdu_bytes_array_len) {
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 						      BUF_SIZE,
 						      BUF_SIZE,
@@ -950,14 +979,26 @@ htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr,
 						      mpdu_bytes_array_len);
 						      mpdu_bytes_array_len);
 				qdf_debug("   MPDU bytes: %s", buf);
 				qdf_debug("   MPDU bytes: %s", buf);
 			}
 			}
-			p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t);
+			calculated_p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t);
+			if (calculated_p8 < p8) {
+				qdf_err("Overflow due to hdr->mpdu_bytes_array_len %u",
+					hdr->mpdu_bytes_array_len);
+				continue;
+			}
+			p8 = calculated_p8;
 			if (hdr->mpdu_msdus_array_len) {
 			if (hdr->mpdu_msdus_array_len) {
 				htt_make_u8_list_str((uint32_t *) p8, buf,
 				htt_make_u8_list_str((uint32_t *) p8, buf,
 						     BUF_SIZE,
 						     BUF_SIZE,
 						     hdr->mpdu_msdus_array_len);
 						     hdr->mpdu_msdus_array_len);
 				qdf_debug("   MPDU MSDUs: %s", buf);
 				qdf_debug("   MPDU MSDUs: %s", buf);
 			}
 			}
-			p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t);
+			calculated_p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t);
+			if (calculated_p8 < p8) {
+				qdf_err("Overflow due to hdr->mpdu_msdus_array_len %u",
+					hdr->mpdu_msdus_array_len);
+				continue;
+			}
+			p8 = calculated_p8;
 			if (hdr->msdu_bytes_array_len) {
 			if (hdr->msdu_bytes_array_len) {
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 						      BUF_SIZE,
 						      BUF_SIZE,