qcacmn: Fix out-of-bounds in wlan_mlo_parse_t2lm_info
wlan_mlo_parse_t2lm_info() does not check ie_len boundary before accessing optional elements. This could lead to OOB access if presence bit is set but its corresponding sub-field is not present in the frame. Add the necessary boundary checks before accessing optional sub-fields when its presence bit is set. Change-Id: Icfc079c460e5ad3382507c11b60ef6541e9baf5e CRs-Fixed: 3895196
This commit is contained in:
parent
3c72258e79
commit
fec800ab53
@ -42,8 +42,26 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
uint8_t *link_mapping_of_tids;
|
||||
uint8_t tid_num;
|
||||
uint8_t *ie_ptr = NULL;
|
||||
uint32_t ie_len_parsed = 0;
|
||||
uint32_t ie_len = 0;
|
||||
|
||||
if (!ie || !t2lm) {
|
||||
t2lm_err("IE buffer is null");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie;
|
||||
ie_len = t2lm_ie->elem_len;
|
||||
|
||||
/* Minimum IE length is 2 bytes:
|
||||
* elem_id_extn is 1 byte
|
||||
* t2lm_control_field can be of minimum 1 byte
|
||||
*/
|
||||
if (ie_len < WLAN_T2LM_CTRL_SIZE) {
|
||||
t2lm_debug("T2LM IE min length (%u) is invalid", ie_len);
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed++;
|
||||
|
||||
t2lm_control_field = t2lm_ie->data;
|
||||
if (!t2lm_control_field) {
|
||||
@ -51,7 +69,9 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field);
|
||||
t2lm_control = *t2lm_control_field;
|
||||
if (ie_len > WLAN_T2LM_CTRL_SIZE)
|
||||
t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field);
|
||||
|
||||
dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
|
||||
WLAN_T2LM_CONTROL_DIRECTION_BITS);
|
||||
@ -88,8 +108,20 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
t2lm->link_mapping_size);
|
||||
|
||||
if (t2lm->default_link_mapping) {
|
||||
if (ie_len < (ie_len_parsed + sizeof(uint8_t))) {
|
||||
t2lm_rl_debug("Failed to parse Default link mapping=1");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += sizeof(uint8_t);
|
||||
|
||||
ie_ptr = t2lm_control_field + sizeof(uint8_t);
|
||||
} else {
|
||||
if (ie_len < (ie_len_parsed + sizeof(t2lm_control))) {
|
||||
t2lm_rl_debug("Failed to parse Default link mapping=0");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += sizeof(t2lm_control);
|
||||
|
||||
link_mapping_presence_ind =
|
||||
QDF_GET_BITS(t2lm_control,
|
||||
WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
|
||||
@ -98,12 +130,25 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
}
|
||||
|
||||
if (t2lm->mapping_switch_time_present) {
|
||||
if (ie_len < (ie_len_parsed + sizeof(uint16_t))) {
|
||||
t2lm_rl_debug("Failed to parse Mapping switch time");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += sizeof(uint16_t);
|
||||
|
||||
t2lm->mapping_switch_time =
|
||||
qdf_le16_to_cpu(*(uint16_t *)ie_ptr);
|
||||
ie_ptr += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
if (t2lm->expected_duration_present) {
|
||||
if (ie_len <
|
||||
(ie_len_parsed + WLAN_T2LM_EXPECTED_DURATION_SIZE)) {
|
||||
t2lm_rl_debug("Failed to parse Expected duration");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += WLAN_T2LM_EXPECTED_DURATION_SIZE;
|
||||
|
||||
qdf_mem_copy(&t2lm->expected_duration, ie_ptr,
|
||||
WLAN_T2LM_EXPECTED_DURATION_SIZE *
|
||||
(sizeof(uint8_t)));
|
||||
@ -113,8 +158,16 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
t2lm_debug("mapping_switch_time:%d expected_duration:%d",
|
||||
t2lm->mapping_switch_time, t2lm->expected_duration);
|
||||
|
||||
if (t2lm->default_link_mapping)
|
||||
if (t2lm->default_link_mapping) {
|
||||
/* With default link mapping set to 1, there is no
|
||||
* `Link Mapping of Tid n` field present.
|
||||
*/
|
||||
if (ie_len > ie_len_parsed) {
|
||||
t2lm_rl_debug("Link mapping of TID present when default link mapping is set");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
link_mapping_of_tids = ie_ptr;
|
||||
|
||||
@ -123,10 +176,22 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
continue;
|
||||
|
||||
if (!t2lm->link_mapping_size) {
|
||||
if (ie_len < (ie_len_parsed + sizeof(uint16_t))) {
|
||||
t2lm_rl_debug("Failed to parse Link mapping for tid=%u", tid_num);
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += sizeof(uint16_t);
|
||||
|
||||
t2lm->ieee_link_map_tid[tid_num] =
|
||||
qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids);
|
||||
link_mapping_of_tids += sizeof(uint16_t);
|
||||
} else {
|
||||
if (ie_len < (ie_len_parsed + sizeof(uint8_t))) {
|
||||
t2lm_rl_debug("Failed to parse Link mapping for tid=%u", tid_num);
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
ie_len_parsed += sizeof(uint8_t);
|
||||
|
||||
t2lm->ieee_link_map_tid[tid_num] =
|
||||
*(uint8_t *)link_mapping_of_tids;
|
||||
link_mapping_of_tids += sizeof(uint8_t);
|
||||
@ -136,6 +201,11 @@ QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
|
||||
t2lm->ieee_link_map_tid[tid_num]);
|
||||
}
|
||||
|
||||
if (ie_len > ie_len_parsed) {
|
||||
t2lm_rl_debug("More data present at the end of T2LM element");
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user