ipvlan: hold lower dev to avoid possible use-after-free

Recently syzkaller discovered the issue of disappearing lower
device (NETDEV_UNREGISTER) while the virtual device (like
macvlan) is still having it as a lower device. So it's just
a matter of time similar discovery will be made for IPvlan
device setup. So fixing it preemptively. Also while at it,
add a refcount tracker.

Fixes: 2ad7bf3638 ("ipvlan: Initial check-in of the IPVLAN driver.")
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Mahesh Bandewar 2022-11-15 17:19:14 -08:00 committed by David S. Miller
parent 8207f253a0
commit 40b9d1ab63
2 changed files with 3 additions and 0 deletions

View file

@ -98,6 +98,7 @@ struct ipvl_port {
struct sk_buff_head backlog; struct sk_buff_head backlog;
int count; int count;
struct ida ida; struct ida ida;
netdevice_tracker dev_tracker;
}; };
struct ipvl_skb_cb { struct ipvl_skb_cb {

View file

@ -83,6 +83,7 @@ static int ipvlan_port_create(struct net_device *dev)
if (err) if (err)
goto err; goto err;
netdev_hold(dev, &port->dev_tracker, GFP_KERNEL);
return 0; return 0;
err: err:
@ -95,6 +96,7 @@ static void ipvlan_port_destroy(struct net_device *dev)
struct ipvl_port *port = ipvlan_port_get_rtnl(dev); struct ipvl_port *port = ipvlan_port_get_rtnl(dev);
struct sk_buff *skb; struct sk_buff *skb;
netdev_put(dev, &port->dev_tracker);
if (port->mode == IPVLAN_MODE_L3S) if (port->mode == IPVLAN_MODE_L3S)
ipvlan_l3s_unregister(port); ipvlan_l3s_unregister(port);
netdev_rx_handler_unregister(dev); netdev_rx_handler_unregister(dev);