diff options
| author | Abhinav Kumar <abhikuma@codeaurora.org> | 2017-12-28 15:18:07 +0530 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2018-01-12 04:46:39 -0800 |
| commit | bf8d356a579e5d63f1753bb093a3dd96327eb022 (patch) | |
| tree | d96a38ce948f275dd862e6a12919b75c1b9770eb | |
| parent | b65a7c8c4609dd0b128599abc441ffd53aa7d6ea (diff) | |
qcacld-3.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: 2153638
| -rw-r--r-- | core/wma/src/wma_features.c | 21 | ||||
| -rw-r--r-- | core/wma/src/wma_main.c | 13 | ||||
| -rw-r--r-- | core/wma/src/wma_mgmt.c | 8 | ||||
| -rw-r--r-- | core/wma/src/wma_nan_datapath.c | 16 | ||||
| -rw-r--r-- | core/wma/src/wma_ocb.c | 11 | ||||
| -rw-r--r-- | core/wma/src/wma_scan_roam.c | 42 | ||||
| -rw-r--r-- | core/wma/src/wma_utils.c | 90 |
7 files changed, 157 insertions, 44 deletions
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 59ea09bc0e58..48bad4493bb8 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -1859,8 +1859,8 @@ int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, if (nan_rsp_event_hdr->data_len > ((WMI_SVC_MSG_MAX_SIZE - sizeof(*nan_rsp_event_hdr)) / sizeof(uint8_t)) || nan_rsp_event_hdr->data_len > param_buf->num_data) { - WMA_LOGE("excess data length:%d", nan_rsp_event_hdr->data_len); - QDF_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 *) qdf_mem_malloc(alloc_len); @@ -2554,6 +2554,11 @@ QDF_STATUS wma_extract_comb_phyerr_spectral(void *handle, void *data, phyerr->bufp = param_tlvs->bufp; phyerr->buf_len = pe_hdr->buf_len; + if (phyerr->buf_len > param_tlvs->num_bufp) { + WMA_LOGE("Invalid buf_len %d, num_bufp %d", + phyerr->buf_len, param_tlvs->num_bufp); + return -EINVAL; + } phyerr->phy_err_mask0 = pe_hdr->rsPhyErrMask0; phyerr->phy_err_mask1 = pe_hdr->rsPhyErrMask1; @@ -8205,7 +8210,11 @@ int wma_channel_avoid_evt_handler(void *handle, uint8_t *event, (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; @@ -11074,6 +11083,12 @@ int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf, } rx_aggr_hole_event->hole_cnt = rx_aggr_failure_info->num_failure_info; + if (rx_aggr_hole_event->hole_cnt > param_buf->num_failure_info) { + WMA_LOGE("Invalid no of hole count: %d", + rx_aggr_hole_event->hole_cnt); + qdf_mem_free(rx_aggr_hole_event); + return -EINVAL; + } WMA_LOGD("aggr holes_sum: %d\n", rx_aggr_failure_info->num_failure_info); for (i = 0; i < rx_aggr_hole_event->hole_cnt; i++) { diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index e8a7328748e8..f5bbdab1a6eb 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3090,6 +3090,12 @@ static int wma_pdev_set_hw_mode_resp_evt_handler(void *handle, } wmi_event = param_buf->fixed_param; + if (wmi_event->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + WMA_LOGE("Invalid num_vdev_mac_entries: %d", + wmi_event->num_vdev_mac_entries); + goto fail; + } hw_mode_resp->status = wmi_event->status; hw_mode_resp->cfgd_hw_mode_index = wmi_event->cfgd_hw_mode_index; hw_mode_resp->num_vdev_mac_entries = wmi_event->num_vdev_mac_entries; @@ -3265,6 +3271,13 @@ static int wma_pdev_hw_mode_transition_evt_handler(void *handle, wmi_event = param_buf->fixed_param; vdev_mac_entry = param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping; + if (wmi_event->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + WMA_LOGE("Invalid num_vdev_mac_entries: %d", + wmi_event->num_vdev_mac_entries); + qdf_mem_free(hw_mode_trans_ind); + return -EINVAL; + } wma_process_pdev_hw_mode_trans_ind(wma, wmi_event, vdev_mac_entry, hw_mode_trans_ind); /* Pass the message to PE */ diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index d27031e3426c..9dcc8e90bbab 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3527,7 +3527,11 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data, WMA_LOGE("Rx event is NULL"); return -EINVAL; } - + if (hdr->buf_len > param_tlvs->num_bufp) { + WMA_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) || hdr->buf_len > data_len) { limit_prints_invalid_len++; diff --git a/core/wma/src/wma_nan_datapath.c b/core/wma/src/wma_nan_datapath.c index a33c75193c0d..d79bd97fdd3e 100644 --- a/core/wma/src/wma_nan_datapath.c +++ b/core/wma/src/wma_nan_datapath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -504,6 +504,15 @@ static int wma_ndp_indication_event_handler(void *handle, uint8_t *event_info, ind_event.ncs_sk_type = fixed_params->nan_csid; ind_event.scid.scid_len = fixed_params->nan_scid_len; + if (fixed_params->ndp_cfg_len > event->num_ndp_cfg || + fixed_params->ndp_app_info_len > event->num_ndp_app_info || + fixed_params->nan_scid_len > event->num_ndp_scid) { + WMA_LOGD(FL("Invalid ndp_cfg_len: %d, ndp_app_info_len: %d, nan_scid_len: %d"), + fixed_params->ndp_cfg_len, + fixed_params->ndp_app_info_len, + fixed_params->nan_scid_len); + return -EINVAL; + } if (ind_event.ndp_config.ndp_cfg_len) { ind_event.ndp_config.ndp_cfg = qdf_mem_malloc(fixed_params->ndp_cfg_len); @@ -635,6 +644,11 @@ static int wma_ndp_confirm_event_handler(void *handle, uint8_t *event_info, ndp_confirm.peer_ndi_mac_addr.bytes); ndp_confirm.ndp_info.ndp_app_info_len = fixed_params->ndp_app_info_len; + if (ndp_confirm.ndp_info.ndp_app_info_len > event->num_ndp_app_info) { + WMA_LOGE(FL("Invalid ndp_app_info_len: %d"), + ndp_confirm.ndp_info.ndp_app_info_len); + return -EINVAL; + } if (ndp_confirm.ndp_info.ndp_app_info_len) { ndp_confirm.ndp_info.ndp_app_info = diff --git a/core/wma/src/wma_ocb.c b/core/wma/src/wma_ocb.c index 745a7868052c..5dc6c87fde7d 100644 --- a/core/wma/src/wma_ocb.c +++ b/core/wma/src/wma_ocb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -514,10 +514,11 @@ static int wma_dcc_get_stats_resp_event_handler(void *handle, /* Allocate and populate the response */ if (fix_param->num_channels > ((WMI_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); - QDF_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 = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels * diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index aa6d51eff41a..b79e5f6a8b24 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -2735,6 +2735,18 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, goto cleanup_label; } + 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_LOGD("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); + goto cleanup_label; + } if (synch_event->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: received invalid vdev_id %d", __func__, synch_event->vdev_id); @@ -4776,6 +4788,10 @@ 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); @@ -5080,10 +5096,11 @@ int wma_extscan_cached_results_event_handler(void *handle, } if (event->num_entries_in_page > - (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist)) { - WMA_LOGE("%s:excess num_entries_in_page %d in WMI event", + (WMI_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); + event->num_entries_in_page, param_buf->num_bssid_list); return -EINVAL; } else { total_len = sizeof(*event) + @@ -5223,6 +5240,10 @@ 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++) rssi_num += src_chglist->num_rssi_samples; @@ -5271,6 +5292,13 @@ int wma_extscan_change_results_event_handler(void *handle, dest_ap->bssid.bytes); 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); + qdf_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++]; @@ -5336,9 +5364,11 @@ int wma_passpoint_match_event_handler(void *handle, * against a constant should not be an issue. */ if ((sizeof(*event) + event->ie_length + event->anqp_length) > - WMI_SVC_MSG_MAX_SIZE) { - WMA_LOGE("IE Length: %d or ANQP Length: %d is huge", - event->ie_length, event->anqp_length); + WMI_SVC_MSG_MAX_SIZE || + (event->ie_length + event->anqp_length) > param_buf->num_bufp) { + WMA_LOGE("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u", + event->ie_length, event->anqp_length, + param_buf->num_bufp); return -EINVAL; } diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index f8d505af1a26..534b51794644 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -457,10 +457,10 @@ int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, alloc_len += stats_ext_info->data_len; if (stats_ext_info->data_len > (WMI_SVC_MSG_MAX_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); - QDF_ASSERT(0); + sizeof(*stats_ext_info)) || stats_ext_info->data_len > + param_buf->num_data) { + WMA_LOGE("Excess data_len:%d, num_data:%d", + stats_ext_info->data_len, param_buf->num_data); return -EINVAL; } stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len); @@ -1117,6 +1117,18 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event, wmi_cca_stats = param_buf->chan_cca_stats; wmi_peer_signal = param_buf->peer_signal_stats; wmi_peer_rx = param_buf->peer_ac_rx_stats; + if (fixed_param->num_peer_signal_stats > + param_buf->num_peer_signal_stats || + fixed_param->num_peer_ac_tx_stats > + param_buf->num_peer_ac_tx_stats || + fixed_param->num_peer_ac_rx_stats > + param_buf->num_peer_ac_rx_stats) { + WMA_LOGE("%s: excess num_peer_signal_stats:%d, num_peer_ac_tx_stats:%d, num_peer_ac_rx_stats:%d", + __func__, fixed_param->num_peer_signal_stats, + fixed_param->num_peer_ac_tx_stats, + fixed_param->num_peer_ac_rx_stats); + return -EINVAL; + } /* Get the MAX of three peer numbers */ peer_num = fixed_param->num_peer_signal_stats > @@ -1302,7 +1314,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle, do { if (fixed_param->num_peers > - WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) { + WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats) || + fixed_param->num_peers > param_tlvs->num_peer_stats) { excess_data = true; break; } else { @@ -1319,7 +1332,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle, total_num_rates += temp_peer_stats->num_rates; if (total_num_rates > WMI_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; } @@ -1334,7 +1348,6 @@ static int wma_unified_link_peer_stats_event_handler(void *handle, (sizeof(*fixed_param) > WMI_SVC_MSG_MAX_SIZE - buf_len)) { WMA_LOGE("excess wmi buffer: rates:%d, peers:%d", peer_stats->num_rates, fixed_param->num_peers); - QDF_ASSERT(0); return -EINVAL; } @@ -1498,9 +1511,12 @@ static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle, fixed_param->radio_id); if (fixed_param->num_tx_power_levels > ((WMI_SVC_MSG_MAX_SIZE - - sizeof(*fixed_param)) / sizeof(uint32_t))) { - WMA_LOGE("%s: excess tx_power buffers:%d", __func__, - fixed_param->num_tx_power_levels); + sizeof(*fixed_param)) / sizeof(uint32_t)) || + fixed_param->num_tx_power_levels > + param_tlvs->num_tx_time_per_power_level) { + WMA_LOGE("%s: excess tx_power buffers:%d, num_tx_time_per_power_level:%d", + __func__, fixed_param->num_tx_power_levels, + param_tlvs->num_tx_time_per_power_level); return -EINVAL; } @@ -1638,7 +1654,8 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, return -EINVAL; } if (radio_stats->num_channels > - (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)) { + (NUM_24GHZ_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; @@ -2149,15 +2166,18 @@ 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; } - if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX) { - WMA_LOGE("%s: Excess num offload stats recvd from fw: %d", - __func__, fixed_param->num_offload_stats); + if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX || + fixed_param->num_offload_stats > + param_tlvs->num_iface_offload_stats) { + WMA_LOGE("%s: Excess num offload stats recvd from fw: %d, um_iface_offload_stats: %d", + __func__, fixed_param->num_offload_stats, + param_tlvs->num_iface_offload_stats); return -EINVAL; } @@ -2861,10 +2881,11 @@ int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats); if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE - - sizeof(*event)) / sizeof(*ht_info))) { - WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__, - event->num_vdev_stats); - QDF_ASSERT(0); + sizeof(*event)) / sizeof(*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; } for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { @@ -3071,6 +3092,13 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, } event = param_buf->fixed_param; temp = (uint8_t *) param_buf->data; + if ((event->num_pdev_stats + event->num_vdev_stats + + event->num_peer_stats) > param_buf->num_data) { + WMA_LOGE("%s: Invalid num_pdev_stats:%d or num_vdev_stats:%d or num_peer_stats:%d", + __func__, event->num_pdev_stats, event->num_vdev_stats, + event->num_peer_stats); + return -EINVAL; + } do { if (event->num_pdev_stats > ((WMI_SVC_MSG_MAX_SIZE - @@ -3154,6 +3182,12 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats; if (rssi_event) { + if (rssi_event->num_per_chain_rssi_stats > + param_buf->num_rssi_stats) { + WMA_LOGE("%s: Invalid num_per_chain_rssi_stats:%d", + __func__, rssi_event->num_per_chain_rssi_stats); + return -EINVAL; + } if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 == WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) && ((rssi_event->tlv_header & 0x0000FFFF) == @@ -3392,10 +3426,12 @@ int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info, WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__); event = param_buf->fixed_param; if (event->num_peers > - ((WMI_SVC_MSG_MAX_SIZE - - sizeof(wmi_peer_stats_info_event_fixed_param))/ - sizeof(wmi_peer_stats_info))) { - WMA_LOGE("Excess num of peers from fw %d", event->num_peers); + ((WMI_SVC_MSG_MAX_SIZE - + sizeof(wmi_peer_stats_info_event_fixed_param))/ + sizeof(wmi_peer_stats_info)) || event->num_peers > + param_buf->num_peer_stats_info) { + WMA_LOGE("Excess num of peers from fw: %d, num_peer_stats_info:%d", + event->num_peers, param_buf->num_peer_stats_info); return -EINVAL; } buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) + |
