]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb
authorZhao Li <enderaoelyther@gmail.com>
Sat, 9 May 2026 04:34:28 +0000 (12:34 +0800)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 20 May 2026 09:19:53 +0000 (11:19 +0200)
ieee80211_invoke_fast_rx() reads RX status through
IEEE80211_SKB_RXCB(skb), which aliases the same skb->cb storage
that ieee80211_rx_mesh_data() reuses as IEEE80211_TX_INFO.  In the
unicast forward path, mesh_data does:

info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));

on the same skb the caller still names via rx->skb, then either
queues the skb for TX (success) or kfree_skb()'s it (no-route)
before returning RX_QUEUED.  The caller's RX_QUEUED arm then
calls sta_stats_encode_rate(status) on memory that is either
zeroed (success path) or freed (no-route path).  The latter is
KASAN slab-use-after-free in ieee80211_prepare_and_rx_handle.

Fix by encoding the rate from status before invoking
ieee80211_rx_mesh_data(), so the RX_QUEUED arm consumes a value
captured while status was still backed by valid memory.

Fixes: 3468e1e0c639 ("wifi: mac80211: add mesh fast-rx support")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260509043427.60322-2-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/rx.c

index d18e962126ce4d8d6bbb62c487a39d15dddb0bb6..3fb40449c6c5c5bec5c70500c99fb3dcc8f8cbe7 100644 (file)
@@ -4984,6 +4984,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
                u8 sa[ETH_ALEN];
        } addrs __aligned(2);
        struct ieee80211_sta_rx_stats *stats;
+       u32 encoded_rate;
 
        /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
         * to a common data structure; drivers can implement that per queue
@@ -5091,11 +5092,14 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
        /* push the addresses in front */
        memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
 
+       /* capture before mesh forward may memset or free skb->cb */
+       encoded_rate = sta_stats_encode_rate(status);
+
        res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
        switch (res) {
        case RX_QUEUED:
                stats->last_rx = jiffies;
-               stats->last_rate = sta_stats_encode_rate(status);
+               stats->last_rate = encoded_rate;
                return true;
        case RX_CONTINUE:
                break;