nl80211: Clear nlmsg payload with keys before freeing
authorJouni Malinen <j@w1.fi>
Fri, 2 Jan 2015 23:01:42 +0000 (01:01 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 2 Jan 2015 23:15:34 +0000 (01:15 +0200)
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>
src/drivers/driver_nl80211.c

index 05521fb..74f5762 100644 (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);
 }