local/net: bcm4358: fix panic when unregistering p2p interface 38/118838/2 accepted/tizen_common accepted/tizen_ivi accepted/tizen_mobile accepted/tizen_tv accepted/tizen_wearable accepted/tizen/common/20170316.161713 accepted/tizen/ivi/20170316.101834 accepted/tizen/mobile/20170316.101734 accepted/tizen/tv/20170316.101804 accepted/tizen/unified/20170316.101853 accepted/tizen/wearable/20170316.101819 submit/tizen/20170316.045621
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 14 Mar 2017 07:48:23 +0000 (16:48 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 14 Mar 2017 08:34:49 +0000 (17:34 +0900)
When unregistering p2p interface, following kernel panic occurs:

   BUG: failure at mm/slub.c:3413/kfree()!
   Kernel panic - not syncing: BUG!
   CPU: 1 PID: 2698 Comm: wpa_supplicant Not tainted 4.1.36-arm64-tm2 #1
   ...
   [<ffffffc000a6bc78>] panic+0xf0/0x234
   [<ffffffc00019cc1c>] show_slab_objects+0x0/0x264
   [<ffffffc0009e2204>] nl80211_set_wowlan+0x748/0x81c
   ...

It is because kfree(wdev->wiphy->wowlan_config) is called from
cfg80211_rdev_free_wowlan(), but it is assigned with const struct
pointer from the commit c1cdee9f047f ("LOCAL / net: bcm4358: set
wowlan_config for broadcom driver"). So this patch fixes to assign
it with kmemdup.

Change-Id: Ia924d27d7f262dfd0b49d61ee0214f2ae24fb5c7
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
drivers/net/wireless/bcmdhd4358/wl_cfg80211.c

index 5d82e978aa9686997691f792ae37fc3e94f6682f..0cfe27ce2968e77f5079b4b5355451765c075309 100644 (file)
@@ -8322,7 +8322,7 @@ static const struct wiphy_wowlan_support brcm_wowlan_support = {
  * Fixed the WiFi disconnection issue during suspend when AP is connected
  * Refer to commit 6abb9cb99f33b20c
  */
-static struct cfg80211_wowlan brcm_wowlan_config = {
+static const struct cfg80211_wowlan brcm_wowlan_config = {
        .any = true,
 };
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
@@ -8331,6 +8331,11 @@ static struct cfg80211_wowlan brcm_wowlan_config = {
 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
 {
        s32 err = 0;
+#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+       struct cfg80211_wowlan *wowlan_config;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 10) */
+#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
        dhd_pub_t *dhd = (dhd_pub_t *)context;
        BCM_REFERENCE(dhd);
@@ -8458,7 +8463,15 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
        wdev->wiphy->wowlan = &brcm_wowlan_support;
-       wdev->wiphy->wowlan_config = &brcm_wowlan_config;
+
+       wowlan_config = kmemdup(&brcm_wowlan_config, sizeof(brcm_wowlan_config),
+                               GFP_KERNEL);
+       if (!wowlan_config) {
+               wiphy_free(wdev->wiphy);
+               return -ENOMEM;
+       }
+
+       wdev->wiphy->wowlan_config = wowlan_config;
 #else
        wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 10) */
@@ -8482,6 +8495,11 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
        err = wiphy_register(wdev->wiphy);
        if (unlikely(err < 0)) {
                WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+               kfree(wdev->wiphy->wowlan_config);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 10) */
+#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
                wiphy_free(wdev->wiphy);
        }