Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F146133768
D24980.1779287536.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D24980.1779287536.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D24980: [net80211] Add a hardware work around for corrupted CCMP PNs
Attached
Detach File
Event Timeline
Log In to Comment