summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVignesh Viswanathan <viswanat@codeaurora.org>2017-09-26 15:21:07 +0530
committersnandini <snandini@codeaurora.org>2017-10-04 15:30:38 -0700
commit1ebe1be210dbcd23782cd9a0c3bf2ba55fcef5b0 (patch)
treee534f954dce3012af6a6dda07210f1965ab00a4d
parenteea5836e0b4be0d3c42d4c32389f08f85332a80b (diff)
qcacld-3.0: Fix integer overflow in wma_unified_link_peer_stats_event_handler
Currently in wma_unified_link_peer_stats_event_handler, the check to validate if peer_stats->num_rates is less than WMA_SVC_MSG_MAX_SIZE is done only for the first member of the peer_stats array. This can lead to integer overflow as num_rates is calculated as sum of peer_stats->num_rates for each of the peer_stats in the array. Add code changes to loop and calculate total_num_rates for all the peer_stats and then validate total_num_rates with WMA_SVC_MSG_MAX_SIZE. Change-Id: Ic934934a990bd55fce70a0eaffa2812bc34b0ddd CRs-Fixed: 2113758
-rw-r--r--core/wma/src/wma_utils.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index eb8130485755..80d02685cabc 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -1250,7 +1250,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
wmi_rate_stats *rate_stats;
tSirLLStatsResults *link_stats_results;
uint8_t *results, *t_peer_stats, *t_rate_stats;
- uint32_t count, num_rates = 0, rate_cnt;
+ uint32_t count, rate_cnt;
+ uint32_t total_num_rates = 0;
uint32_t next_res_offset, next_peer_offset, next_rate_offset;
size_t peer_info_size, peer_stats_size, rate_stats_size;
size_t link_stats_results_size;
@@ -1278,8 +1279,8 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
* cmd_param_info contains
* wmi_peer_stats_event_fixed_param fixed_param;
* num_peers * size of(struct wmi_peer_link_stats)
- * num_rates * size of(struct wmi_rate_stats)
- * num_rates is the sum of the rates of all the peers.
+ * total_num_rates * size of(struct wmi_rate_stats)
+ * total_num_rates is the sum of the rates of all the peers.
*/
fixed_param = param_tlvs->fixed_param;
peer_stats = param_tlvs->peer_stats;
@@ -1292,22 +1293,33 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
}
do {
- if (peer_stats->num_rates >
- WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_rate_stats)) {
- excess_data = true;
- break;
- } else {
- buf_len =
- peer_stats->num_rates * sizeof(wmi_rate_stats);
- }
if (fixed_param->num_peers >
WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) {
excess_data = true;
break;
} else {
- buf_len += fixed_param->num_peers *
+ buf_len = fixed_param->num_peers *
sizeof(wmi_peer_link_stats);
}
+ temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
+ for (count = 0; count < fixed_param->num_peers; count++) {
+ if (temp_peer_stats->num_rates >
+ WMI_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) {
+ excess_data = true;
+ break;
+ } else {
+ total_num_rates += temp_peer_stats->num_rates;
+ if (total_num_rates >
+ WMI_SVC_MSG_MAX_SIZE /
+ sizeof(wmi_rate_stats)) {
+ excess_data = true;
+ break;
+ }
+ buf_len += temp_peer_stats->num_rates *
+ sizeof(wmi_rate_stats);
+ }
+ temp_peer_stats++;
+ }
} while (0);
if (excess_data ||
@@ -1318,22 +1330,13 @@ static int wma_unified_link_peer_stats_event_handler(void *handle,
return -EINVAL;
}
- /*
- * num_rates - sum of the rates of all the peers
- */
- temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
- for (count = 0; count < fixed_param->num_peers; count++) {
- num_rates += temp_peer_stats->num_rates;
- temp_peer_stats++;
- }
-
peer_stats_size = sizeof(tSirWifiPeerStat);
peer_info_size = sizeof(tSirWifiPeerInfo);
rate_stats_size = sizeof(tSirWifiRateStat);
link_stats_results_size =
sizeof(*link_stats_results) + peer_stats_size +
(fixed_param->num_peers * peer_info_size) +
- (num_rates * rate_stats_size);
+ (total_num_rates * rate_stats_size);
link_stats_results = qdf_mem_malloc(link_stats_results_size);
if (NULL == link_stats_results) {