nl80211: Clear nlmsg payload with keys before freeing

This reduces the time possible keys could remain in heap memory. Couple
of the nl80211 messages include keys (TK for normal ciphers and
KCK/KEK/PMK for various offloading cases).

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-01-03 01:01:42 +02:00
parent f2535da879
commit bbd89bfca0

View file

@ -281,6 +281,22 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
}
static void nl80211_nlmsg_clear(struct nl_msg *msg)
{
/*
* Clear nlmsg data, e.g., to make sure key material is not left in
* heap memory for unnecessarily long time.
*/
if (msg) {
struct nlmsghdr *hdr = nlmsg_hdr(msg);
void *data = nlmsg_data(hdr);
int len = nlmsg_datalen(hdr);
os_memset(data, 0, len);
}
}
static int send_and_recv(struct nl80211_global *global,
struct nl_handle *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
@ -320,6 +336,8 @@ static int send_and_recv(struct nl80211_global *global,
}
out:
nl_cb_put(cb);
if (!valid_handler && valid_data == (void *) -1)
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return err;
}
@ -2331,10 +2349,11 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -1;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Key management set key failed: ret=%d (%s)",
@ -2426,7 +2445,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@ -2477,6 +2496,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
return ret;
fail:
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
@ -6717,13 +6737,14 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
replay_ctr)) {
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return;
}
nla_nest_end(msg, replay_nested);
send_and_recv_msgs(drv, msg, NULL, NULL);
send_and_recv_msgs(drv, msg, NULL, (void *) -1);
}