driver: ipvlan: Fix one possible memleak in ipvlan_link_new
authorGao Feng <fgao@ikuai8.com>
Thu, 24 Nov 2016 15:39:59 +0000 (23:39 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Nov 2016 00:58:04 +0000 (19:58 -0500)
When ipvlan_link_new fails and creates one ipvlan port, it does not
destroy the ipvlan port created. It causes mem leak and the physical
device contains invalid ipvlan data.

Signed-off-by: Gao Feng <fgao@ikuai8.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ipvlan/ipvlan_main.c

index f442eb366863e034055c8cf773c9b4b0e287ae87..0fef17874d5031f48f186b639763a3b09b446d2e 100644 (file)
@@ -497,6 +497,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
        struct net_device *phy_dev;
        int err;
        u16 mode = IPVLAN_MODE_L3;
+       bool create = false;
 
        if (!tb[IFLA_LINK])
                return -EINVAL;
@@ -513,6 +514,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
                err = ipvlan_port_create(phy_dev);
                if (err < 0)
                        return err;
+               create = true;
        }
 
        if (data && data[IFLA_IPVLAN_MODE])
@@ -536,22 +538,27 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
 
        err = register_netdevice(dev);
        if (err < 0)
-               return err;
+               goto destroy_ipvlan_port;
 
        err = netdev_upper_dev_link(phy_dev, dev);
        if (err) {
-               unregister_netdevice(dev);
-               return err;
+               goto unregister_netdev;
        }
        err = ipvlan_set_port_mode(port, mode);
        if (err) {
-               unregister_netdevice(dev);
-               return err;
+               goto unregister_netdev;
        }
 
        list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
        netif_stacked_transfer_operstate(phy_dev, dev);
        return 0;
+
+unregister_netdev:
+       unregister_netdevice(dev);
+destroy_ipvlan_port:
+       if (create)
+               ipvlan_port_destroy(phy_dev);
+       return err;
 }
 
 static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)