Page MenuHomeFreeBSD

D24980.1779287536.diff
No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None

D24980.1779287536.diff

Index: sys/net80211/ieee80211_crypto.h
===================================================================
--- sys/net80211/ieee80211_crypto.h
+++ sys/net80211/ieee80211_crypto.h
@@ -101,6 +101,8 @@
#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */
/* key receive sequence counter */
uint64_t wk_keyrsc[IEEE80211_TID_SIZE];
+ /* Suspect key receive seq counter */
+ uint64_t wk_suspect_keyrsc[IEEE80211_TID_SIZE];
uint64_t wk_keytsc; /* key transmit sequence counter */
const struct ieee80211_cipher *wk_cipher;
void *wk_private; /* private cipher state */
Index: sys/net80211/ieee80211_crypto_ccmp.c
===================================================================
--- sys/net80211/ieee80211_crypto_ccmp.c
+++ sys/net80211/ieee80211_crypto_ccmp.c
@@ -240,6 +240,8 @@
struct ieee80211_frame *wh;
uint8_t *ivp, tid;
uint64_t pn;
+ int do_update = 1;
+ int do_replay = 0;
rxs = ieee80211_get_rx_params_ptr(m);
@@ -263,10 +265,147 @@
}
tid = ieee80211_gettid(wh);
pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
- if (pn <= k->wk_keyrsc[tid] &&
+
+ /*
+ * Handle a chipset specific bug in some (all?) Atheros chips
+ * doing hardware CCMP decryption - the PN gets corrupted in a frame.
+ *
+ * It looks like a /huge/ jump in the PN as some high bits in the
+ * IV get flipped to 1 somehow. The next decrypted frame is likely
+ * fine with the old PN but all subsequent frames are ignored.
+ */
+
+ /*
+ * First part - is this a potentially garbage high PN.
+ * This could be a garbage PN, it could be a valid PN
+ * with a bunch of missing frames in the PN space after
+ * a garbage PN. So, we handle all of those cases below.
+ */
+
+ if (k->wk_suspect_keyrsc[tid] != 0) {
+ /* Handle replay with the same suspect PN; tsk */
+ if (pn == k->wk_suspect_keyrsc[tid]) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+ wh->i_addr2,
+ "Suspect PN equal/replay; tid=%d, "
+ "pn=0x%jx, rsc=0x%jx, suspect_rsc=0x%jx",
+ tid, (uintmax_t) pn,
+ (uintmax_t) k->wk_keyrsc[tid],
+ (uintmax_t) k->wk_suspect_keyrsc[tid]);
+ do_replay = 1;
+ do_update = 0;
+ }
+
+ /*
+ * Handle it being bigger than the suspected PN.
+ * It's quite possible we'll get a SECOND invalid
+ * frame after the first, and if that's the case
+ * this logic will need adjusting.
+ */
+ else if (pn > k->wk_suspect_keyrsc[tid]) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+ wh->i_addr2,
+ "Suspect PN not a suspect; tid=%d, "
+ "pn=0x%jx, rsc=0x%jx, suspect_rsc=0x%jx",
+ tid, (uintmax_t) pn,
+ (uintmax_t) k->wk_keyrsc[tid],
+ (uintmax_t) k->wk_suspect_keyrsc[tid]);
+ /*
+ * This isn't technically needed, but let's
+ * just be explicit here - if it passes
+ * the rest of the checks then we'll
+ * update the rsc and clear the suspect
+ * rsc counter.
+ */
+ do_update = 1;
+ }
+
+ /*
+ * It's smaller than the suspect rsc but bigger
+ * than the rsc. We're back to normal.
+ */
+ else if (pn > k->wk_keyrsc[tid]) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+ wh->i_addr2,
+ "Suspect PN; back to normal; tid=%d, "
+ "pn=0x%jx, rsc=0x%jx, suspect_rsc=0x%jx",
+ tid, (uintmax_t) pn,
+ (uintmax_t) k->wk_keyrsc[tid],
+ (uintmax_t) k->wk_suspect_keyrsc[tid]);
+ do_update = 1;
+ } else {
+ /*
+ * pn is less or equal to the suspect rsc,
+ * but greater than the last seen rsc.
+ * We don't know whether this is another
+ * corrupted frame with a lower bit corrupted,
+ * or a replay attack.
+ *
+ * Mark it as a replay attack and clear
+ * ths suspect PN. This may result in some
+ * incorrectly dropped frames but that's
+ * better than mucking up the valid-y looking
+ * RSC and potentially leaving a replay attack
+ * vector open.
+ */
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+ wh->i_addr2,
+ "Suspect PN is a replay attack; tid=%d, "
+ "pn=0x%jx, rsc=0x%jx, suspect_rsc=0x%jx",
+ tid, (uintmax_t) pn,
+ (uintmax_t) k->wk_keyrsc[tid],
+ (uintmax_t) k->wk_suspect_keyrsc[tid]);
+ k->wk_suspect_keyrsc[tid] = 0;
+ do_update = 0;
+ do_replay = 1;
+ }
+ }
+
+ /*
+ * Next, check if we have a garbage looking PN and we need to
+ * set the suspect PN track.
+ */
+ else if ((k->wk_keyrsc[tid] > 1) && (pn > (k->wk_keyrsc[tid] + 32))) {
+ /*
+ * This is a suspected invalid PN. This may be because
+ * of a hole in the sender side (eg multicast frame
+ * or non-aggregate frames with holes in their transmit
+ * sequence counters - typically the latter is net80211
+ * style stacks with sequence numbers assigned BEFORE
+ * actual transmit!).
+ *
+ * Track it in the per-key suspected key array.
+ * Then let it through, but don't update the rsc yet.
+ * If the next frame seen resumes the normal sequence
+ * count then we'll use it; else we'll use this suspect one.
+ */
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+ wh->i_addr2, "Suspect PN; tid=%d, pn=0x%jx, rsc=0x%jx",
+ tid, (uintmax_t) pn, (uintmax_t) k->wk_keyrsc[tid]);
+ k->wk_suspect_keyrsc[tid] = pn;
+ /* XXX TODO: statistics, etc */
+ do_update = 0;
+ }
+
+ /*
+ * Check if the PN is invalid / replay attack.
+ *
+ * Note that if we have a suspect rsc here then the checks
+ * are being done above; this would have to be ALSO before
+ * the last non-suspect rsc to trigger it here!
+ */
+ if (pn <= k->wk_keyrsc[tid]) {
+ do_replay = 1;
+ }
+
+ if ((do_replay == 1) &&
(k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
/*
* Replay violation.
+ *
+ * Yes, this also will ignore suspect PNs if we see
+ * them being invalid as whomever asked for
+ * IEEE80211_KEY_NOREPLAY asked for everything..
*/
ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
vap->iv_stats.is_rx_ccmpreplay++;
@@ -303,8 +442,13 @@
/*
* Ok to update rsc now.
*/
- if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) {
+ if ((do_update == 1) &&
+ (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP)))) {
+ /*
+ * Update rsc and override suspect rsc tracking.
+ */
k->wk_keyrsc[tid] = pn;
+ k->wk_suspect_keyrsc[tid] = 0;
}
return 1;
Index: sys/net80211/ieee80211_freebsd.c
===================================================================
--- sys/net80211/ieee80211_freebsd.c
+++ sys/net80211/ieee80211_freebsd.c
@@ -789,8 +789,11 @@
struct ifnet *ifp = vap->iv_ifp;
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
- "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
- k->wk_cipher->ic_name, tid, (intmax_t) rsc,
+ "%s replay detected tid %d <rsc %ju (%jx), csc %ju (%jx), keyix %u rxkeyix %u>",
+ k->wk_cipher->ic_name, tid,
+ (intmax_t) rsc,
+ (intmax_t) rsc,
+ (intmax_t) k->wk_keyrsc[tid],
(intmax_t) k->wk_keyrsc[tid],
k->wk_keyix, k->wk_rxkeyix);

File Metadata

Mime Type
text/plain
Expires
Wed, May 20, 2:32 PM (2 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28754467
Default Alt Text
D24980.1779287536.diff (6 KB)

Event Timeline