* [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld)
@ 2026-05-15 12:10 Michael Bommarito
2026-05-15 12:10 ` [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check Michael Bommarito
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
To: Miri Korenblit
Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel, stable
Four defensive bound-check additions on the WoWLAN net-detect
resume path in iwlwifi, validating firmware-controlled response
lengths and bitmap-bit positions at the host/firmware trust
boundary. Two patches each in the mvm and mld op-modes; both
op-modes are live in current kernels (mvm drives 7000-series
through pre-BE200 hardware; mld drives Wi-Fi 7 / BE200+ when
CONFIG_IWLMLD is enabled).
The series is in the same shape as the recently fixed sibling
commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()"), which
landed in stable on 2026-04-11. Well-behaved firmware should not
trigger any of these, but the host parser should not depend on
that.
Patches 1 + 3: length-tail guard on the firmware response.
iwl_mvm_netdetect_query_results() and
iwl_mld_netdetect_match_info_handler() validate only the fixed
header size of the response/notification, then memcpy the flex-
array tail unconditionally. A response of exactly query_len /
sizeof(*notif) bytes passes the guard and the memcpy reads
matches_len / NETDETECT_QUERY_BUF_LEN bytes of adjacent slab
content. KASAN reports the slab-out-of-bounds READ "0 bytes to
the right of the allocated 24-byte region" in the kmalloc-32
cache. Same fix shape as the sibling.
Patches 2 + 4: clamp the channel-iteration upper bound against
the netdetect channels-table length. iwl_mvm_query_set_freqs()
and iwl_mld_set_netdetect_info() iterate the per-match
matching_channels[] bitmap and index a channels[] pointer table
by bit position, without bounding the bit positions against
the table length. The pre-existing caller-side guards compare
popcount to table length, not bit position to table length. The
mvm path iterates over the full 0..55 bit range; the mld path
is accidentally bounded to 0..6 by a bits-vs-bytes confusion
(for_each_set_bit() takes bits, but the call passes sizeof(...)
which is 7 bytes). Both can index past the channels[] allocation
when the user's net-detect configuration has fewer channels than
the relevant bound. The wild-pointer dereference of
channels[j]->center_freq inside the resume work-queue then page-
faults the kernel; a KUnit harness exercising the mvm shape
panics with
Kernel panic - not syncing: Segfault with no mm
and the mld shape panics identically when n_channels < 7. The
mld fix folds the bits-vs-bytes correction together with the
clamp because applying only the bits-correction without the
clamp would widen the OOB exposure from j < 7 to j < 56.
All four bugs require the firmware to produce inputs outside the
implied driver contract: a short response (patches 1, 3), or
matching_channels[] bits set at positions outside the channels-
table bound (patches 2, 4). Well-behaved firmware should not do
either. The patches add defensive validation at a trust boundary;
they are not a claim that current Intel firmware misbehaves.
Reproducer: self-contained KUnit suite that lifts all four buggy
code paths into standalone harnesses (no firmware or hardware
dependency, ~10s on UML). Patched-shape subtests pass cleanly
under the proposed fixes (test_patched_rejects_short,
test_patched_accepts_full, test_set_freqs_patched_clamps,
test_mld_match_info_patched_rejects_short,
test_mld_set_freqs_patched_clamps).
All four patches build clean under x86_64 allmodconfig with no
new warnings; checkpatch --strict reports 0/0/0 on each.
Michael Bommarito (4):
wifi: iwlwifi: mvm: include matches_len in scan-offload-query length
check
wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
wifi: iwlwifi: mld: include matches tail in match-info length check
wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels
drivers/net/wireless/intel/iwlwifi/mld/d3.c | 20 +++++++++++++++-----
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 10 +++++++---
2 files changed, 22 insertions(+), 8 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
@ 2026-05-15 12:10 ` Michael Bommarito
2026-05-15 12:10 ` [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels Michael Bommarito
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
To: Miri Korenblit
Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel, stable
iwl_mvm_netdetect_query_results() validates the firmware response
length against query_len (the fixed-header size of struct
iwl_scan_offload_match_info or iwl_scan_offload_profiles_query_v1)
but immediately follows with:
memcpy(results->matches, query->matches, matches_len);
where matches_len is
sizeof(struct iwl_scan_offload_profile_match[_v1]) *
iwl_umac_scan_get_max_profiles(mvm->fw)
and is not included in the guard. A firmware response of exactly
query_len bytes therefore satisfies the guard yet the memcpy
reads matches_len bytes past the end of the slab-allocated
firmware-response buffer. The worst-case extent depends on the
firmware path:
- v2 layout, SCAN_OFFLOAD_UPDATE_PROFILES_CMD version unknown
or < 3: matches_len = 18 * IWL_SCAN_MAX_PROFILES = 198 bytes.
- v2 layout, command version >= 3:
matches_len = 18 * IWL_SCAN_MAX_PROFILES_V2 = 144 bytes.
- v1 layout: matches_len = 16 * IWL_SCAN_MAX_PROFILES = 176 bytes.
Reproduced under UML+KASAN via a KUnit harness that lifts the
length-validation + memcpy logic into a self-contained test.
With the response sized at the v2 query_len (24 bytes of
match-info header) and the older-firmware max_profiles path,
KASAN reports a slab-out-of-bounds READ of 198 bytes at 0 bytes
to the right of a 24-byte allocation in the kmalloc-32 cache.
Building drivers/net/wireless/intel/iwlwifi/mvm/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.
The sibling fix iwl_mvm_nd_match_info_handler() was corrected
by commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()"). The
present function was missed during that audit; apply the same
correction shape.
Cc: stable@vger.kernel.org
Fixes: e4fe5d4b10cd ("iwlwifi: mvm: Support new format of SCAN_OFFLOAD_PROFILES_QUERY_RSP")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 9a74f60c9185..c17ac62feec3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -2458,7 +2458,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
}
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
- if (len < query_len) {
+ if (len < query_len + matches_len) {
IWL_ERR(mvm, "Invalid scan offload profiles query response!\n");
ret = -EIO;
goto out_free_resp;
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
2026-05-15 12:10 ` [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check Michael Bommarito
@ 2026-05-15 12:10 ` Michael Bommarito
2026-07-14 15:49 ` Korenblit, Miriam Rachel
2026-05-15 12:10 ` [PATCH 3/4] wifi: iwlwifi: mld: include matches tail in match-info length check Michael Bommarito
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
To: Miri Korenblit
Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel, stable
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 <michael.bommarito@gmail.com>
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/4] wifi: iwlwifi: mld: include matches tail in match-info length check
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
2026-05-15 12:10 ` [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check Michael Bommarito
2026-05-15 12:10 ` [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels Michael Bommarito
@ 2026-05-15 12:10 ` Michael Bommarito
2026-05-15 12:11 ` [PATCH 4/4] wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels Michael Bommarito
2026-07-14 15:36 ` [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Korenblit, Miriam Rachel
4 siblings, 0 replies; 7+ messages in thread
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
To: Miri Korenblit
Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel, stable
iwl_mld_netdetect_match_info_handler() validates the firmware
notification length against sizeof(*notif) (the fixed-header
size of struct iwl_scan_offload_match_info, 24 bytes) but then
immediately memcpys NETDETECT_QUERY_BUF_LEN bytes from
notif->matches:
if (IWL_FW_CHECK(mld, len < sizeof(*notif),
"Invalid scan offload match notif of length: %d\n",
len))
return true;
...
if (results->matched_profiles)
memcpy(results->matches, notif->matches,
NETDETECT_QUERY_BUF_LEN);
NETDETECT_QUERY_BUF_LEN is
(sizeof(struct iwl_scan_offload_profile_match) *
IWL_SCAN_MAX_PROFILES_V2)
= 18 * 8 = 144 bytes
so a firmware-emitted notif sized at exactly sizeof(*notif)
(24 bytes) satisfies the guard yet the memcpy reads 144 bytes
past the slab-allocated notification buffer.
Reproduced under UML+KASAN via a KUnit harness that lifts the
length-validation + memcpy logic into a self-contained test.
KASAN reports
BUG: KASAN: slab-out-of-bounds in mld_match_info_buggy.constprop.0
Read of size 144 at addr ...
Building drivers/net/wireless/intel/iwlwifi/mld/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.
This is the same bug shape as the previously fixed sibling
commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()") applied
to the mvm peer function. The mld driver was added in February
2025 and inherited the same length-check miss; apply the same
correction shape.
Cc: stable@vger.kernel.org
Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
drivers/net/wireless/intel/iwlwifi/mld/d3.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index ef98efc8fb1b..e89ec531cb06 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1128,7 +1128,7 @@ iwl_mld_netdetect_match_info_handler(struct iwl_mld *mld,
mld->netdetect))
return true;
- if (IWL_FW_CHECK(mld, len < sizeof(*notif),
+ if (IWL_FW_CHECK(mld, len < sizeof(*notif) + NETDETECT_QUERY_BUF_LEN,
"Invalid scan offload match notif of length: %d\n",
len))
return true;
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/4] wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
` (2 preceding siblings ...)
2026-05-15 12:10 ` [PATCH 3/4] wifi: iwlwifi: mld: include matches tail in match-info length check Michael Bommarito
@ 2026-05-15 12:11 ` Michael Bommarito
2026-07-14 15:36 ` [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Korenblit, Miriam Rachel
4 siblings, 0 replies; 7+ messages in thread
From: Michael Bommarito @ 2026-05-15 12:11 UTC (permalink / raw)
To: Miri Korenblit
Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel, stable
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 <michael.bommarito@gmail.com>
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld)
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
` (3 preceding siblings ...)
2026-05-15 12:11 ` [PATCH 4/4] wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels Michael Bommarito
@ 2026-07-14 15:36 ` Korenblit, Miriam Rachel
4 siblings, 0 replies; 7+ messages in thread
From: Korenblit, Miriam Rachel @ 2026-07-14 15:36 UTC (permalink / raw)
To: Michael Bommarito
Cc: Berg, Johannes, Grumbach, Emmanuel, linux-wireless, linux-kernel, stable
> -----Original Message-----
> From: Michael Bommarito <michael.bommarito@gmail.com>
> Sent: Friday, May 15, 2026 3:11 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>
> Cc: Berg, Johannes <johannes.berg@intel.com>; Grumbach, Emmanuel
> <emmanuel.grumbach@intel.com>; linux-wireless@vger.kernel.org; linux-
> kernel@vger.kernel.org; stable@vger.kernel.org
> Subject: [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against
> firmware-controlled inputs (mvm + mld)
>
> Four defensive bound-check additions on the WoWLAN net-detect resume path in
> iwlwifi, validating firmware-controlled response lengths and bitmap-bit positions
> at the host/firmware trust boundary. Two patches each in the mvm and mld op-
> modes; both op-modes are live in current kernels (mvm drives 7000-series
> through pre-BE200 hardware; mld drives Wi-Fi 7 / BE200+ when
> CONFIG_IWLMLD is enabled).
>
> The series is in the same shape as the recently fixed sibling commit 744fabc338e8
> ("wifi: iwlwifi: mvm: fix potential out-of-bounds read in
> iwl_mvm_nd_match_info_handler()"), which landed in stable on 2026-04-11.
> Well-behaved firmware should not trigger any of these, but the host parser
> should not depend on that.
>
> Patches 1 + 3: length-tail guard on the firmware response.
> iwl_mvm_netdetect_query_results() and
> iwl_mld_netdetect_match_info_handler() validate only the fixed header size of
> the response/notification, then memcpy the flex- array tail unconditionally. A
> response of exactly query_len /
> sizeof(*notif) bytes passes the guard and the memcpy reads matches_len /
> NETDETECT_QUERY_BUF_LEN bytes of adjacent slab content. KASAN reports the
> slab-out-of-bounds READ "0 bytes to the right of the allocated 24-byte region" in
> the kmalloc-32 cache. Same fix shape as the sibling.
>
> Patches 2 + 4: clamp the channel-iteration upper bound against the netdetect
> channels-table length. iwl_mvm_query_set_freqs() and
> iwl_mld_set_netdetect_info() iterate the per-match matching_channels[] bitmap
> and index a channels[] pointer table by bit position, without bounding the bit
> positions against the table length. The pre-existing caller-side guards compare
> popcount to table length, not bit position to table length. The mvm path iterates
> over the full 0..55 bit range; the mld path is accidentally bounded to 0..6 by a
> bits-vs-bytes confusion
> (for_each_set_bit() takes bits, but the call passes sizeof(...) which is 7 bytes). Both
> can index past the channels[] allocation when the user's net-detect configuration
> has fewer channels than the relevant bound. The wild-pointer dereference of
> channels[j]->center_freq inside the resume work-queue then page- faults the
> kernel; a KUnit harness exercising the mvm shape panics with
>
> Kernel panic - not syncing: Segfault with no mm
>
> and the mld shape panics identically when n_channels < 7. The mld fix folds the
> bits-vs-bytes correction together with the clamp because applying only the bits-
> correction without the clamp would widen the OOB exposure from j < 7 to j < 56.
>
> All four bugs require the firmware to produce inputs outside the implied driver
> contract: a short response (patches 1, 3), or matching_channels[] bits set at
> positions outside the channels- table bound (patches 2, 4). Well-behaved
> firmware should not do either. The patches add defensive validation at a trust
> boundary; they are not a claim that current Intel firmware misbehaves.
>
> Reproducer: self-contained KUnit suite that lifts all four buggy code paths into
> standalone harnesses (no firmware or hardware dependency, ~10s on UML).
> Patched-shape subtests pass cleanly under the proposed fixes
> (test_patched_rejects_short, test_patched_accepts_full,
> test_set_freqs_patched_clamps, test_mld_match_info_patched_rejects_short,
> test_mld_set_freqs_patched_clamps).
>
> All four patches build clean under x86_64 allmodconfig with no new warnings;
> checkpatch --strict reports 0/0/0 on each.
>
> Michael Bommarito (4):
> wifi: iwlwifi: mvm: include matches_len in scan-offload-query length
> check
> wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
> wifi: iwlwifi: mld: include matches tail in match-info length check
> wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels
>
> drivers/net/wireless/intel/iwlwifi/mld/d3.c | 20 +++++++++++++++-----
> drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 10 +++++++---
> 2 files changed, 22 insertions(+), 8 deletions(-)
>
Hi Michael,
Thank you for your time and your fixes 😊
2 of those were already fixed internally,
But the 2 'clamp' ones are not. Will comment on those separately.
Miri
---
> --
> 2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
2026-05-15 12:10 ` [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels Michael Bommarito
@ 2026-07-14 15:49 ` Korenblit, Miriam Rachel
0 siblings, 0 replies; 7+ messages in thread
From: Korenblit, Miriam Rachel @ 2026-07-14 15:49 UTC (permalink / raw)
To: Michael Bommarito
Cc: Berg, Johannes, Grumbach, Emmanuel, linux-wireless, linux-kernel, stable
> -----Original Message-----
> From: Michael Bommarito <michael.bommarito@gmail.com>
> Sent: Friday, May 15, 2026 3:11 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>
> Cc: Berg, Johannes <johannes.berg@intel.com>; Grumbach, Emmanuel
> <emmanuel.grumbach@intel.com>; linux-wireless@vger.kernel.org; linux-
> kernel@vger.kernel.org; stable@vger.kernel.org
> Subject: [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to
> n_nd_channels
>
> 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 <michael.bommarito@gmail.com>
> 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);
>
In case the FW is misbehaving, we want to know about it, and we use
IWL_FW_CHECK. Also in mld.
> - 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
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-14 15:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-15 12:10 [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Michael Bommarito
2026-05-15 12:10 ` [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check Michael Bommarito
2026-05-15 12:10 ` [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels Michael Bommarito
2026-07-14 15:49 ` Korenblit, Miriam Rachel
2026-05-15 12:10 ` [PATCH 3/4] wifi: iwlwifi: mld: include matches tail in match-info length check Michael Bommarito
2026-05-15 12:11 ` [PATCH 4/4] wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels Michael Bommarito
2026-07-14 15:36 ` [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld) Korenblit, Miriam Rachel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®