qcacmn: Avoid buffer overflow in roam scan stats extract handler
In extract_roam_scan_stats_res_evt_tlv(), there is potential
buffer-overflow due to no input validation of following event
parameters from firmware:
(a) Roam scan frequencies against maximum value of 50
(WMI_ROAM_SCAN_STATS_CHANNELS_MAX) and
(b) Roam scan candidates against maximum value of 4
(WMI_ROAM_SCAN_STATS_CANDIDATES_MAX)
To fix this, validate roam scan stats event parameters.
Change-Id: I866b492f7ccb48c4960ff25a9e817cbdb394509e
CRs-Fixed: 2335530
diff --git a/wmi_unified_tlv.c b/wmi_unified_tlv.c
index 413ce6a..7d56095 100644
--- a/wmi_unified_tlv.c
+++ b/wmi_unified_tlv.c
@@ -10377,13 +10377,14 @@
num_scans = fixed_param->num_roam_scans;
scan_param_size = sizeof(struct wmi_roam_scan_stats_params);
- if ((num_scans > ((UINT_MAX - sizeof(*res)) / scan_param_size))) {
- wmi_err_rl("Invalid num_roam_scans %d", num_scans);
+ *vdev_id = fixed_param->vdev_id;
+ if (num_scans > WMI_ROAM_SCAN_STATS_MAX) {
+ wmi_err_rl("%u exceeded maximum roam scan stats: %u",
+ num_scans, WMI_ROAM_SCAN_STATS_MAX);
return QDF_STATUS_E_INVAL;
}
total_len = sizeof(*res) + num_scans * scan_param_size;
- *vdev_id = fixed_param->vdev_id;
res = qdf_mem_malloc(total_len);
if (!res) {
@@ -10425,8 +10426,16 @@
uint32_t count, chan_info_sum = 0;
num_channels = param_buf->num_channels;
- for (count = 0; count < param_buf->num_num_channels; count++)
+ for (count = 0; count < param_buf->num_num_channels; count++) {
+ if (param_buf->num_channels[count] >
+ WMI_ROAM_SCAN_STATS_CHANNELS_MAX) {
+ wmi_err_rl("%u exceeded max scan channels %u",
+ param_buf->num_channels[count],
+ WMI_ROAM_SCAN_STATS_CHANNELS_MAX);
+ goto error;
+ }
chan_info_sum += param_buf->num_channels[count];
+ }
if (param_buf->chan_info &&
param_buf->num_chan_info == chan_info_sum)
@@ -10435,12 +10444,19 @@
if (param_buf->num_roam_candidates &&
param_buf->num_num_roam_candidates == num_scans) {
- uint32_t count, roam_cand_sum = 0;
+ uint32_t cnt, roam_cand_sum = 0;
num_roam_candidates = param_buf->num_roam_candidates;
- for (count = 0; count < param_buf->num_num_roam_candidates;
- count++)
- roam_cand_sum += param_buf->num_roam_candidates[count];
+ for (cnt = 0; cnt < param_buf->num_num_roam_candidates; cnt++) {
+ if (param_buf->num_roam_candidates[cnt] >
+ WMI_ROAM_SCAN_STATS_CANDIDATES_MAX) {
+ wmi_err_rl("%u exceeded max scan cand %u",
+ param_buf->num_roam_candidates[cnt],
+ WMI_ROAM_SCAN_STATS_CANDIDATES_MAX);
+ goto error;
+ }
+ roam_cand_sum += param_buf->num_roam_candidates[cnt];
+ }
if (param_buf->bssid &&
param_buf->num_bssid == roam_cand_sum)
@@ -10520,6 +10536,9 @@
*res_param = res;
return QDF_STATUS_SUCCESS;
+error:
+ qdf_mem_free(res);
+ return QDF_STATUS_E_FAILURE;
}
/**