summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVignesh Viswanathan <viswanat@codeaurora.org>2017-11-14 14:58:54 +0530
committersnandini <snandini@codeaurora.org>2017-11-15 08:45:07 -0800
commit6e9ed1d63d3bad802185c3be6342ee38d7df59f7 (patch)
treee21a758238641cc0e34ca528520029b49079d4f8
parent6479dea25a024032018cd519c3aa1370fc9fcad7 (diff)
qcacld-2.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: 2143080
-rw-r--r--CORE/SERVICES/WMA/wma.c107
1 files changed, 92 insertions, 15 deletions
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 79ea86c1574d..1cc273552868 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -5532,6 +5532,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."));
@@ -5595,21 +5597,96 @@ static tSirLLStatsResults *__wma_get_ll_stats_ext_buf(uint32_t *len,
* ---------------------------------
*/
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 > (WMA_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 >
+ WMA_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 >
+ (WMA_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 >
+ (WMA_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 >
+ (WMA_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 >
+ (WMA_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 >
+ (WMA_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 > (WMA_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 > WMA_SVC_MSG_MAX_SIZE) {
+ excess_data = true;
+ break;
+ }
+ if (peer_num > WMA_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 > WMA_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);
+ return NULL;
+ }
buf = (tSirLLStatsResults *)vos_mem_malloc(buf_len);
if (buf == NULL) {