qcacld-2.0: Fix multiple length definition issue in WLAN FW message

Currently, firmware fills the num variables value of param_tlvs
structure for all wmi commands. But during buffer write the fixed param
values are used to check maximum limit of buffer in wmi commands.
Due to multiple length definition of num variable in WLAN FW message,
num variables of param_tlvs may not equal to max limit defined in
fixed_param, resulting OOB issues in WLAN FW messages during buffer write.
Add sanity check to make sure that num variables value doesn’t exceed max
limit of num value defined in param_tlvs.

Change-Id: I43c15557057ab5b900f19b9f54426dcdf85e2c27
CRs-Fixed: 2226556
This commit is contained in:
Tiger Yu 2019-07-25 15:13:45 +08:00 committed by L R
parent 1dae7178e7
commit 68b103fb46
3 changed files with 71 additions and 23 deletions

View File

@ -596,6 +596,12 @@ static int tlshim_mgmt_rx_process(void *context, u_int8_t *data,
return 0;
}
if (hdr->buf_len > param_tlvs->num_bufp) {
TLSHIM_LOGE("Invalid length of frame hdr->buf_len:%u, param_tlvs->num_bufp:%u",
hdr->buf_len, param_tlvs->num_bufp);
return -EINVAL;
}
if (hdr->buf_len < sizeof(struct ieee80211_frame) ||
(!saved_beacon && hdr->buf_len > data_len)) {
adf_os_spin_unlock_bh(&tl_shim->mgmt_lock);

View File

@ -2949,10 +2949,12 @@ static int wma_link_status_event_handler(void *handle, u_int8_t *cmd_param_info,
event = param_buf->fixed_param;
if (event->num_vdev_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_vdev_rate_ht_info))) {
WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__,
event->num_vdev_stats);
VOS_ASSERT(0);
sizeof(*event)) / sizeof(wmi_vdev_rate_ht_info)) ||
event->num_vdev_stats > param_buf->num_ht_info) {
WMA_LOGE("%s: excess vdev_stats buffers:%d, num_ht_info:%d",
__func__,
event->num_vdev_stats,
param_buf->num_ht_info);
return -EINVAL;
}
buf_size = sizeof(wmi_vdev_rate_stats_event_fixed_param) +
@ -3770,6 +3772,10 @@ static int wma_extscan_hotlist_match_event_handler(void *handle,
WMA_LOGE("%s: Hotlist AP's list invalid", __func__);
return -EINVAL;
}
if (numap > param_buf->num_hotlist_match) {
WMA_LOGE("Invalid no of total enteries %d", numap);
return -EINVAL;
}
if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) {
WMA_LOGE("%s: Total Entries %u greater than max",
__func__, numap);
@ -4068,9 +4074,11 @@ static int wma_extscan_cached_results_event_handler(void *handle,
goto noresults;
}
if (event->num_entries_in_page >
(WMA_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist)) {
WMA_LOGE("%s:excess num_entries_in_page %d in WMI event",
__func__, event->num_entries_in_page);
(WMA_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) ||
event->num_entries_in_page > param_buf->num_bssid_list) {
WMA_LOGE("%s:excess num_entries_in_page %d in WMI event. num_bssid_list %d",
__func__,
event->num_entries_in_page, param_buf->num_bssid_list);
return -EINVAL;
} else {
total_len = sizeof(*event) +
@ -4201,6 +4209,10 @@ static int wma_extscan_change_results_event_handler(void *handle,
WMA_LOGE("%s: Results invalid", __func__);
return -EINVAL;
}
if (numap > param_buf->num_bssid_signal_descriptor_list) {
WMA_LOGE("%s: Invalid num of entries in page: %d", __func__, numap);
return -EINVAL;
}
for (i = 0; i < numap; i++) {
if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) {
WMA_LOGE("%s: Invalid num of rssi samples %d numap %d rssi_num %d",
@ -4258,6 +4270,13 @@ static int wma_extscan_change_results_event_handler(void *handle,
dest_ap->numOfRssi =
src_chglist->num_rssi_samples;
if (dest_ap->numOfRssi) {
if ((dest_ap->numOfRssi + count) >
param_buf->num_rssi_list) {
WMA_LOGE("%s: Invalid num in rssi list: %d",
__func__, dest_ap->numOfRssi);
vos_mem_free(dest_chglist);
return -EINVAL;
}
for (k = 0; k < dest_ap->numOfRssi; k++) {
dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM +
src_rssi[count++];
@ -4441,9 +4460,10 @@ static int wma_unified_link_iface_stats_event_handler(void *handle,
WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
return -EINVAL;
}
if (link_stats->num_ac > WIFI_AC_MAX) {
WMA_LOGE("%s: Excess data received from firmware num_ac %d",
__func__, link_stats->num_ac);
if (link_stats->num_ac > WIFI_AC_MAX || link_stats->num_ac >
param_tlvs->num_ac) {
WMA_LOGE("%s: Excess data received from firmware num_ac %d, param_tlvs->num_ac %d",
__func__, link_stats->num_ac, param_tlvs->num_ac);
return -EINVAL;
}
@ -4607,7 +4627,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
do {
if (fixed_param->num_peers >
WMA_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) {
WMA_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats) ||
fixed_param->num_peers > param_tlvs->num_peer_stats) {
excess_data = true;
break;
} else {
@ -4624,7 +4645,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
total_num_rates += temp_peer_stats->num_rates;
if (total_num_rates >
WMA_SVC_MSG_MAX_SIZE /
sizeof(wmi_rate_stats)) {
sizeof(wmi_rate_stats) || total_num_rates >
param_tlvs->num_peer_rate_stats) {
excess_data = true;
break;
}
@ -4639,7 +4661,6 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
(buf_len > WMA_SVC_MSG_MAX_SIZE - sizeof(*fixed_param))) {
WMA_LOGE("excess wmi buffer: rates:%d, peers:%d",
peer_stats->num_rates, fixed_param->num_peers);
VOS_ASSERT(0);
return -EINVAL;
}
@ -4778,7 +4799,8 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
}
if (radio_stats->num_channels >
NUM_2_4GHZ_CHANNELS + NUM_5GHZ_CHANNELS) {
(NUM_2_4GHZ_CHANNELS + NUM_5GHZ_CHANNELS) ||
radio_stats->num_channels > param_tlvs->num_channel_stats) {
WMA_LOGE("%s: Too many channels %d",
__func__, radio_stats->num_channels);
return -EINVAL;
@ -6142,8 +6164,8 @@ static int wma_nan_rsp_event_handler(void *handle, u_int8_t *event_buf,
if (nan_rsp_event_hdr->data_len > ((WMA_SVC_MSG_MAX_SIZE -
WMI_TLV_HDR_SIZE - sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t)) ||
nan_rsp_event_hdr->data_len > param_buf->num_data) {
WMA_LOGE("excess data length:%d", nan_rsp_event_hdr->data_len);
VOS_ASSERT(0);
WMA_LOGE("excess data length:%d, num_data:%d",
nan_rsp_event_hdr->data_len, param_buf->num_data);
return -EINVAL;
}
nan_rsp_event = (tSirNanEvent *) vos_mem_malloc(alloc_len);
@ -6491,6 +6513,19 @@ static int wma_roam_synch_event_handler(void *handle, u_int8_t *event, u_int32_t
return -EINVAL;
}
if (synch_event->bcn_probe_rsp_len >
param_buf->num_bcn_probe_rsp_frame ||
synch_event->reassoc_req_len >
param_buf->num_reassoc_req_frame ||
synch_event->reassoc_rsp_len >
param_buf->num_reassoc_rsp_frame) {
WMA_LOGE("Invalid synch payload: LEN bcn:%d, req:%d, rsp:%d",
synch_event->bcn_probe_rsp_len,
synch_event->reassoc_req_len,
synch_event->reassoc_rsp_len);
return -EINVAL;
}
if(wma->interfaces[synch_event->vdev_id].roam_synch_in_progress ==
VOS_TRUE) {
WMA_LOGE("%s: Ignoring RSI since one is already in progress",
@ -6845,7 +6880,8 @@ static int wma_stats_ext_event_handler(void *handle, u_int8_t *event_buf,
if (stats_ext_info->data_len > (WMA_SVC_MSG_MAX_SIZE -
WMI_TLV_HDR_SIZE - sizeof(*stats_ext_info)) ||
stats_ext_info->data_len > param_buf->num_data) {
WMA_LOGE("Excess data_len:%d", stats_ext_info->data_len);
WMA_LOGE("Excess data_len:%d, num_data:%d",
stats_ext_info->data_len, param_buf->num_data);
VOS_ASSERT(0);
return -EINVAL;
}
@ -30452,7 +30488,11 @@ static int wma_channel_avoid_evt_handler(void *handle, u_int8_t *event,
num_freq_ranges = (afr_fixed_param->num_freq_ranges > SIR_CH_AVOID_MAX_RANGE)?
SIR_CH_AVOID_MAX_RANGE:afr_fixed_param->num_freq_ranges;
if (num_freq_ranges > param_buf->num_avd_freq_range) {
WMA_LOGE("Invalid num_freq_ranges %d, avd_freq_range %d",
num_freq_ranges, param_buf->num_avd_freq_range);
return -EINVAL;
}
WMA_LOGD("Channel avoid event received with %d ranges", num_freq_ranges);
for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; freq_range_idx++) {
afr_desc = (wmi_avoid_freq_range_desc *) ((void *)param_buf->avd_freq_range

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -807,10 +807,12 @@ int wma_dcc_get_stats_resp_event_handler(void *handle, uint8_t *event_buf,
/* Allocate and populate the response */
if (fix_param->num_channels > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel))) {
WMA_LOGE("%s: too many channels:%d", __func__,
fix_param->num_channels);
VOS_ASSERT(0);
sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) ||
fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
WMA_LOGE("%s: too many channels:%d, param_tlvs->num_stats_per_channel_list:%d",
__func__,
fix_param->num_channels,
param_tlvs->num_stats_per_channel_list);
return -EINVAL;
}
response = vos_mem_malloc(sizeof(*response) + fix_param->num_channels *