[PATCH] wifi: nl80211: validate NAN band config attributes

From: Noah Weinberger

Date: Sun Nov 08 2026 - 18:48:53 EST


Hello,

nl80211_parse_nan_conf() parses NL80211_NAN_CONFIG and each nested
band config with a NULL nla policy, and the per-band index is taken
from a raw u8 attribute without any bounds check:

band = nla_get_u8(tb[NL80211_NAN_BAND_CONF_BAND]);
if (conf->bands && !(conf->bands & BIT(band)))
return -EINVAL;

cfg = &conf->band_cfgs[band];

band_cfgs[] has NUM_NL80211_BANDS (6) entries of 16 bytes, and conf is
a struct cfg80211_nan_conf on the stack of nl80211_start_nan() /
nl80211_nan_change_config(). Both guards are bypassable: BIT(band)
with band >= 64 is compiled as a shift of band mod 64, so band values
such as 64, 128 or 192 alias to bit 0 (2.4 GHz) and pass the
nan_supported_bands test; the conf->bands test is skipped entirely
when NL80211_ATTR_BANDS is not supplied. The band-config writes
(rssi_close, rssi_middle, awake_dw_interval, disable_scan) then land
roughly 1 KB to 3.1 KB past the 128-byte stack object - three
attacker-controlled bytes plus a zero byte per attribute, at
16-byte-strided offsets chosen by the band value.

The path is reachable by an unprivileged user when user namespaces
are enabled: START_NAN needs CAP_NET_ADMIN over a netns, and
mac80211_hwsim (which registers .start_nan and nan_supported_bands)
lets any user create a NAN-capable radio in their own netns via
HWSIM_CMD_NEW_RADIO (GENL_UNS_ADMIN_PERM, netnsok family). Real
hardware paths (mt7925, iwlwifi MLD) are covered by the same code.

The patch adds the missing bounds check and also requires an
ETH_ALEN-sized CLUSTER_ID attribute, whose ether_addr_copy() currently
reads 6 bytes from a policy-less attribute of arbitrary length. A full
fix would additionally give both nested policies real NLA_POLICY
entries.

Affected version/commit: mainline 8a65162514fbad21a2c58ffed65f42b27e92b163 (v7.4-rc2 window, 2026-11-08), net/wireless/nl80211.c:17043-17087 (nl80211_parse_nan_band_config), :17165-17194 (band_configs loop), :17133-17135 and :17173-17176 (NULL nla policies), :17183-17187 (band = nla_get_u8; cfg = &conf->band_cfgs[band]), :17140-17142 (cluster_id copy), :17259 and :17634 (stack frames holding struct cfg80211_nan_conf), include/net/cfg80211.h:4176-4182 and :4210-4224 (band_cfgs[NUM_NL80211_BANDS=6], 16-byte elements)
Introduced with the NAN band-configuration UAPI (before the reviewed window; present in the whole 7.3/7.4 series).

This was found during an assisted (AI-supported) static source review of
mainline 8a65162514fbad21a2c58ffed65f42b27e92b163 (v7.4-rc2 window, 2026-11-08). The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.

---
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d790e204ae..4dea7afcdc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17138,6 +17138,8 @@ static int nl80211_parse_nan_conf(struct wiphy *wiphy,

changed |= CFG80211_NAN_CONF_CHANGED_CONFIG;
if (attrs[NL80211_NAN_CONF_CLUSTER_ID] && start) {
+ if (nla_len(attrs[NL80211_NAN_CONF_CLUSTER_ID]) != ETH_ALEN)
+ return -EINVAL;
ether_addr_copy(conf->cluster_id,
nla_data(attrs[NL80211_NAN_CONF_CLUSTER_ID]));
} else if (start) {
@@ -17184,6 +17186,8 @@ static int nl80211_parse_nan_conf(struct wiphy *wiphy,
if (conf->bands && !(conf->bands & BIT(band)))
return -EINVAL;

+ if (band >= NUM_NL80211_BANDS)
+ return -EINVAL;
cfg = &conf->band_cfgs[band];

err = nl80211_parse_nan_band_config(wiphy, tb, cfg,