diff options
author | sam <sam@FreeBSD.org> | 2008-08-29 05:02:10 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2008-08-29 05:02:10 +0000 |
commit | e920342cd46a6e2b57b701fa655a92aa3159605e (patch) | |
tree | 7ef0bd12ae3bcd01e5d30b34292ae8dcc3623118 /sys/net80211 | |
parent | 743ae14c809633e69d2ef724ef9ec1d47c62f73f (diff) | |
download | FreeBSD-src-e920342cd46a6e2b57b701fa655a92aa3159605e.zip FreeBSD-src-e920342cd46a6e2b57b701fa655a92aa3159605e.tar.gz |
Fix mic calculation when final data is entirely in a trailing mbuf;
it's unclear if this can happen on freebsd but does appear on netbsd.
Identified by Matthias Drochner who came up with an initial change
that we then revised together.
Reviewed by: thompsa, sephe, avatar
MFC after: 2 weeks
Diffstat (limited to 'sys/net80211')
-rw-r--r-- | sys/net80211/ieee80211_crypto_tkip.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/sys/net80211/ieee80211_crypto_tkip.c b/sys/net80211/ieee80211_crypto_tkip.c index 0e6bc78..fc963ca 100644 --- a/sys/net80211/ieee80211_crypto_tkip.c +++ b/sys/net80211/ieee80211_crypto_tkip.c @@ -831,7 +831,17 @@ michael_mic(struct tkip_ctx *ctx, const u8 *key, data += sizeof(uint32_t), space -= sizeof(uint32_t); data_len -= sizeof(uint32_t); } - if (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 == 0 || + (data_len < sizeof(uint32_t) && space != 0)) break; m = m->m_next; if (m == NULL) { @@ -878,6 +888,14 @@ michael_mic(struct tkip_ctx *ctx, const u8 *key, 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, + ("not enough data, data_len %u space %u\n", data_len, space)); + /* Last block and padding (0x5a, 4..7 x 0) */ switch (data_len) { case 0: |