qcacmn: Fix out of bound issue in util_scan_parse_mbssid()

During multiple BSSID scan ie parse, there is memory allocation
on new_ie variable of size 1024 which may create buffer overflow
in util_gen_new_ie() if ie length is greater than 1024.

As part of fix, allocate memory of size ie length in new_ie.
And also add check before copying to pos variable in
util_gen_new_ie().

Change-Id: I55e0819817b5a616684067170bf28a314a145fc2
CRs-Fixed: 2867353
Este commit está contenido en:
Jyoti Kumari
2021-02-03 17:10:16 +05:30
cometido por snandini
padre cded00d118
commit a426e5e166

Ver fichero

@@ -1800,6 +1800,7 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
uint8_t *pos, *tmp;
const uint8_t *tmp_old, *tmp_new;
uint8_t *sub_copy;
size_t tmp_rem_len;
/* copy subelement as we need to change its content to
* mark an ie after it is processed.
@@ -1815,12 +1816,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);
if (tmp_new) {
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;
if ((pos + tmp_new[1] + 2) <= (new_ie + ielen)) {
qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
pos += (tmp_new[1] + 2);
}
qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
pos += (tmp_new[1] + 2);
}
/* go through IEs in ie (skip SSID) and subelement,
@@ -1840,13 +1839,12 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
if (!tmp) {
/* ie in old ie but not in subelement */
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;
if ((pos + tmp_old[1] + 2) <=
(new_ie + ielen)) {
qdf_mem_copy(pos, tmp_old,
tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
qdf_mem_copy(pos, tmp_old, tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
} else {
/* ie in transmitting ie also in subelement,
@@ -1855,59 +1853,53 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
* vendor ie, compare OUI + type + subType to
* determine if they are the same ie.
*/
if (tmp_old[0] == WLAN_ELEMID_VENDOR) {
tmp_rem_len = subie_len - (tmp - sub_copy);
if (tmp_old[0] == WLAN_ELEMID_VENDOR &&
tmp_rem_len >= 7) {
if (!qdf_mem_cmp(tmp_old + 2, tmp + 2, 5)) {
/* same vendor ie, copy from
* subelement
*/
if ((pos - new_ie + tmp[1] + 2) >
MAX_IE_LEN) {
qdf_mem_free(sub_copy);
return 0;
if ((pos + tmp[1] + 2) <=
(new_ie + ielen)) {
qdf_mem_copy(pos, tmp,
tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
}
qdf_mem_copy(pos, tmp, tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
} else {
if ((pos - new_ie + tmp_old[1] + 2) >
MAX_IE_LEN) {
qdf_mem_free(sub_copy);
return 0;
if ((pos + tmp_old[1] + 2) <=
(new_ie + ielen)) {
qdf_mem_copy(pos, tmp_old,
tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
qdf_mem_copy(pos, tmp_old,
tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
} else if (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM) {
if (tmp_old[2] == tmp[2]) {
/* same ie, copy from subelement */
if ((pos - new_ie + tmp[1] + 2) >
MAX_IE_LEN) {
qdf_mem_free(sub_copy);
return 0;
if ((pos + tmp[1] + 2) <=
(new_ie + ielen)) {
qdf_mem_copy(pos, tmp,
tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
}
qdf_mem_copy(pos, tmp, tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
} else {
if ((pos - new_ie + tmp_old[1] + 2) >
MAX_IE_LEN) {
qdf_mem_free(sub_copy);
return 0;
if ((pos + tmp_old[1] + 2) <=
(new_ie + ielen)) {
qdf_mem_copy(pos, tmp_old,
tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
qdf_mem_copy(pos, tmp_old,
tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
} else {
/* copy ie from subelement into new ie */
if ((pos - new_ie + tmp[1] + 2) > MAX_IE_LEN) {
qdf_mem_free(sub_copy);
return 0;
if ((pos + tmp[1] + 2) <= (new_ie + ielen)) {
qdf_mem_copy(pos, tmp, tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
}
qdf_mem_copy(pos, tmp, tmp[1] + 2);
pos += tmp[1] + 2;
tmp[0] = 0;
}
}
@@ -1925,12 +1917,10 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
if (!(tmp_new[0] == WLAN_ELEMID_NONTX_BSSID_CAP ||
tmp_new[0] == WLAN_ELEMID_SSID ||
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;
if ((pos + tmp_new[1] + 2) <= (new_ie + ielen)) {
qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
pos += tmp_new[1] + 2;
}
qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
pos += tmp_new[1] + 2;
}
if (((tmp_new + tmp_new[1] + 2) - sub_copy) >= subie_len)
break;
@@ -1976,7 +1966,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
pos = ie;
new_ie = qdf_mem_malloc(MAX_IE_LEN);
new_ie = qdf_mem_malloc(ielen);
if (!new_ie)
return QDF_STATUS_E_NOMEM;