mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-17 18:34:03 -05:00
AP: Drop retransmitted auth/assoc/action frames
It is possible that a station device might miss an ACK for an authentication, association, or action frame, and thus retransmit the same frame although the frame is already being processed in the stack. While the duplicated frame should really be dropped in the kernel or firmware code where duplicate detection is implemented for data frames, it is possible that pre-association cases are not fully addressed (which is the case at least with mac80211 today) and the frame may be delivered to upper layer stack. In such a case, the local AP will process the retransmitted frame although it has already handled the request, which might cause the station to get confused and as a result disconnect from the AP, blacklist it, etc. To avoid such a case, save the sequence control of the last processed management frame and in case of retransmissions drop them. Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
parent
453553698c
commit
38cb0a2db6
@ -709,6 +709,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
size_t resp_ies_len = 0;
|
||||
char *identity = NULL;
|
||||
char *radius_cui = NULL;
|
||||
u16 seq_ctrl;
|
||||
|
||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
|
||||
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
|
||||
@ -730,6 +731,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
||||
status_code = le_to_host16(mgmt->u.auth.status_code);
|
||||
fc = le_to_host16(mgmt->frame_control);
|
||||
seq_ctrl = le_to_host16(mgmt->seq_ctrl);
|
||||
|
||||
if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
|
||||
2 + WLAN_AUTH_CHALLENGE_LEN &&
|
||||
@ -738,10 +740,12 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
challenge = &mgmt->u.auth.variable[2];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
|
||||
"auth_transaction=%d status_code=%d wep=%d%s",
|
||||
"auth_transaction=%d status_code=%d wep=%d%s "
|
||||
"seq_ctrl=0x%x%s",
|
||||
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
|
||||
status_code, !!(fc & WLAN_FC_ISWEP),
|
||||
challenge ? " challenge" : "");
|
||||
challenge ? " challenge" : "",
|
||||
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
|
||||
|
||||
if (hapd->tkip_countermeasures) {
|
||||
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
|
||||
@ -802,21 +806,36 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (sta) {
|
||||
if ((fc & WLAN_FC_RETRY) &&
|
||||
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
|
||||
sta->last_seq_ctrl == seq_ctrl &&
|
||||
sta->last_subtype == WLAN_FC_STYPE_AUTH) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Drop repeated authentication frame seq_ctrl=0x%x",
|
||||
seq_ctrl);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->conf->mesh & MESH_ENABLED) {
|
||||
/* if the mesh peer is not available, we don't do auth. */
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (!sta)
|
||||
/* if the mesh peer is not available, we don't do auth.
|
||||
*/
|
||||
return;
|
||||
} else
|
||||
}
|
||||
#endif /* CONFIG_MESH */
|
||||
{
|
||||
|
||||
sta = ap_sta_add(hapd, mgmt->sa);
|
||||
if (!sta) {
|
||||
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
sta->last_seq_ctrl = seq_ctrl;
|
||||
sta->last_subtype = WLAN_FC_STYPE_AUTH;
|
||||
|
||||
if (vlan_id > 0) {
|
||||
if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
|
||||
@ -1464,7 +1483,7 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||
int reassoc)
|
||||
{
|
||||
u16 capab_info, listen_interval;
|
||||
u16 capab_info, listen_interval, seq_ctrl, fc;
|
||||
u16 resp = WLAN_STATUS_SUCCESS;
|
||||
const u8 *pos;
|
||||
int left, i;
|
||||
@ -1497,15 +1516,19 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
fc = le_to_host16(mgmt->frame_control);
|
||||
seq_ctrl = le_to_host16(mgmt->seq_ctrl);
|
||||
|
||||
if (reassoc) {
|
||||
capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
|
||||
listen_interval = le_to_host16(
|
||||
mgmt->u.reassoc_req.listen_interval);
|
||||
wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
|
||||
" capab_info=0x%02x listen_interval=%d current_ap="
|
||||
MACSTR,
|
||||
MACSTR " seq_ctrl=0x%x%s",
|
||||
MAC2STR(mgmt->sa), capab_info, listen_interval,
|
||||
MAC2STR(mgmt->u.reassoc_req.current_ap));
|
||||
MAC2STR(mgmt->u.reassoc_req.current_ap),
|
||||
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
|
||||
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
|
||||
pos = mgmt->u.reassoc_req.variable;
|
||||
} else {
|
||||
@ -1513,8 +1536,10 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
listen_interval = le_to_host16(
|
||||
mgmt->u.assoc_req.listen_interval);
|
||||
wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
|
||||
" capab_info=0x%02x listen_interval=%d",
|
||||
MAC2STR(mgmt->sa), capab_info, listen_interval);
|
||||
" capab_info=0x%02x listen_interval=%d "
|
||||
"seq_ctrl=0x%x%s",
|
||||
MAC2STR(mgmt->sa), capab_info, listen_interval,
|
||||
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
|
||||
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
|
||||
pos = mgmt->u.assoc_req.variable;
|
||||
}
|
||||
@ -1540,6 +1565,21 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
if ((fc & WLAN_FC_RETRY) &&
|
||||
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
|
||||
sta->last_seq_ctrl == seq_ctrl &&
|
||||
sta->last_subtype == reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
|
||||
WLAN_FC_STYPE_ASSOC_REQ) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Drop repeated association frame seq_ctrl=0x%x",
|
||||
seq_ctrl);
|
||||
return;
|
||||
}
|
||||
sta->last_seq_ctrl = seq_ctrl;
|
||||
sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
|
||||
WLAN_FC_STYPE_ASSOC_REQ;
|
||||
|
||||
if (hapd->tkip_countermeasures) {
|
||||
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
|
||||
goto fail;
|
||||
@ -1665,6 +1705,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
@ -1716,6 +1757,7 @@ static void handle_deauth(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
||||
WLAN_STA_ASSOC_REQ_OK);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
|
||||
@ -1815,6 +1857,26 @@ static int handle_action(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
if (sta) {
|
||||
u16 fc = le_to_host16(mgmt->frame_control);
|
||||
u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
|
||||
|
||||
if ((fc & WLAN_FC_RETRY) &&
|
||||
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
|
||||
sta->last_seq_ctrl == seq_ctrl &&
|
||||
sta->last_subtype == WLAN_FC_STYPE_ACTION) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Drop repeated action frame seq_ctrl=0x%x",
|
||||
seq_ctrl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sta->last_seq_ctrl = seq_ctrl;
|
||||
sta->last_subtype = WLAN_FC_STYPE_ACTION;
|
||||
}
|
||||
|
||||
switch (mgmt->u.action.category) {
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
case WLAN_ACTION_FT:
|
||||
|
@ -604,6 +604,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
ap_sta_hash_add(hapd, sta);
|
||||
sta->ssid = &hapd->conf->ssid;
|
||||
ap_sta_remove_in_other_bss(hapd, sta);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
|
||||
return sta;
|
||||
}
|
||||
@ -668,6 +669,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
@ -706,6 +708,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
|
@ -158,6 +158,12 @@ struct sta_info {
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
u32 session_timeout; /* valid only if session_timeout_set == 1 */
|
||||
|
||||
/* Last Authentication/(Re)Association Request/Action frame sequence
|
||||
* control */
|
||||
u16 last_seq_ctrl;
|
||||
/* Last Authentication/(Re)Association Request/Action frame subtype */
|
||||
u8 last_subtype;
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
|
||||
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
|
||||
|
||||
#define WLAN_INVALID_MGMT_SEQ 0xFFFF
|
||||
|
||||
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
|
||||
#define WLAN_GET_SEQ_SEQ(seq) \
|
||||
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
|
||||
|
Loading…
Reference in New Issue
Block a user