iwl_mld_set_netdetect_info() walks the per-match matching_channels[] bitmap and emits one center_freq per set bit by indexing netdetect_cfg->channels[]: for_each_set_bit(j, (unsigned long *)&matches[i].matching_channels[0], sizeof(matches[i].matching_channels)) { match->channels[match->n_channels] = netdetect_cfg->channels[j]->center_freq; match->n_channels++; } Two problems here. First, the third argument to for_each_set_bit(bit, addr, size) is the number of BITS to walk, not bytes. sizeof(matches[i].matching_channels) is SCAN_OFFLOAD_MATCHING_CHANNELS_LEN = 7 BYTES, so the macro only visits j = 0..6 and silently misses bits 7..55 of the 56-bit bitmap. This is a functional defect (per-match channel reporting is truncated to the first 7 entries of the bitmap). Second, the loop body indexes netdetect_cfg->channels[j] without bounding j against netdetect_cfg->n_channels. netdetect_cfg ->channels is a kmemdup()'ed array of pointers sized at exactly n_channels entries (the user's WoWLAN net-detect channel list). If n_channels < 7 (a 2.4 GHz only configuration, or a small saved- SSID channel allowlist) and the firmware sets a match bit at any position in [n_channels, 6], the indexed load reads past the end of the allocation, and ->center_freq then dereferences whatever that wild pointer fetched. Reproduced under UML+KASAN via a KUnit harness that lifts the iteration logic. With netdetect_cfg->channels sized at 5 entries and matching_channels bit 5 set, the kernel panics on the wild deref: Kernel panic - not syncing: Segfault with no mm RIP: 0033:mld_set_freqs_buggy.constprop.0+0x116/0x1c2 (The selector 0x0033 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/mld/d3.o under x86_64 allmodconfig with the fix applied yields no new warnings. Rewrite the iteration as an explicit indexed loop with an upper bound of min(bitmap-width-in-bits, n_channels). This addresses both issues in one step: bits-correct iteration over the bitmap, and a hard clamp against the channels-table length. Address the two together because applying only the bits-correct iteration without the clamp would widen the OOB exposure from j < 7 to j < 56. A short comment is added because the clamp's purpose (avoiding an OOB pointer fetch from netdetect_cfg->channels) is not obvious from the expression alone, and a future reader could otherwise "simplify" the bound back to the underlying constant. Cc: stable@vger.kernel.org Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver") Signed-off-by: Michael Bommarito Assisted-by: Claude:claude-opus-4-7 --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index e89ec531cb06..51abf414bb1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -1165,7 +1165,7 @@ iwl_mld_set_netdetect_info(struct iwl_mld *mld, for_each_set_bit(i, &matched_profiles, netdetect_cfg->n_match_sets) { struct cfg80211_wowlan_nd_match *match; - int idx, j, n_channels = 0; + int idx, j, max, n_channels = 0; struct iwl_scan_offload_profile_match *matches = (void *)netdetect_res->matches; @@ -1192,9 +1192,19 @@ iwl_mld_set_netdetect_info(struct iwl_mld *mld, if (netdetect_cfg->n_channels < n_channels) continue; - for_each_set_bit(j, - (unsigned long *)&matches[i].matching_channels[0], - sizeof(matches[i].matching_channels)) { + /* Clamp bit-index iteration to the channels table length: + * a firmware-set bit past n_channels would otherwise index + * past the kmemdup'd netdetect_cfg->channels[] allocation. + */ + max = min_t(int, BITS_PER_BYTE * + sizeof(matches[i].matching_channels), + netdetect_cfg->n_channels); + + for (j = 0; j < max; j++) { + if (!(matches[i].matching_channels[j / BITS_PER_BYTE] & + BIT(j % BITS_PER_BYTE))) + continue; + match->channels[match->n_channels] = netdetect_cfg->channels[j]->center_freq; match->n_channels++; -- 2.53.0