From: Johannes Berg Date: Wed, 15 Apr 2026 12:42:14 +0000 (+0200) Subject: wifi: nl80211: reject too short HT/VHT/HE/EHT capability/operation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d642e759b73cbf4d9b8c40e55c44437465d31820;p=thirdparty%2Fkernel%2Flinux.git wifi: nl80211: reject too short HT/VHT/HE/EHT capability/operation If any of these are present, the code only assigns pointers when they're also long enough. Instead of ignoring them in that case, reject the configuration instead. Also add error messages to existing error paths. Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20260415144514.40c24d7ee2df.Ib1368e4d8e33a396f332a38a6ba6708fd188f143@changeid Signed-off-by: Johannes Berg --- diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d1bede3d0a145..a4dbe6ff0045e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6649,28 +6649,49 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_beacon_data *bcn, * HT/VHT/... capabilities, we parse them out of the elements and check for * validity for use by drivers/mac80211. */ -static int nl80211_calculate_ap_capabilities(struct cfg80211_ap_settings *params) +static int nl80211_calculate_ap_capabilities(struct genl_info *info, + struct cfg80211_ap_settings *params) { size_t ies_len = params->beacon.tail_len; const u8 *ies = params->beacon.tail; const struct element *cap; cap = cfg80211_find_elem(WLAN_EID_HT_CAPABILITY, ies, ies_len); - if (cap && cap->datalen >= sizeof(*params->ht_cap)) + if (cap) { + if (cap->datalen < sizeof(*params->ht_cap)) { + GENL_SET_ERR_MSG(info, "bad HT capability in beacon"); + return -EINVAL; + } params->ht_cap = (void *)cap->data; + } + cap = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY, ies, ies_len); - if (cap && cap->datalen >= sizeof(*params->vht_cap)) + if (cap) { + if (cap->datalen < sizeof(*params->vht_cap)) { + GENL_SET_ERR_MSG(info, "bad VHT capability in beacon"); + return -EINVAL; + } params->vht_cap = (void *)cap->data; + } + cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len); - if (cap && cap->datalen >= sizeof(*params->he_cap) + 1) + if (cap) { + if (cap->datalen < sizeof(*params->he_cap) + 1) { + GENL_SET_ERR_MSG(info, "bad HE capability in beacon"); + return -EINVAL; + } params->he_cap = (void *)(cap->data + 1); + } + cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_CAPABILITY, ies, ies_len); if (cap) { params->eht_cap = (void *)(cap->data + 1); if (!ieee80211_eht_capa_size_ok((const u8 *)params->he_cap, (const u8 *)params->eht_cap, - cap->datalen - 1, true)) + cap->datalen - 1, true)) { + GENL_SET_ERR_MSG(info, "bad EHT capability in beacon"); return -EINVAL; + } } return 0; @@ -6696,26 +6717,36 @@ static int nl80211_calculate_ap_operation(struct genl_info *info, nl80211_check_ap_rate_selectors(bcn, rates); op = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len); - if (op && op->datalen >= sizeof(*bcn->he_oper) + 1) { + if (op) { + if (op->datalen < sizeof(*bcn->he_oper) + 1) { + GENL_SET_ERR_MSG(info, "bad HE operation in beacon"); + return -EINVAL; + } bcn->he_oper = (void *)(op->data + 1); /* takes extension ID into account */ - if (op->datalen < ieee80211_he_oper_size((void *)bcn->he_oper)) + if (op->datalen < ieee80211_he_oper_size((void *)bcn->he_oper)) { + GENL_SET_ERR_MSG(info, "bad HE operation in beacon"); return -EINVAL; + } } op = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ies, ies_len); if (op) { if (!ieee80211_eht_oper_size_ok(op->data + 1, - op->datalen - 1)) + op->datalen - 1)) { + GENL_SET_ERR_MSG(info, "bad EHT operation in beacon"); return -EINVAL; + } bcn->eht_oper = (void *)(op->data + 1); } op = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len); if (op) { /* need full UHR operation separately */ - if (!info->attrs[NL80211_ATTR_UHR_OPERATION]) + if (!info->attrs[NL80211_ATTR_UHR_OPERATION]) { + GENL_SET_ERR_MSG(info, "missing UHR operation"); return -EINVAL; + } bcn->uhr_oper = nla_data(info->attrs[NL80211_ATTR_UHR_OPERATION]); } else if (info->attrs[NL80211_ATTR_UHR_OPERATION]) { GENL_SET_ERR_MSG(info, "unexpected UHR operation"); @@ -7156,7 +7187,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) goto out; } - err = nl80211_calculate_ap_capabilities(params); + err = nl80211_calculate_ap_capabilities(info, params); if (err) goto out;