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
This commit is contained in:
Vignesh Viswanathan 2017-09-26 15:27:16 +05:30 • committed by snandini
commit 53d69c9b7f

View file

@ -1224,7 +1224,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;
@ -1252,8 +1253,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;
@ -1266,22 +1267,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 ||
@ -1292,22 +1304,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) {