DF-0594 / fix.diff
diff --git a/sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c b/sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c index 1111111..2222222 100644 --- a/sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c +++ b/sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c @@ -276,6 +276,24 @@ */ wh = mtod(m, struct ieee80211_frame *); ivp = mtod(m, uint8_t *) + hdrlen; + /* + * Reject frames too short to hold the 802.11 header + the cipher's + * IV/EIV header + the ICV trailer. Without this, the length + * arithmetic in tkip_decrypt() underflows: m->m_pkthdr.len (int) minus + * (hdrlen + ic_header + ic_trailer) (u_int) wraps to ~0 and + * wep_decrypt() walks past the mbuf chain (KASSERT panic on INVARIANTS + * kernels, OOB read on production kernels). The upper-layer + * ieee80211_crypto_decap() only enforces the WEP 32-byte floor, which + * is too small for TKIP (needs >= hdrlen + ic_header + ic_trailer). + */ + if (m->m_pkthdr.len < hdrlen + (int)(tkip.ic_header + tkip.ic_trailer)) { + vap->iv_stats.is_rx_tkipformat++; + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, + "TKIP", "frame too short for decrypt: len %d, need %d", + m->m_pkthdr.len, + hdrlen + (int)(tkip.ic_header + tkip.ic_trailer)); + return 0; + } if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) { /* * No extended IV; discard frame. @@ -353,7 +371,23 @@ vap->iv_stats.is_crypto_tkipdemic++; - michael_mic(ctx, k->wk_rxmic, + /* + * Reject frames too short to hold the 802.11 header + the MIC. + * Without this the length arithmetic below underflows: the + * subtraction m->m_pkthdr.len (int) - (hdrlen + ic_miclen) + * (u_int) wraps and michael_mic()/m_copydata() walk past the + * mbuf chain. Reachable in the HW-decrypt + SW-MIC config. + */ + if (m->m_pkthdr.len < hdrlen + (int)tkip.ic_miclen) { + vap->iv_stats.is_rx_tkipformat++; + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_CRYPTO, + wh->i_addr2, "TKIP", + "frame too short for MIC: len %d, need %d", + m->m_pkthdr.len, hdrlen + (int)tkip.ic_miclen); + return 0; + } + + michael_mic(ctx, k->wk_rxmic, m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen), mic); m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen, |