wifi: wfx: fix possible NULL pointer dereference in wfx_set_mfp_ap()
authorDmitry Antipov <dmantipov@yandex.ru>
Mon, 4 Dec 2023 17:11:28 +0000 (20:11 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Feb 2024 20:14:22 +0000 (20:14 +0000)
[ Upstream commit fe0a7776d4d19e613bb8dd80fe2d78ae49e8b49d ]

Since 'ieee80211_beacon_get()' can return NULL, 'wfx_set_mfp_ap()'
should check the return value before examining skb data. So convert
the latter to return an appropriate error code and propagate it to
return from 'wfx_start_ap()' as well. Compile tested only.

Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Tested-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Acked-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20231204171130.141394-1-dmantipov@yandex.ru
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/silabs/wfx/sta.c

index 626dfb4..073e870 100644 (file)
@@ -354,29 +354,38 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif)
        return 0;
 }
 
-static void wfx_set_mfp_ap(struct wfx_vif *wvif)
+static int wfx_set_mfp_ap(struct wfx_vif *wvif)
 {
        struct ieee80211_vif *vif = wvif_to_vif(wvif);
        struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0);
        const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
-       const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
-                                                skb->len - ieoffset);
        const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16);
        const int pairwise_cipher_suite_size = 4 / sizeof(u16);
        const int akm_suite_size = 4 / sizeof(u16);
+       const u16 *ptr;
 
-       if (ptr) {
-               ptr += pairwise_cipher_suite_count_offset;
-               if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
-                       return;
-               ptr += 1 + pairwise_cipher_suite_size * *ptr;
-               if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
-                       return;
-               ptr += 1 + akm_suite_size * *ptr;
-               if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
-                       return;
-               wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
-       }
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
+                                     skb->len - ieoffset);
+       if (unlikely(!ptr))
+               return -EINVAL;
+
+       ptr += pairwise_cipher_suite_count_offset;
+       if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+               return -EINVAL;
+
+       ptr += 1 + pairwise_cipher_suite_size * *ptr;
+       if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+               return -EINVAL;
+
+       ptr += 1 + akm_suite_size * *ptr;
+       if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+               return -EINVAL;
+
+       wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
+       return 0;
 }
 
 int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -394,8 +403,7 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        ret = wfx_hif_start(wvif, &vif->bss_conf, wvif->channel);
        if (ret > 0)
                return -EIO;
-       wfx_set_mfp_ap(wvif);
-       return ret;
+       return wfx_set_mfp_ap(wvif);
 }
 
 void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,