Call if_start() directly to send the EAPOL key.
authormpi <mpi@openbsd.org>
Thu, 21 Dec 2017 12:09:38 +0000 (12:09 +0000)
committermpi <mpi@openbsd.org>
Thu, 21 Dec 2017 12:09:38 +0000 (12:09 +0000)
Using if_enqueue() here, from interrupt context, might result in
the packet beeing enqueued, incorrectly encrypted, on the TX ring.

This race has been recently exposed by the re-introduction of the
TX mitigation.  It exists because the net80211 stack sets
IEEE80211_NODE_TXPROT on the node while processing the 3rd message,
assuming the answer has already been transmitted.  However a CPU
returns from if_enqueue() it cannot assume that the send queue is
empty.  So call if_start() to flush this queue.

Encrypting the 4th message of the 4way handshake with the new key
breaks WPA handshake as found the hardway by anton@.

Race analysed by dlg@, a lot of net80211 inputs and suggetions from
stsp@.

ok stsp@, dlg@

sys/net80211/ieee80211_pae_output.c

index d385b00..51d0fa4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_pae_output.c,v 1.29 2017/03/01 19:28:48 stsp Exp $  */
+/*     $OpenBSD: ieee80211_pae_output.c,v 1.30 2017/12/21 12:09:38 mpi Exp $   */
 
 /*-
  * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
@@ -66,7 +66,7 @@ ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
        struct ether_header *eh;
        struct ieee80211_eapol_key *key;
        u_int16_t info;
-       int len;
+       int len, error;
 
        M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
        if (m == NULL)
@@ -123,7 +123,12 @@ ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
        if (info & EAPOL_KEY_KEYACK)
                timeout_add_msec(&ni->ni_eapol_to, 100);
 #endif
-       return if_enqueue(ifp, m);
+
+       IFQ_ENQUEUE(&ifp->if_snd, m, error);
+       if (error)
+               return (error);
+       if_start(ifp);
+       return 0;
 }
 
 #ifndef IEEE80211_STA_ONLY