iwl_mvm_query_set_freqs() iterates over bit positions 0 .. SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8 - 1 (= 0..55 on the v2 path, 0..39 on the v1 path) and, for each set bit, performs: match->channels[n_channels++] = mvm->nd_channels[i]->center_freq; without constraining i against mvm->n_nd_channels. The pointer table mvm->nd_channels is kmemdup()ed at suspend time with exactly mvm->n_nd_channels entries (whatever the userspace NL80211_CMD_SET_WOWLAN request supplied as nd_config->n_channels; typical real-world values are 5..50). If the firmware response contains any matching_channels[] bit set at a position >= mvm->n_nd_channels, the indexed load reads a u8* slot past the end of the pointer-table allocation, then the immediate ->center_freq dereferences that wild pointer. The pre-existing caller guard if (mvm->n_nd_channels < n_channels) continue; compares the bitmap's popcount to the table length, not the bit positions to the table length. A bitmap with three set bits at positions {50, 51, 52} has popcount 3 and passes the guard unconditionally, then walks 50+ entries off the end of mvm->nd_channels. Reproduced under UML+KASAN via a KUnit harness that lifts the iteration logic. With nd_channels allocated as 5 entries and matching_channels bits set at positions 7 (immediate redzone) and 50 (far OOB), the kernel panics on the wild deref: Kernel panic - not syncing: Segfault with no mm RIP: 0033:set_freqs_buggy.constprop.0+0xc1/0x15e (The selector 0x0033 in the RIP line is UML's user-mode segment; under UML, in-kernel code runs in ring 3 on the host. The trap is a kernel-context page fault on the wild-pointer deref.) Building drivers/net/wireless/intel/iwlwifi/mvm/d3.o under x86_64 allmodconfig with the fix applied yields no new warnings. Clamp the iteration upper bound to min(matching-bits-width, mvm->n_nd_channels) so high-position bits, however the firmware emitted them, cannot index past the pointer table. Mirror the fix for the v1 fallback arm. Cc: stable@vger.kernel.org Fixes: 8ed4e659f34c ("iwlwifi: mvm: add channel information to the netdetect notifications") Signed-off-by: Michael Bommarito Assisted-by: Claude:claude-opus-4-7 --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index c17ac62feec3..b04d8dd26cd0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2514,16 +2514,20 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm, IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { struct iwl_scan_offload_profile_match *matches = (void *)results->matches; + int max = min_t(int, SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8, + mvm->n_nd_channels); - for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++) + for (i = 0; i < max; i++) if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) match->channels[n_channels++] = mvm->nd_channels[i]->center_freq; } else { struct iwl_scan_offload_profile_match_v1 *matches = (void *)results->matches; + int max = min_t(int, SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8, + mvm->n_nd_channels); - for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++) + for (i = 0; i < max; i++) if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) match->channels[n_channels++] = mvm->nd_channels[i]->center_freq; -- 2.53.0