From f8800692cd8b7e32bdd1b6c0fc3943e58dc55ebb Mon Sep 17 00:00:00 2001 From: Vignesh Viswanathan Date: Thu, 28 Sep 2017 14:49:00 +0530 Subject: [PATCH] qcacld-3.0: Fix potential buffer overwrite in wma_roam_synch_event_handler In the function wma_roam_synch_event_handler, vdev_id is received from the fw and is used to access member of the array wma->interfaces without validating the max of the vdev_id received from the fw Add check to make sure vdev_id is less than max_bssid before using it Change-Id: I3b940e183ab66680891cb7351af4537b50afce1d CRs-Fixed: 2114187 --- core/wma/src/wma_scan_roam.c | 51 +++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 13dff55cb866..89a0f88c6cf7 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -2416,6 +2416,7 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, int status = -EINVAL; tSirRoamOffloadScanReq *roam_req; qdf_time_t roam_synch_received = qdf_get_system_timestamp(); + uint32_t roam_synch_data_len; WMA_LOGD("LFR3:%s", __func__); if (!event) { @@ -2435,6 +2436,12 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, goto cleanup_label; } + if (synch_event->vdev_id > wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, synch_event->vdev_id); + goto cleanup_label; + } + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, synch_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, QDF_PROTO_TYPE_EVENT, QDF_ROAM_SYNCH)); @@ -2451,17 +2458,33 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, * Maximum number during the addition would be (3 * MAX_LIMIT(UINT32) + * few fixed fields). */ - if (sizeof(*synch_event) + synch_event->bcn_probe_rsp_len + - synch_event->reassoc_rsp_len + - synch_event->reassoc_req_len + - sizeof(wmi_channel) + sizeof(wmi_key_material) + - sizeof(uint32_t) > WMI_SVC_MSG_MAX_SIZE) { - WMA_LOGE("excess 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); + WMA_LOGD("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); + if (synch_event->bcn_probe_rsp_len > WMI_SVC_MSG_MAX_SIZE) goto cleanup_label; - } + if (synch_event->reassoc_rsp_len > + (WMI_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len)) + goto cleanup_label; + if (synch_event->reassoc_req_len > + WMI_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len + + synch_event->reassoc_rsp_len)) + goto cleanup_label; + roam_synch_data_len = synch_event->bcn_probe_rsp_len + + synch_event->reassoc_rsp_len + synch_event->reassoc_req_len; + /* + * Below is the check for the entire size of the message received from' + * the firmware. + */ + if (roam_synch_data_len > WMI_SVC_MSG_MAX_SIZE - + (sizeof(*synch_event) + sizeof(wmi_channel) + + sizeof(wmi_key_material) + sizeof(uint32_t))) + goto cleanup_label; + if (sizeof(roam_offload_synch_ind) > + (WMI_SVC_MSG_MAX_SIZE - roam_synch_data_len)) + goto cleanup_label; + roam_synch_data_len += sizeof(roam_offload_synch_ind); cds_host_diag_log_work(&wma->roam_ho_wl, WMA_ROAM_HO_WAKE_LOCK_DURATION, @@ -2470,10 +2493,8 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, WMA_ROAM_HO_WAKE_LOCK_DURATION); wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = true; - len = sizeof(roam_offload_synch_ind) + - synch_event->bcn_probe_rsp_len + synch_event->reassoc_rsp_len + - synch_event->reassoc_req_len; - roam_synch_ind_ptr = (roam_offload_synch_ind *)qdf_mem_malloc(len); + roam_synch_ind_ptr = + (roam_offload_synch_ind *)qdf_mem_malloc(roam_synch_data_len); if (!roam_synch_ind_ptr) { WMA_LOGE("%s: failed to allocate memory for roam_synch_event", __func__); @@ -2481,7 +2502,7 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, status = -ENOMEM; goto cleanup_label; } - qdf_mem_zero(roam_synch_ind_ptr, len); + qdf_mem_zero(roam_synch_ind_ptr, roam_synch_data_len); status = wma_fill_roam_synch_buffer(wma, roam_synch_ind_ptr, param_buf); if (status != 0)