Module Name:    src
Committed By:   drochner
Date:           Sun Apr  3 10:04:32 UTC 2011

Modified Files:
        src/sys/net80211: ieee80211_crypto_tkip.c

Log Message:
make michael_mic() robust against degenerate mbuf layouts like
odd sizes in the middle of a chain


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/net80211/ieee80211_crypto_tkip.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net80211/ieee80211_crypto_tkip.c
diff -u src/sys/net80211/ieee80211_crypto_tkip.c:1.10 src/sys/net80211/ieee80211_crypto_tkip.c:1.11
--- src/sys/net80211/ieee80211_crypto_tkip.c:1.10	Wed Dec 17 20:51:37 2008
+++ src/sys/net80211/ieee80211_crypto_tkip.c	Sun Apr  3 10:04:32 2011
@@ -34,7 +34,7 @@
 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_tkip.c,v 1.10 2005/08/08 18:46:35 sam Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_tkip.c,v 1.10 2008/12/17 20:51:37 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_tkip.c,v 1.11 2011/04/03 10:04:32 drochner Exp $");
 #endif
 
 /*
@@ -802,6 +802,8 @@
 	u32 l, r;
 	const uint8_t *data;
 	u_int space;
+	uint8_t spill[4];
+	int nspill = 0;
 
 	michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
 
@@ -824,6 +826,20 @@
 	for (;;) {
 		if (space > data_len)
 			space = data_len;
+		if (nspill) {
+			int n = min(4 - nspill, space);
+			memcpy(spill + nspill, data, n);
+			nspill += n;
+			data += n;
+			space -= n;
+			data_len -= n;
+			if (nspill == 4) {
+				l ^= get_le32(spill);
+				michael_block(l, r);
+				nspill = 0;
+			} else
+				goto next;
+		}
 		/* collect 32-bit blocks from current buffer */
 		while (space >= sizeof(uint32_t)) {
 			l ^= get_le32(data);
@@ -832,84 +848,27 @@
 			space -= sizeof(uint32_t);
 			data_len -= sizeof(uint32_t);
 		}
-		/*
-		 * NB: when space is zero we make one more trip around
-		 * the loop to advance to the next mbuf where there is
-		 * data.  This handles the case where there are 4*n
-		 * bytes in an mbuf followed by <4 bytes in a later mbuf.
-		 * By making an extra trip we'll drop out of the loop
-		 * with m pointing at the mbuf with 3 bytes and space
-		 * set as required by the remainder handling below.
-		 */
-		if (!data_len || (data_len < sizeof(uint32_t) && space != 0))
+		if (space) {
+			memcpy(spill, data, space);
+			nspill = space;
+			data_len -= space;
+		}
+next:
+		if (!data_len)
 			break;
 		m = m->m_next;
-		if (m == NULL) {
-			IASSERT(0, ("out of data, data_len %zu\n", data_len));
-			break;
-		}
-		if (space != 0) {
-			const uint8_t *data_next;
-			/*
-			 * Block straddles buffers, split references.
-			 */
-			data_next = mtod(m, const uint8_t *);
-			IASSERT(m->m_len >= sizeof(uint32_t) - space,
-				("not enough data in following buffer, "
-				"m_len %u need %zu\n", m->m_len,
-				sizeof(uint32_t) - space));
-			switch (space) {
-			case 1:
-				l ^= get_le32_split(data[0], data_next[0],
-					data_next[1], data_next[2]);
-				data = data_next + 3;
-				space = m->m_len - 3;
-				break;
-			case 2:
-				l ^= get_le32_split(data[0], data[1],
-					data_next[0], data_next[1]);
-				data = data_next + 2;
-				space = m->m_len - 2;
-				break;
-			case 3:
-				l ^= get_le32_split(data[0], data[1],
-					data[2], data_next[0]);
-				data = data_next + 1;
-				space = m->m_len - 1;
-				break;
-			}
-			michael_block(l, r);
-			data_len -= sizeof(uint32_t);
-		} else {
-			/*
-			 * Setup for next buffer.
-			 */
-			data = mtod(m, const uint8_t *);
-			space = m->m_len;
-		}
+		KASSERT(m);
+		/*
+		 * Setup for next buffer.
+		 */
+		data = mtod(m, const uint8_t *);
+		space = m->m_len;
 	}
-	/*
-	 * Catch degenerate cases like mbuf[4*n+1 bytes] followed by
-	 * mbuf[2 bytes].  I don't believe these should happen; if they
-	 * do then we'll need more involved logic.
-	 */
-	KASSERT(data_len <= space);
-
 	/* Last block and padding (0x5a, 4..7 x 0) */
-	switch (data_len) {
-	case 0:
-		l ^= get_le32_split(0x5a, 0, 0, 0);
-		break;
-	case 1:
-		l ^= get_le32_split(data[0], 0x5a, 0, 0);
-		break;
-	case 2:
-		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
-		break;
-	case 3:
-		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
-		break;
-	}
+	spill[nspill++] = 0x5a;
+	for (; nspill < 4; nspill++)
+		spill[nspill] = 0;
+	l ^= get_le32(spill);
 	michael_block(l, r);
 	/* l ^= 0; */
 	michael_block(l, r);

Reply via email to