brcmfmac: fix double free upon register_netdevice() failure
authorArend Van Spriel <arend.vanspriel@broadcom.com>
Sat, 24 Jun 2017 21:08:27 +0000 (22:08 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 27 Jun 2017 14:13:57 +0000 (17:13 +0300)
The function brcmf_net_attach() can only fail when register_netdevice()
fails. When this happens register_netdevice() calls priv_destructor, ie.
brcmf_cfg80211_free_netdev() freeing the vif instance. Also upon this
failure brcmf_net_attach() calls free_netdev(). However, callers are also
doing cleanup resulting in double free. In some places they need netdev
private space as it holds parameters to communicate with the device. So
we want to do the cleanup only in callers of brcmf_net_attach() by making
the following changes:

 - set priv_destructor after register_netdevice() succeeds.
 - remove call to free_netdev() in brcmf_net_attach().
 - call free_netdev() in brcmf_net_detach() for unregistered netdev.
 - add free_netdev() if brcmf_net_attach() fails for a created interface.

Fixes: cf124db566e6 ("net: Fix inconsistent teardown and release of private netdev state.")
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c

index 2443c71a202f49bca066682bffb613be21f6e54c..63e7683a80dd52c60a712bbab00c8b31d8ff4619 100644 (file)
@@ -625,6 +625,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
        err = brcmf_net_attach(ifp, true);
        if (err) {
                brcmf_err("Registering netdevice failed\n");
+               free_netdev(ifp->ndev);
                goto fail;
        }
 
index c60b897e479a7973234c9266f96d3887bdd0b83c..b4c86434ad80a81fc06355b7e207e95a08b1d70a 100644 (file)
@@ -485,13 +485,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
                goto fail;
        }
 
+       ndev->priv_destructor = brcmf_cfg80211_free_netdev;
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
        return 0;
 
 fail:
        drvr->iflist[ifp->bsscfgidx] = NULL;
        ndev->netdev_ops = NULL;
-       free_netdev(ndev);
        return -EBADE;
 }
 
@@ -504,6 +504,7 @@ static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
                        unregister_netdev(ndev);
        } else {
                brcmf_cfg80211_free_netdev(ndev);
+               free_netdev(ndev);
        }
 }
 
@@ -580,7 +581,6 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
 fail:
        ifp->drvr->iflist[ifp->bsscfgidx] = NULL;
        ndev->netdev_ops = NULL;
-       free_netdev(ndev);
        return -EBADE;
 }
 
@@ -626,7 +626,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
                        return ERR_PTR(-ENOMEM);
 
                ndev->needs_free_netdev = true;
-               ndev->priv_destructor = brcmf_cfg80211_free_netdev;
                ifp = netdev_priv(ndev);
                ifp->ndev = ndev;
                /* store mapping ifidx to bsscfgidx */
index aa299c47bfa24e7cfc4af283efb29458ca90d11e..2ce675ab40ef867cf6a86ca5257a6db7ef76e80a 100644 (file)
@@ -2208,6 +2208,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
        err = brcmf_net_attach(ifp, true);
        if (err) {
                brcmf_err("Registering netdevice failed\n");
+               free_netdev(ifp->ndev);
                goto fail;
        }