diff options
author | Gao Feng <fgao@ikuai8.com> | 2016-11-24 10:39:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-27 19:58:04 -0500 |
commit | 147fd2874d8a8ba69970f0069d67ac341bf0bb09 (patch) | |
tree | 0d0d55274d2a959655b004d15ac5d39bbf0de179 /drivers/net/ipvlan/ipvlan_main.c | |
parent | d8e435f3ab6fea2ea324dce72b51dd7761747523 (diff) |
driver: ipvlan: Fix one possible memleak in ipvlan_link_new
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>
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index f442eb366863..0fef17874d50 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
@@ -497,6 +497,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, | |||
497 | struct net_device *phy_dev; | 497 | struct net_device *phy_dev; |
498 | int err; | 498 | int err; |
499 | u16 mode = IPVLAN_MODE_L3; | 499 | u16 mode = IPVLAN_MODE_L3; |
500 | bool create = false; | ||
500 | 501 | ||
501 | if (!tb[IFLA_LINK]) | 502 | if (!tb[IFLA_LINK]) |
502 | return -EINVAL; | 503 | return -EINVAL; |
@@ -513,6 +514,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, | |||
513 | err = ipvlan_port_create(phy_dev); | 514 | err = ipvlan_port_create(phy_dev); |
514 | if (err < 0) | 515 | if (err < 0) |
515 | return err; | 516 | return err; |
517 | create = true; | ||
516 | } | 518 | } |
517 | 519 | ||
518 | if (data && data[IFLA_IPVLAN_MODE]) | 520 | if (data && data[IFLA_IPVLAN_MODE]) |
@@ -536,22 +538,27 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, | |||
536 | 538 | ||
537 | err = register_netdevice(dev); | 539 | err = register_netdevice(dev); |
538 | if (err < 0) | 540 | if (err < 0) |
539 | return err; | 541 | goto destroy_ipvlan_port; |
540 | 542 | ||
541 | err = netdev_upper_dev_link(phy_dev, dev); | 543 | err = netdev_upper_dev_link(phy_dev, dev); |
542 | if (err) { | 544 | if (err) { |
543 | unregister_netdevice(dev); | 545 | goto unregister_netdev; |
544 | return err; | ||
545 | } | 546 | } |
546 | err = ipvlan_set_port_mode(port, mode); | 547 | err = ipvlan_set_port_mode(port, mode); |
547 | if (err) { | 548 | if (err) { |
548 | unregister_netdevice(dev); | 549 | goto unregister_netdev; |
549 | return err; | ||
550 | } | 550 | } |
551 | 551 | ||
552 | list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); | 552 | list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); |
553 | netif_stacked_transfer_operstate(phy_dev, dev); | 553 | netif_stacked_transfer_operstate(phy_dev, dev); |
554 | return 0; | 554 | return 0; |
555 | |||
556 | unregister_netdev: | ||
557 | unregister_netdevice(dev); | ||
558 | destroy_ipvlan_port: | ||
559 | if (create) | ||
560 | ipvlan_port_destroy(phy_dev); | ||
561 | return err; | ||
555 | } | 562 | } |
556 | 563 | ||
557 | static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) | 564 | static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) |