diff options
| author | Vignesh Viswanathan <viswanat@codeaurora.org> | 2017-09-27 20:25:33 +0530 |
|---|---|---|
| committer | snandini <snandini@codeaurora.org> | 2017-10-03 08:27:45 -0700 |
| commit | 27077eff522a611ba85747c8a905bb9238d9ae02 (patch) | |
| tree | 00e370d9447a950f71fd86e546870928e193e90c | |
| parent | 5bca4f1b0ca065db1552e1ce5707e0056ac9031e (diff) | |
qcacld-3.0: Avoid integer overflow in wma_get_ll_stats_ext_buf
Check multiple variables received from firmware used to calculate
buf_len to make sure that it does not exceed the max msg size, as
this buf_len is in turn used in malloc and can lead to less than
required memory allocated in case of integer overflow of buf_len
Change-Id: I2689873c2c5e63c83e5059563662c0c69dc659fc
CRs-Fixed: 2115112
| -rw-r--r-- | core/wma/src/wma_utils.c | 108 |
1 files changed, 93 insertions, 15 deletions
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 2fa35ff09a5f..eb8130485755 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -631,6 +631,8 @@ static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len, { tSirLLStatsResults *buf; uint32_t buf_len; + uint32_t total_array_len, total_peer_len; + bool excess_data = false; if (!len || !fixed_param) { WMA_LOGE(FL("Invalid input parameters.")); @@ -693,22 +695,98 @@ static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len, * | VO | * --------------------------------- */ + buf_len = sizeof(tSirLLStatsResults) + - sizeof(struct sir_wifi_ll_ext_stats) + - fixed_param->num_chan_cca_stats * - sizeof(struct sir_wifi_chan_cca_stats) + - peer_num * - (sizeof(struct sir_wifi_ll_ext_peer_stats) + - WLAN_MAX_AC * - (sizeof(struct sir_wifi_tx) + - sizeof(struct sir_wifi_rx)) + - sizeof(uint32_t) * WLAN_MAX_AC * - (fixed_param->tx_mpdu_aggr_array_len + - fixed_param->tx_succ_mcs_array_len + - fixed_param->tx_fail_mcs_array_len + - fixed_param->tx_ppdu_delay_array_len + - fixed_param->rx_mpdu_aggr_array_len + - fixed_param->rx_mcs_array_len)); + sizeof(struct sir_wifi_ll_ext_stats); + do { + if (fixed_param->num_chan_cca_stats > (WMI_SVC_MSG_MAX_SIZE / + sizeof(struct sir_wifi_chan_cca_stats))) { + excess_data = true; + break; + } + buf_len += (fixed_param->num_chan_cca_stats * + sizeof(struct sir_wifi_chan_cca_stats)); + if (fixed_param->tx_mpdu_aggr_array_len > + WMI_SVC_MSG_MAX_SIZE) { + excess_data = true; + break; + } else { + total_array_len = fixed_param->tx_mpdu_aggr_array_len; + } + if (fixed_param->tx_succ_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_succ_mcs_array_len; + } + if (fixed_param->tx_fail_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_fail_mcs_array_len; + } + if (fixed_param->tx_ppdu_delay_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_ppdu_delay_array_len; + } + if (fixed_param->rx_mpdu_aggr_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->rx_mpdu_aggr_array_len; + } + if (fixed_param->rx_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->rx_mcs_array_len; + } + + if (total_array_len > (WMI_SVC_MSG_MAX_SIZE / + (sizeof(uint32_t) * WLAN_MAX_AC))) { + excess_data = true; + break; + } else { + total_peer_len = (sizeof(uint32_t) * WLAN_MAX_AC * + total_array_len) + + (WLAN_MAX_AC * + (sizeof(struct sir_wifi_tx) + + sizeof(struct sir_wifi_rx))); + } + if (total_peer_len > WMI_SVC_MSG_MAX_SIZE) { + excess_data = true; + break; + } + if (peer_num > (WMI_SVC_MSG_MAX_SIZE - total_peer_len) / + sizeof(struct sir_wifi_ll_ext_peer_stats)) { + excess_data = true; + break; + } else { + buf_len += peer_num * + (sizeof(struct sir_wifi_ll_ext_peer_stats) + + total_peer_len); + } + } while (0); + + if (excess_data || (buf_len > WMI_SVC_MSG_MAX_SIZE)) { + WMA_LOGE("%s: excess wmi buffer: peer %d cca %d tx_mpdu %d tx_succ%d tx_fail %d tx_ppdu %d rx_mpdu %d rx_mcs %d", + __func__, peer_num, fixed_param->num_chan_cca_stats, + fixed_param->tx_mpdu_aggr_array_len, + fixed_param->tx_succ_mcs_array_len, + fixed_param->tx_fail_mcs_array_len, + fixed_param->tx_ppdu_delay_array_len, + fixed_param->rx_mpdu_aggr_array_len, + fixed_param->rx_mcs_array_len); + QDF_ASSERT(0); + return NULL; + } buf = (tSirLLStatsResults *)qdf_mem_malloc(buf_len); if (buf == NULL) { |
