瀏覽代碼

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 年之前
父節點
當前提交
46e0a1354b
共有 1 個文件被更改,包括 49 次插入8 次删除
  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 record_size;
+	int calculated_record_size;
 	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;
+	if (num_records < 0) {
+		qdf_err("Underflow due to length %d", length);
+		return;
+	}
 	qdf_debug("Tx PPDU log elements: num_records %d", num_records);
 
 	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
 			char buf[BUF_SIZE];
 			uint8_t *p8;
+			uint8_t *calculated_p8;
 
 			time_enqueue_us =
 				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 */
 			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) {
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 						      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);
 				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) {
 				htt_make_u8_list_str((uint32_t *) p8, buf,
 						     BUF_SIZE,
 						     hdr->mpdu_msdus_array_len);
 				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) {
 				htt_make_u16_list_str((uint32_t *) p8, buf,
 						      BUF_SIZE,