mac80211: mlme: check for null after calling kmemdup
authorJiasheng Jiang <jiasheng@iscas.ac.cn>
Wed, 5 Jan 2022 08:15:59 +0000 (16:15 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 23 Feb 2022 11:03:10 +0000 (12:03 +0100)
commit a72c01a94f1d285a274219d36e2a17b4846c0615 upstream.

As the possible failure of the alloc, the ifmgd->assoc_req_ies might be
NULL pointer returned from kmemdup().
Therefore it might be better to free the skb and return error in order
to fail the association, like ieee80211_assoc_success().
Also, the caller, ieee80211_do_assoc(), needs to deal with the return
value from ieee80211_send_assoc().

Fixes: 4d9ec73d2b78 ("cfg80211: Report Association Request frame IEs in association events")
Signed-off-by: Jiasheng Jiang <jiasheng@iscas.ac.cn>
Link: https://lore.kernel.org/r/20220105081559.2387083-1-jiasheng@iscas.ac.cn
[fix some paths to be errors, not success]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/mac80211/mlme.c

index 89c648b035b9a0ef51caabde75f08d0e75608bde..215948fb0d35e25e290e1f27ccce0010a9b0f493 100644 (file)
@@ -664,7 +664,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
        ieee80211_ie_build_he_6ghz_cap(sdata, skb);
 }
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -684,6 +684,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
        const struct ieee80211_sband_iftype_data *iftd;
        struct ieee80211_prep_tx_info info = {};
+       int ret;
 
        /* we know it's writable, cast away the const */
        if (assoc_data->ie_len)
@@ -697,7 +698,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (WARN_ON(!chanctx_conf)) {
                rcu_read_unlock();
-               return;
+               return -EINVAL;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();
@@ -748,7 +749,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        (iftd ? iftd->vendor_elems.len : 0),
                        GFP_KERNEL);
        if (!skb)
-               return;
+               return -ENOMEM;
 
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
@@ -1029,15 +1030,22 @@ skip_rates:
                skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
        }
 
-       if (assoc_data->fils_kek_len &&
-           fils_encrypt_assoc_req(skb, assoc_data) < 0) {
-               dev_kfree_skb(skb);
-               return;
+       if (assoc_data->fils_kek_len) {
+               ret = fils_encrypt_assoc_req(skb, assoc_data);
+               if (ret < 0) {
+                       dev_kfree_skb(skb);
+                       return ret;
+               }
        }
 
        pos = skb_tail_pointer(skb);
        kfree(ifmgd->assoc_req_ies);
        ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC);
+       if (!ifmgd->assoc_req_ies) {
+               dev_kfree_skb(skb);
+               return -ENOMEM;
+       }
+
        ifmgd->assoc_req_ies_len = pos - ie_start;
 
        drv_mgd_prepare_tx(local, sdata, &info);
@@ -1047,6 +1055,8 @@ skip_rates:
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
                                                IEEE80211_TX_INTFL_MLME_CONN_TX;
        ieee80211_tx_skb(sdata, skb);
+
+       return 0;
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -4451,6 +4461,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
        struct ieee80211_local *local = sdata->local;
+       int ret;
 
        sdata_assert_lock(sdata);
 
@@ -4471,7 +4482,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
        sdata_info(sdata, "associate with %pM (try %d/%d)\n",
                   assoc_data->bss->bssid, assoc_data->tries,
                   IEEE80211_ASSOC_MAX_TRIES);
-       ieee80211_send_assoc(sdata);
+       ret = ieee80211_send_assoc(sdata);
+       if (ret)
+               return ret;
 
        if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
                assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;