Cumulative patch from commit 3302b7c29f42c532c815268bcdcd09e1dbe1840c
3302b7c Rate limit SA Query procedure initiation on unprotected disconnect
4075e2f EAP-GPSK: Clean up CSuite_List length validation (CID 62854)
2dbc959 EAP-FAST: Clean up TLV length validation (CID 62853)
35cbadb VHT: Remove useless validation code from Operating Mode Notification
bed7eb6 TDLS: Do not bail when failing to process IEs in Discovery Request
7e0f4f4 TDLS: Do not reject TPK M3 when failing to process IEs
Change-Id: I85ed050d7fce0ed8eb1959688171236d87264ff4
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 221d9c2..437cf50 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -112,25 +112,11 @@
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper_notif)
{
- u8 channel_width;
-
if (!vht_oper_notif) {
sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
return WLAN_STATUS_SUCCESS;
}
- channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
-
- if (channel_width != VHT_CHANWIDTH_USE_HT &&
- channel_width != VHT_CHANWIDTH_80MHZ &&
- channel_width != VHT_CHANWIDTH_160MHZ &&
- channel_width != VHT_CHANWIDTH_80P80MHZ &&
- ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >>
- VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) {
- sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
-
sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
sta->vht_opmode = *vht_oper_notif;
return WLAN_STATUS_SUCCESS;
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 04b987d..fceb1b0 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -174,7 +174,7 @@
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len)
+ int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
case EAP_TLV_EAP_PAYLOAD_TLV:
diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h
index 8955617..d59a845 100644
--- a/src/eap_common/eap_fast_common.h
+++ b/src/eap_common/eap_fast_common.h
@@ -102,6 +102,6 @@
void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len);
+ int tlv_type, u8 *pos, size_t len);
#endif /* EAP_FAST_H */
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index cc1f264..b3f6a52 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1080,7 +1080,8 @@
struct eap_fast_tlv_parse *tlv,
struct wpabuf **resp)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1094,13 +1095,14 @@
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 5b023c7..3c9cbf4 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -236,6 +236,8 @@
size_t *list_len,
const u8 *pos, const u8 *end)
{
+ size_t len;
+
if (pos == NULL)
return NULL;
@@ -243,23 +245,25 @@
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
return NULL;
}
- *list_len = WPA_GET_BE16(pos);
+ len = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < (int) *list_len) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
return NULL;
}
- if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
+ if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
- (unsigned long) *list_len);
+ (unsigned long) len);
return NULL;
}
- *list = pos;
- pos += *list_len;
- if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
+ if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
return NULL;
+ *list = pos;
+ *list_len = len;
+ pos += len;
+
return pos;
}
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index fcb80dc..44a443a 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -1123,7 +1123,8 @@
static int eap_fast_parse_tlvs(struct wpabuf *data,
struct eap_fast_tlv_parse *tlv)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1136,13 +1137,14 @@
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 59ed2c9..652e52c 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1378,10 +1378,17 @@
dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+ /*
+ * Some APs will tack on a weird IE to the end of a TDLS
+ * discovery request packet. This needn't fail the response,
+ * since the required IE are verified separately.
+ */
if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
len - (sizeof(struct wpa_tdls_frame) + 1),
- &kde) < 0)
- return -1;
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround");
+ }
if (!kde.lnkid) {
wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
@@ -2290,9 +2297,16 @@
pos += 2 /* status code */ + 1 /* dialog token */;
ielen = len - (pos - buf); /* start of IE in buf */
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs piggy-back broken IEs to the end
+ * of a TDLS Confirm packet, which will fail the link if we don't ignore
+ * this error.
+ */
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
- goto error;
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround");
}
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 60da3bf..147836b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1927,6 +1927,7 @@
#ifdef CONFIG_SME
os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
wpa_s->sme.prev_bssid_set = 1;
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
#endif /* CONFIG_SME */
wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 82aef0d..81a1ede 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1344,6 +1344,7 @@
const u8 *da, u16 reason_code)
{
struct wpa_ssid *ssid;
+ struct os_reltime now;
if (wpa_s->wpa_state != WPA_COMPLETED)
return;
@@ -1360,6 +1361,12 @@
if (wpa_s->sme.sa_query_count > 0)
return;
+ os_get_reltime(&now);
+ if (wpa_s->sme.last_unprot_disconnect.sec &&
+ !os_reltime_expired(&now, &wpa_s->sme.last_unprot_disconnect, 10))
+ return; /* limit SA Query procedure frequency */
+ wpa_s->sme.last_unprot_disconnect = now;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
"possible AP/STA state mismatch - trigger SA Query");
sme_start_sa_query(wpa_s);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index c51a703..1cb4e16 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -636,6 +636,7 @@
* sa_query_count octets of pending
* SA Query transaction identifiers */
struct os_reltime sa_query_start;
+ struct os_reltime last_unprot_disconnect;
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;