From 0acc2c809d86e4c7b18baca35bed5717e4d50208 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 22 Dec 2014 21:54:11 +0200 Subject: [PATCH] HT: More robust 20/40 coex Action frame parsing Commit 587d60d2b74190d58ddeb6a30ab338352af1186a ('Add AP mode support for HT 20/40 co-ex Action frame') added processing of co-ex report, but did not include proper bounds checking or IE type checking for the payload. Furthermore, this was not ready for the possible extensibility of the 20/40 BSS Coexistence element. Fix these by checking IE ids for both elements and doing more apprioriate bounds checking for the element lengths to avoid potentially reading beyond the frame buffer. Though, the event receive buffer in both libnl and driver_nl80211_monitor.c is sufficiently large to make it very unlikely that the maximum read of about 260 bytes beyond the end of the Action frame would really have any chances of hitting the end of the memory buffer, so the practical effect of missing bounds checking would have been possibly accepting an invalid report frame and moving to 20 MHz channel unnecessarily. Signed-off-by: Jouni Malinen --- src/ap/ieee802_11_ht.c | 48 +++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index f54942178..3f299f3ee 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -211,7 +211,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, struct ieee80211_2040_intol_chan_report *ic_report; int is_ht_allowed = 1; int i; - const u8 *data = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; + const u8 *start = (const u8 *) mgmt; + const u8 *data = start + IEEE80211_HDRLEN + 2; hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d", @@ -220,14 +221,22 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) return; - if (len < IEEE80211_HDRLEN + 1) + if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) return; - data++; - bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0]; - ic_report = (struct ieee80211_2040_intol_chan_report *) - (&data[0] + sizeof(*bc_ie)); + bc_ie = (struct ieee80211_2040_bss_coex_ie *) data; + if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE || + bc_ie->length < 1) { + wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report", + bc_ie->element_id, bc_ie->length); + return; + } + if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) + return; + data += 2 + bc_ie->length; + wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x", + bc_ie->coex_param); if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -244,22 +253,34 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, is_ht_allowed = 0; } - if (ic_report && - (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) { + if (start + len - data >= 3 && + data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) { + u8 ielen = data[1]; + + if (ielen > start + len - data - 2) + return; + ic_report = (struct ieee80211_2040_intol_chan_report *) data; + wpa_printf(MSG_DEBUG, + "20/40 BSS Intolerant Channel Report: Operating Class %u", + ic_report->op_class); + /* Go through the channel report to find any BSS there in the * affected channel range */ - for (i = 0; i < ic_report->length - 1; i++) { - if (is_40_allowed(iface, ic_report->variable[i])) + for (i = 0; i < ielen - 1; i++) { + u8 chan = ic_report->variable[i]; + + if (is_40_allowed(iface, chan)) continue; hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "20_40_INTOLERANT channel %d reported", - ic_report->variable[i]); + chan); is_ht_allowed = 0; - break; } } + wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d", + is_ht_allowed, iface->num_sta_ht40_intolerant); if (!is_ht_allowed && (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { @@ -279,6 +300,9 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, NULL); eloop_register_timeout(delay_time, 0, ap_ht2040_timeout, hapd->iface, NULL); + wpa_printf(MSG_DEBUG, + "Reschedule HT 20/40 timeout to occur in %u seconds", + delay_time); } } }