]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
wifi: mac80211: fix mbss changed flags corruption on 32 bit systems
authorIssam Hamdi <ih@simonwunderlich.de>
Mon, 25 Nov 2024 16:29:20 +0000 (17:29 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 3 Dec 2024 10:26:43 +0000 (11:26 +0100)
On 32-bit systems, the size of an unsigned long is 4 bytes,
while a u64 is 8 bytes. Therefore, when using
or_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE),
the code is incorrectly searching for a bit in a 32-bit
variable that is expected to be 64 bits in size,
leading to incorrect bit finding.

Solution: Ensure that the size of the bits variable is correctly
adjusted for each architecture.

 Call Trace:
  ? show_regs+0x54/0x58
  ? __warn+0x6b/0xd4
  ? ieee80211_link_info_change_notify+0xcc/0xd4 [mac80211]
  ? report_bug+0x113/0x150
  ? exc_overflow+0x30/0x30
  ? handle_bug+0x27/0x44
  ? exc_invalid_op+0x18/0x50
  ? handle_exception+0xf6/0xf6
  ? exc_overflow+0x30/0x30
  ? ieee80211_link_info_change_notify+0xcc/0xd4 [mac80211]
  ? exc_overflow+0x30/0x30
  ? ieee80211_link_info_change_notify+0xcc/0xd4 [mac80211]
  ? ieee80211_mesh_work+0xff/0x260 [mac80211]
  ? cfg80211_wiphy_work+0x72/0x98 [cfg80211]
  ? process_one_work+0xf1/0x1fc
  ? worker_thread+0x2c0/0x3b4
  ? kthread+0xc7/0xf0
  ? mod_delayed_work_on+0x4c/0x4c
  ? kthread_complete_and_exit+0x14/0x14
  ? ret_from_fork+0x24/0x38
  ? kthread_complete_and_exit+0x14/0x14
  ? ret_from_fork_asm+0xf/0x14
  ? entry_INT80_32+0xf0/0xf0

Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
Link: https://patch.msgid.link/20241125162920.2711462-1-ih@simonwunderlich.de
[restore no-op path for no changes]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/mesh.c

index cb5f16366b9c54c9c9cffdf62762b335215dc49c..974081324aa44dd5167967a42e37ab3c57d26256 100644 (file)
@@ -1157,14 +1157,14 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                                       u64 changed)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       unsigned long bits = changed;
+       unsigned long bits[] = { BITMAP_FROM_U64(changed) };
        u32 bit;
 
-       if (!bits)
+       if (!changed)
                return;
 
        /* if we race with running work, worst case this work becomes a noop */
-       for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
+       for_each_set_bit(bit, bits, sizeof(changed) * BITS_PER_BYTE)
                set_bit(bit, ifmsh->mbss_changed);
        set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
        wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);