]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: fix MLE defragmentation
authorJohannes Berg <johannes.berg@intel.com>
Fri, 8 May 2026 07:10:31 +0000 (09:10 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 20 May 2026 09:19:52 +0000 (11:19 +0200)
If either reconf or EPCS multi-link element (MLE) is contained in
a non-transmitted profile, the defragmentation routine is called
with a pointer to the defragmented copy, but the original elements.

This is incorrect for two reasons:
 - if the original defragmentation was needed, it will not find the
   correct data
 - if the original frame is at a higher address, the parsing will
   potentially overrun the heap data (though given the layout of
   the buffers, only into the new defragmentation buffer, and then
   it has to stop and fail once that's filled with copied data.

Fix it by tracking the container along with the pointer and in
doing so also unify the two almost identical defragmentation
routines.

Fixes: 4d70e9c5488d ("wifi: mac80211: defragment reconfiguration MLE when parsing")
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
Link: https://patch.msgid.link/20260508091031.8a6c34613178.I4de16ebbce2d27f2f8f98fc49949c7a376c2fe8d@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/parse.c

index 2b3632c6008af254cd529197190ee3f73cbb7f9d..666cdd5fd0ea5b51165a3f7886e9d368393ee40c 100644 (file)
 #include "led.h"
 #include "wep.h"
 
+struct ieee80211_elem_defrag {
+       const struct element *elem;
+       /* container start/len */
+       const u8 *start;
+       size_t len;
+};
+
 struct ieee80211_elems_parse {
        /* must be first for kfree to work */
        struct ieee802_11_elems elems;
@@ -41,11 +48,7 @@ struct ieee80211_elems_parse {
        /* The basic Multi-Link element in the original elements */
        const struct element *ml_basic_elem;
 
-       /* The reconfiguration Multi-Link element in the original elements */
-       const struct element *ml_reconf_elem;
-
-       /* The EPCS Multi-Link element in the original elements */
-       const struct element *ml_epcs_elem;
+       struct ieee80211_elem_defrag ml_reconf, ml_epcs;
 
        bool multi_link_inner;
        bool skip_vendor;
@@ -162,10 +165,14 @@ ieee80211_parse_extension_element(u32 *crc,
                                }
                                break;
                        case IEEE80211_ML_CONTROL_TYPE_RECONF:
-                               elems_parse->ml_reconf_elem = elem;
+                               elems_parse->ml_reconf.elem = elem;
+                               elems_parse->ml_reconf.start = params->start;
+                               elems_parse->ml_reconf.len = params->len;
                                break;
                        case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
-                               elems_parse->ml_epcs_elem = elem;
+                               elems_parse->ml_epcs.elem = elem;
+                               elems_parse->ml_epcs.start = params->start;
+                               elems_parse->ml_epcs.len = params->len;
                                break;
                        default:
                                break;
@@ -990,46 +997,27 @@ ieee80211_prep_mle_link_parse(struct ieee80211_elems_parse *elems_parse,
                                      sub->start, sub->len);
 }
 
-static void
-ieee80211_mle_defrag_reconf(struct ieee80211_elems_parse *elems_parse)
-{
-       struct ieee802_11_elems *elems = &elems_parse->elems;
-       ssize_t ml_len;
-
-       ml_len = cfg80211_defragment_element(elems_parse->ml_reconf_elem,
-                                            elems->ie_start,
-                                            elems->total_len,
-                                            elems_parse->scratch_pos,
-                                            elems_parse->scratch +
-                                               elems_parse->scratch_len -
-                                               elems_parse->scratch_pos,
-                                            WLAN_EID_FRAGMENT);
-       if (ml_len < 0)
-               return;
-       elems->ml_reconf = (void *)elems_parse->scratch_pos;
-       elems->ml_reconf_len = ml_len;
-       elems_parse->scratch_pos += ml_len;
-}
-
-static void
-ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
+static const void *
+ieee80211_mle_defrag(struct ieee80211_elems_parse *elems_parse,
+                    struct ieee80211_elem_defrag *defrag,
+                    size_t *out_len)
 {
-       struct ieee802_11_elems *elems = &elems_parse->elems;
+       const void *ret;
        ssize_t ml_len;
 
-       ml_len = cfg80211_defragment_element(elems_parse->ml_epcs_elem,
-                                            elems->ie_start,
-                                            elems->total_len,
+       ml_len = cfg80211_defragment_element(defrag->elem,
+                                            defrag->start, defrag->len,
                                             elems_parse->scratch_pos,
                                             elems_parse->scratch +
                                                elems_parse->scratch_len -
                                                elems_parse->scratch_pos,
                                             WLAN_EID_FRAGMENT);
        if (ml_len < 0)
-               return;
-       elems->ml_epcs = (void *)elems_parse->scratch_pos;
-       elems->ml_epcs_len = ml_len;
+               return NULL;
+       ret = elems_parse->scratch_pos;
+       *out_len = ml_len;
        elems_parse->scratch_pos += ml_len;
+       return ret;
 }
 
 struct ieee802_11_elems *
@@ -1109,9 +1097,12 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
                _ieee802_11_parse_elems_full(&sub, elems_parse, NULL);
        }
 
-       ieee80211_mle_defrag_reconf(elems_parse);
-
-       ieee80211_mle_defrag_epcs(elems_parse);
+       elems->ml_reconf = ieee80211_mle_defrag(elems_parse,
+                                               &elems_parse->ml_reconf,
+                                               &elems->ml_reconf_len);
+       elems->ml_epcs = ieee80211_mle_defrag(elems_parse,
+                                             &elems_parse->ml_epcs,
+                                             &elems->ml_epcs_len);
 
        if (elems->tim && !elems->parse_error) {
                const struct ieee80211_tim_ie *tim_ie = elems->tim;