SAE: Process received commit message through a queue

This allows better control of processing new SAE sessions so that other
operations can be given higher priority during bursts of SAE requests,
e.g., during a potential DoS attack. The receive commit messages are
queued (up to maximum of 15 entries) and processed from eloop callback.
If the queue has multiple pending entries, more wait time is used to go
through the each new entry to reduce heavy CPU load from SAE processing.

Enable anti-clogging token use also based on the pending commit message
queue and not only based on the already started sessions.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2019-03-01 19:54:51 +02:00 committed by Jouni Malinen
parent a053ab9590
commit ff9f40aee1
4 changed files with 108 additions and 4 deletions

View File

@ -417,6 +417,20 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
#ifdef CONFIG_SAE
{
struct hostapd_sae_commit_queue *q;
while ((q = dl_list_first(&hapd->sae_commit_queue,
struct hostapd_sae_commit_queue,
list))) {
dl_list_del(&q->list);
os_free(q);
}
}
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
#endif /* CONFIG_SAE */
}
@ -2150,6 +2164,9 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
dl_list_init(&hapd->l2_queue);
dl_list_init(&hapd->l2_oui_queue);
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
dl_list_init(&hapd->sae_commit_queue);
#endif /* CONFIG_SAE */
return hapd;
}

View File

@ -129,6 +129,13 @@ struct hostapd_neighbor_entry {
int stationary;
};
struct hostapd_sae_commit_queue {
struct dl_list list;
int rssi;
size_t len;
u8 msg[];
};
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
@ -308,6 +315,7 @@ struct hostapd_data {
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
int dot11RSNASAERetransPeriod; /* msec */
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS

View File

@ -62,6 +62,9 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue);
u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
@ -518,6 +521,13 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
return 1;
}
/* In addition to already existing open SAE sessions, check whether
* there are enough pending commit messages in the processing queue to
* potentially result in too many open sessions. */
if (open + dl_list_len(&hapd->sae_commit_queue) >=
hapd->conf->sae_anti_clogging_threshold)
return 1;
return 0;
}
@ -1176,6 +1186,62 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
return 0;
}
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct hostapd_sae_commit_queue *q;
unsigned int queue_len;
q = dl_list_first(&hapd->sae_commit_queue,
struct hostapd_sae_commit_queue, list);
if (!q)
return;
wpa_printf(MSG_DEBUG,
"SAE: Process next available commit message from queue");
dl_list_del(&q->list);
handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
q->rssi, 1);
os_free(q);
if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
return;
queue_len = dl_list_len(&hapd->sae_commit_queue);
eloop_register_timeout(0, queue_len * 50000, auth_sae_process_commit,
hapd, NULL);
}
static void auth_sae_queue_commit(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi)
{
struct hostapd_sae_commit_queue *q;
unsigned int queue_len;
queue_len = dl_list_len(&hapd->sae_commit_queue);
if (queue_len >= 15) {
wpa_printf(MSG_DEBUG,
"SAE: No more room in commit message queue - drop the new frame from "
MACSTR, MAC2STR(mgmt->sa));
return;
}
wpa_printf(MSG_DEBUG, "SAE: Queue Authentication commit message from "
MACSTR " for processing", MAC2STR(mgmt->sa));
q = os_zalloc(sizeof(*q) + len);
if (!q)
return;
q->rssi = rssi;
q->len = len;
os_memcpy(q->msg, mgmt, len);
dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
return;
eloop_register_timeout(0, queue_len * 50000, auth_sae_process_commit,
hapd, NULL);
}
#endif /* CONFIG_SAE */
@ -1807,7 +1873,7 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi)
int rssi, int from_queue)
{
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
@ -1854,11 +1920,12 @@ static void handle_auth(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
"auth_transaction=%d status_code=%d wep=%d%s "
"seq_ctrl=0x%x%s",
"seq_ctrl=0x%x%s%s",
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
status_code, !!(fc & WLAN_FC_ISWEP),
challenge ? " challenge" : "",
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
from_queue ? " (from queue)" : "");
#ifdef CONFIG_NO_RC4
if (auth_alg == WLAN_AUTH_SHARED_KEY) {
@ -1986,6 +2053,16 @@ static void handle_auth(struct hostapd_data *hapd,
if (res == HOSTAPD_ACL_PENDING)
return;
#ifdef CONFIG_SAE
if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1 && !from_queue) {
/* Handle SAE Authentication commit message through a queue to
* provide more control for postponing the needed heavy
* processing under a possible DoS attack scenario. */
auth_sae_queue_commit(hapd, mgmt, len, rssi);
return;
}
#endif /* CONFIG_SAE */
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
@ -4245,7 +4322,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
handle_auth(hapd, mgmt, len, ssi_signal);
handle_auth(hapd, mgmt, len, ssi_signal, 0);
ret = 1;
break;
case WLAN_FC_STYPE_ASSOC_REQ:

View File

@ -175,4 +175,6 @@ int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
#endif /* IEEE802_11_H */