Page MenuHomeFreeBSD

D45619.diff
No OneTemporary

D45619.diff

diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -271,8 +271,14 @@
* Otherwise a unicast/pairwise key is specified by the bssid
* (on a station) or mac address (on an ap). They key length
* must include any MIC key data; otherwise it should be no
- * more than IEEE80211_KEYBUF_SIZE.
+ * more than IEEE80211_IOCTL_KEYBUF_SIZE.
*/
+#define IEEE80211_IOCTL_KEYBUF_SIZE (16) /* 128 bit keys */
+#define IEEE80211_IOCTL_MICBUF_SIZE (8+8) /* TX + RX MIC */
+
+#define IEEE80211_IOCTL_KEYDATA_SIZE \
+ (IEEE80211_IOCTL_KEYBUF_SIZE + IEEE80211_IOCTL_MICBUF_SIZE)
+
struct ieee80211req_key {
uint8_t ik_type; /* key/cipher type */
uint8_t ik_pad;
@@ -284,7 +290,7 @@
uint8_t ik_macaddr[IEEE80211_ADDR_LEN];
uint64_t ik_keyrsc; /* key receive sequence counter */
uint64_t ik_keytsc; /* key transmit sequence counter */
- uint8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
+ uint8_t ik_keydata[IEEE80211_IOCTL_KEYDATA_SIZE];
};
/*
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -110,11 +110,18 @@
ik.ik_keyrsc = wk->wk_keyrsc[IEEE80211_NONQOS_TID];
ik.ik_keytsc = wk->wk_keytsc;
memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
+
+ /*
+ * Treat the ioctl as a fixed-size key buffer for now
+ * and use the ioctl sizes. This will return truncated
+ * keys the net80211 key is larger, but it won't leak data,
+ * go out of bounds or change the ioctl ABI.
+ */
if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
memcpy(ik.ik_keydata+wk->wk_keylen,
- wk->wk_key + IEEE80211_KEYBUF_SIZE,
- IEEE80211_MICBUF_SIZE);
- ik.ik_keylen += IEEE80211_MICBUF_SIZE;
+ wk->wk_key + IEEE80211_IOCTL_KEYBUF_SIZE,
+ IEEE80211_IOCTL_MICBUF_SIZE);
+ ik.ik_keylen += IEEE80211_IOCTL_MICBUF_SIZE;
}
} else {
ik.ik_keyrsc = 0;
@@ -1177,6 +1184,7 @@
struct ieee80211_key *wk;
uint16_t kid;
int error, i;
+ int max_keylen;
if (ireq->i_len != sizeof(ik))
return EINVAL;
@@ -1217,17 +1225,40 @@
wk->wk_keyix = kid;
ni = NULL;
}
+
+ max_keylen = ieee80211_crypto_get_max_keylen(ik.ik_type);
+ if (max_keylen == 0)
+ return EINVAL;
+
error = 0;
ieee80211_key_update_begin(vap);
if (ieee80211_crypto_newkey(vap, ik.ik_type, ik.ik_flags, wk)) {
wk->wk_keylen = ik.ik_keylen;
- /* NB: MIC presence is implied by cipher type */
- if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
- wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
+
+ /*
+ * Cap the key length at the cipher key length.
+ *
+ * This captures the TKIP case where we're passed in both
+ * a key and the TX/RX MIC; the ioctl API unfortunately
+ * doesn't separate them out. (And in fairness, neither
+ * does the net80211 crypto code.)
+ */
+ if (wk->wk_keylen > max_keylen)
+ wk->wk_keylen = max_keylen;
+
for (i = 0; i < IEEE80211_TID_SIZE; i++)
wk->wk_keyrsc[i] = ik.ik_keyrsc;
wk->wk_keytsc = 0; /* new key, reset */
memset(wk->wk_key, 0, sizeof(wk->wk_key));
+ /*
+ * Copy the key and any tx/rx MIC that is present.
+ *
+ * For TKIP w/ MIC the ik_keylen being passed in
+ * includes tx/rx MIC and this memcpy() copies everything
+ * including the tx/rx MIC blob that may be at the
+ * end of the key. However, wk->wk_keylen needs to be
+ * the actual key length.
+ */
memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
IEEE80211_ADDR_COPY(wk->wk_macaddr,
ni != NULL ? ni->ni_macaddr : ik.ik_macaddr);

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 25, 6:50 AM (20 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12730715
Default Alt Text
D45619.diff (3 KB)

Event Timeline