]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: cfg80211: validate assoc response length before status and IE access
authorZhao Li <enderaoelyther@gmail.com>
Tue, 7 Jul 2026 02:53:35 +0000 (10:53 +0800)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Jul 2026 07:31:38 +0000 (09:31 +0200)
cfg80211_rx_assoc_resp() initialises the status and response-IE fields
of cfg80211_connect_resp_params from the management frame before
proving that the frame is long enough for those offsets. S1G and
regular association responses also have different IE offsets, but the
S1G path only patched resp_ie after the unsafe initialiser had already
run.

Defer resp_ie, resp_ie_len, and status to after the link-iteration
loop. Use a bool to remember whether the frame is S1G, then validate
the appropriate minimum length and set all three fields in a single
if/else block. Funnel short-frame and SME-reject cleanup through a
shared free_bss label for the abandon paths.

Assisted-by: Codex:gpt-5.5
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260707025336.22557-2-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/mlme.c

index acc749eee2fea8579fef853003311898b809575f..7824b7ac2770fbb180a3834202cd7d1d892c20d5 100644 (file)
@@ -32,15 +32,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
                .timeout_reason = NL80211_TIMEOUT_UNSPECIFIED,
                .req_ie = data->req_ies,
                .req_ie_len = data->req_ies_len,
-               .resp_ie = mgmt->u.assoc_resp.variable,
-               .resp_ie_len = data->len -
-                              offsetof(struct ieee80211_mgmt,
-                                       u.assoc_resp.variable),
-               .status = le16_to_cpu(mgmt->u.assoc_resp.status_code),
                .ap_mld_addr = data->ap_mld_addr,
                .assoc_encrypted = data->assoc_encrypted,
        };
        unsigned int link_id;
+       bool is_s1g = false;
 
        for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
                cr.links[link_id].status = data->links[link_id].status;
@@ -61,16 +57,32 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
 
                if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) {
                        WARN_ON(link_id);
-                       cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
-                       cr.resp_ie_len = data->len -
-                                        offsetof(struct ieee80211_mgmt,
-                                                 u.s1g_assoc_resp.variable);
+                       is_s1g = true;
                }
 
                if (cr.ap_mld_addr)
                        cr.valid_links |= BIT(link_id);
        }
 
+       if (is_s1g) {
+               if (data->len < offsetof(struct ieee80211_mgmt,
+                                        u.s1g_assoc_resp.variable))
+                       goto free_bss;
+               cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
+               cr.resp_ie_len = data->len -
+                                offsetof(struct ieee80211_mgmt,
+                                         u.s1g_assoc_resp.variable);
+       } else {
+               if (data->len < offsetof(struct ieee80211_mgmt,
+                                        u.assoc_resp.variable))
+                       goto free_bss;
+               cr.resp_ie = mgmt->u.assoc_resp.variable;
+               cr.resp_ie_len = data->len -
+                                offsetof(struct ieee80211_mgmt,
+                                         u.assoc_resp.variable);
+       }
+       cr.status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
        trace_cfg80211_send_rx_assoc(dev, data);
 
        /*
@@ -79,22 +91,24 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
         * and got a reject -- we only try again with an assoc
         * frame instead of reassoc.
         */
-       if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
-               for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
-                       struct cfg80211_bss *bss = data->links[link_id].bss;
-
-                       if (!bss)
-                               continue;
-
-                       cfg80211_unhold_bss(bss_from_pub(bss));
-                       cfg80211_put_bss(wiphy, bss);
-               }
-               return;
-       }
+       if (cfg80211_sme_rx_assoc_resp(wdev, cr.status))
+               goto free_bss;
 
        nl80211_send_rx_assoc(rdev, dev, data);
        /* update current_bss etc., consumes the bss reference */
        __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
+       return;
+
+free_bss:
+       for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
+               struct cfg80211_bss *bss = data->links[link_id].bss;
+
+               if (!bss)
+                       continue;
+
+               cfg80211_unhold_bss(bss_from_pub(bss));
+               cfg80211_put_bss(wiphy, bss);
+       }
 }
 EXPORT_SYMBOL(cfg80211_rx_assoc_resp);