nxpwifi_update_bss_desc_with_ie() stores pointers to the HT, VHT and HE capability and operation elements, to the operating mode notification and to the 20/40 BSS coexistence element, taken from a beacon or probe response, without checking that each element is long enough for the structure the driver later dereferences it as. bss_desc->beacon_buf is a tight kmemdup() of the on-air elements, so a truncated element leaves the stored pointer short of the structure and the consumers read past the end of that allocation at association time. Some of those bytes are copied into the association request, so a rogue access point in range can both trigger the read and receive the result. Reject the frame with -EINVAL when any of these elements is shorter than the structure read from it, as the FH, DS and CF parameter set cases in the same parser already do. The extended capabilities element has no structure size to check against, so nxpwifi_is_ap_11ax_twt_supported()'s read of bcn_ext_cap->data[9] is bounded at that consumer instead. Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Assisted-by: LLM Signed-off-by: Aamir Ahmed --- v2: - drop Cc: stable; nxpwifi is not in a released kernel yet (Jeff) - cut the commit message down (Jeff) - Assisted-by: LLM, without the tool name - name the target tree in the subject v1: https://lore.kernel.org/linux-wireless/AS8P251MB00017FB955BDEFEEA1EA579BC8B32@AS8P251MB0001.EURP251.PROD.OUTLOOK.COM/ Tested on a KASAN kernel with a harness that feeds a short element stream ending in a zero-length HT capability element to the parser and then copies from bcn_ht_cap as the association path does: unpatched that copy trips a slab-out-of-bounds read, patched the parser returns -EINVAL and KASAN is silent. I have no IW61x hardware, so the over-the-air path was not exercised. drivers/net/wireless/nxp/nxpwifi/11ax.c | 2 ++ drivers/net/wireless/nxp/nxpwifi/scan.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/nxp/nxpwifi/11ax.c b/drivers/net/wireless/nxp/nxpwifi/11ax.c index 96540914f3cf..dc1e747383ec 100644 --- a/drivers/net/wireless/nxp/nxpwifi/11ax.c +++ b/drivers/net/wireless/nxp/nxpwifi/11ax.c @@ -402,6 +402,8 @@ static u8 nxpwifi_is_ap_11ax_twt_supported(struct nxpwifi_bssdescriptor *bss_des return false; ext_cap = (struct element *)bss_desc->bcn_ext_cap; + if (ext_cap->datalen < 10) + return false; if (!(ext_cap->data[9] & WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT)) return false; return true; diff --git a/drivers/net/wireless/nxp/nxpwifi/scan.c b/drivers/net/wireless/nxp/nxpwifi/scan.c index b77056983e83..d82ee8e502f6 100644 --- a/drivers/net/wireless/nxp/nxpwifi/scan.c +++ b/drivers/net/wireless/nxp/nxpwifi/scan.c @@ -1209,6 +1209,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, (u16)(current_ptr - bss_entry->beacon_buf); break; case WLAN_EID_HT_CAPABILITY: + if (element_len < sizeof(*bss_entry->bcn_ht_cap)) + return -EINVAL; bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)(current_ptr + elem_size); @@ -1217,6 +1219,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_HT_OPERATION: + if (element_len < sizeof(*bss_entry->bcn_ht_oper)) + return -EINVAL; bss_entry->bcn_ht_oper = (struct ieee80211_ht_operation *)(current_ptr + elem_size); @@ -1225,6 +1229,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_VHT_CAPABILITY: + if (element_len < sizeof(*bss_entry->bcn_vht_cap)) + return -EINVAL; bss_entry->disable_11ac = false; bss_entry->bcn_vht_cap = (void *)(current_ptr + elem_size); @@ -1233,6 +1239,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_VHT_OPERATION: + if (element_len < sizeof(*bss_entry->bcn_vht_oper)) + return -EINVAL; bss_entry->bcn_vht_oper = (void *)(current_ptr + elem_size); bss_entry->vht_info_offset = @@ -1240,6 +1248,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_BSS_COEX_2040: + if (!element_len) + return -EINVAL; bss_entry->bcn_bss_co_2040 = current_ptr; bss_entry->bss_co_2040_offset = (u16)(current_ptr - bss_entry->beacon_buf); @@ -1250,6 +1260,8 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, (u16)(current_ptr - bss_entry->beacon_buf); break; case WLAN_EID_OPMODE_NOTIF: + if (total_ie_len < sizeof(*bss_entry->oper_mode)) + return -EINVAL; bss_entry->oper_mode = (void *)current_ptr; bss_entry->oper_mode_offset = (u16)(current_ptr - bss_entry->beacon_buf); @@ -1262,6 +1274,9 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, switch (elem->data[0]) { case WLAN_EID_EXT_HE_CAPABILITY: + if (element_len < + 1 + sizeof(*bss_entry->bcn_he_cap)) + return -EINVAL; bss_entry->disable_11ax = false; bss_entry->bcn_he_cap = (void *)(current_ptr + elem_size + 1); @@ -1270,6 +1285,9 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_EXT_HE_OPERATION: + if (element_len < + 1 + sizeof(*bss_entry->bcn_he_oper)) + return -EINVAL; bss_entry->bcn_he_oper = (void *)(current_ptr + elem_size + 1); bss_entry->he_info_offset = base-commit: df2908090cda368b01ff43709f51890076c56157 -- 2.55.0