瀏覽代碼

qcacmn: Add boundary checks to restrict memory corruption

With the reception of MBSSIE beacon frame, host tries to
construct beacon frames for the non tx VAPs as well.
For which, it has to copy all the IEs from the
received beacon's IE except the MBSSID relevant element
IDs, by comparing the subelement data.

The memcpy that is being used in this case, does not check
the space availability in the target buffer which may lead
to random memory corruption. Hence, using safe memcpy to
avoid buffer overflow.

Change-Id: Ib0861d606dba7725077dd530dd15ebff59058cfd
CRs-Fixed: 2857436
Adwait Nayak 4 年之前
父節點
當前提交
eb4f57ac02
共有 1 個文件被更改,包括 49 次插入3 次删除
  1. 49 3
      umac/scan/dispatcher/src/wlan_scan_utils_api.c

+ 49 - 3
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -1779,6 +1779,10 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 	tmp_new = util_scan_find_ie(WLAN_ELEMID_SSID, sub_copy, subie_len);
 	tmp_new = util_scan_find_ie(WLAN_ELEMID_SSID, sub_copy, subie_len);
 	if (tmp_new) {
 	if (tmp_new) {
 		scm_debug(" SSID %.*s", tmp_new[1], &tmp_new[2]);
 		scm_debug(" SSID %.*s", tmp_new[1], &tmp_new[2]);
+		if ((pos - new_ie + tmp_new[1] + 2) > MAX_IE_LEN) {
+			qdf_mem_free(sub_copy);
+			return 0;
+		}
 		qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
 		qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
 		pos += (tmp_new[1] + 2);
 		pos += (tmp_new[1] + 2);
 	}
 	}
@@ -1796,10 +1800,15 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 		}
 		}
 
 
 		tmp = (uint8_t *)util_scan_find_ie(tmp_old[0], sub_copy,
 		tmp = (uint8_t *)util_scan_find_ie(tmp_old[0], sub_copy,
-				subie_len);
+						   subie_len);
 		if (!tmp) {
 		if (!tmp) {
 			/* ie in old ie but not in subelement */
 			/* ie in old ie but not in subelement */
 			if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
 			if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
+				if ((pos - new_ie + tmp_old[1] + 2) >
+				    MAX_IE_LEN) {
+					qdf_mem_free(sub_copy);
+					return 0;
+				}
 				qdf_mem_copy(pos, tmp_old, tmp_old[1] + 2);
 				qdf_mem_copy(pos, tmp_old, tmp_old[1] + 2);
 				pos += tmp_old[1] + 2;
 				pos += tmp_old[1] + 2;
 			}
 			}
@@ -1815,10 +1824,20 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 					/* same vendor ie, copy from
 					/* same vendor ie, copy from
 					 * subelement
 					 * subelement
 					 */
 					 */
+					if ((pos - new_ie + tmp[1] + 2) >
+					    MAX_IE_LEN) {
+						qdf_mem_free(sub_copy);
+						return 0;
+					}
 					qdf_mem_copy(pos, tmp, tmp[1] + 2);
 					qdf_mem_copy(pos, tmp, tmp[1] + 2);
 					pos += tmp[1] + 2;
 					pos += tmp[1] + 2;
 					tmp[0] = 0;
 					tmp[0] = 0;
 				} else {
 				} else {
+					if ((pos - new_ie + tmp_old[1] + 2) >
+					    MAX_IE_LEN) {
+						qdf_mem_free(sub_copy);
+						return 0;
+					}
 					qdf_mem_copy(pos, tmp_old,
 					qdf_mem_copy(pos, tmp_old,
 						     tmp_old[1] + 2);
 						     tmp_old[1] + 2);
 					pos += tmp_old[1] + 2;
 					pos += tmp_old[1] + 2;
@@ -1826,16 +1845,30 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 			} else if (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM) {
 			} else if (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM) {
 				if (tmp_old[2] == tmp[2]) {
 				if (tmp_old[2] == tmp[2]) {
 					/* same ie, copy from subelement */
 					/* same ie, copy from subelement */
+					if ((pos - new_ie + tmp[1] + 2) >
+					    MAX_IE_LEN) {
+						qdf_mem_free(sub_copy);
+						return 0;
+					}
 					qdf_mem_copy(pos, tmp, tmp[1] + 2);
 					qdf_mem_copy(pos, tmp, tmp[1] + 2);
 					pos += tmp[1] + 2;
 					pos += tmp[1] + 2;
 					tmp[0] = 0;
 					tmp[0] = 0;
 				} else {
 				} else {
+					if ((pos - new_ie + tmp_old[1] + 2) >
+					    MAX_IE_LEN) {
+						qdf_mem_free(sub_copy);
+						return 0;
+					}
 					qdf_mem_copy(pos, tmp_old,
 					qdf_mem_copy(pos, tmp_old,
 						     tmp_old[1] + 2);
 						     tmp_old[1] + 2);
 					pos += tmp_old[1] + 2;
 					pos += tmp_old[1] + 2;
 				}
 				}
 			} else {
 			} else {
 				/* copy ie from subelement into new ie */
 				/* copy ie from subelement into new ie */
+				if ((pos - new_ie + tmp[1] + 2) > MAX_IE_LEN) {
+					qdf_mem_free(sub_copy);
+					return 0;
+				}
 				qdf_mem_copy(pos, tmp, tmp[1] + 2);
 				qdf_mem_copy(pos, tmp, tmp[1] + 2);
 				pos += tmp[1] + 2;
 				pos += tmp[1] + 2;
 				tmp[0] = 0;
 				tmp[0] = 0;
@@ -1856,6 +1889,10 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 		if (!(tmp_new[0] == WLAN_ELEMID_NONTX_BSSID_CAP ||
 		if (!(tmp_new[0] == WLAN_ELEMID_NONTX_BSSID_CAP ||
 		      tmp_new[0] == WLAN_ELEMID_SSID ||
 		      tmp_new[0] == WLAN_ELEMID_SSID ||
 		      tmp_new[0] == WLAN_ELEMID_MULTI_BSSID_IDX)) {
 		      tmp_new[0] == WLAN_ELEMID_MULTI_BSSID_IDX)) {
+			if ((pos - new_ie + tmp_new[1] + 2) > MAX_IE_LEN) {
+				qdf_mem_free(sub_copy);
+				return 0;
+			}
 			qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
 			qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
 			pos += tmp_new[1] + 2;
 			pos += tmp_new[1] + 2;
 		}
 		}
@@ -1884,11 +1921,11 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 	QDF_STATUS status;
 	QDF_STATUS status;
 	uint8_t *pos, *subelement, *mbssid_end_pos;
 	uint8_t *pos, *subelement, *mbssid_end_pos;
 	uint8_t *tmp, *mbssid_index_ie;
 	uint8_t *tmp, *mbssid_index_ie;
-	uint32_t subie_len, new_ie_len;
+	uint32_t subie_len, new_ie_len, ielen;
 	uint8_t new_bssid[QDF_MAC_ADDR_SIZE], bssid[QDF_MAC_ADDR_SIZE];
 	uint8_t new_bssid[QDF_MAC_ADDR_SIZE], bssid[QDF_MAC_ADDR_SIZE];
 	uint8_t *new_ie;
 	uint8_t *new_ie;
 	uint8_t *ie, *new_frame = NULL;
 	uint8_t *ie, *new_frame = NULL;
-	uint64_t ielen, new_frame_len;
+	int new_frame_len;
 
 
 	hdr = (struct wlan_frame_hdr *)frame;
 	hdr = (struct wlan_frame_hdr *)frame;
 	bcn = (struct wlan_bcn_frame *)(frame + sizeof(struct wlan_frame_hdr));
 	bcn = (struct wlan_bcn_frame *)(frame + sizeof(struct wlan_frame_hdr));
@@ -1957,6 +1994,15 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 				continue;
 				continue;
 
 
 			new_frame_len = frame_len - ielen + new_ie_len;
 			new_frame_len = frame_len - ielen + new_ie_len;
+
+			if (new_frame_len < 0) {
+				qdf_mem_free(new_ie);
+				scm_err("Invalid frame:Stop MBSSIE parsing");
+				scm_err("Frame_len: %zu,ielen:%u,new_ie_len:%u",
+					frame_len, ielen, new_ie_len);
+				return QDF_STATUS_E_INVAL;
+			}
+
 			new_frame = qdf_mem_malloc(new_frame_len);
 			new_frame = qdf_mem_malloc(new_frame_len);
 			if (!new_frame) {
 			if (!new_frame) {
 				qdf_mem_free(new_ie);
 				qdf_mem_free(new_ie);