aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2022-03-14 10:06:54 +0000
committerDavid S. Miller <davem@davemloft.net>2022-03-14 10:06:54 +0000
commitd96657dc9238f8e9bda47b377e17e7c6f90935af (patch)
tree016666de92847148d489058102bdd5023d62869b
parentMerge tag 'linux-can-next-for-5.18-20220313' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next (diff)
parentnet: macvlan: add net device refcount tracker (diff)
downloadwireguard-linux-d96657dc9238f8e9bda47b377e17e7c6f90935af.tar.xz
wireguard-linux-d96657dc9238f8e9bda47b377e17e7c6f90935af.zip
Merge branch 'macvlan-uaf'
Ziyang Xuan says: ==================== net: macvlan: fix potential UAF problem for lowerdev Add the reference operation to lowerdev of macvlan to avoid the potential UAF problem under the following known scenario: Someone module puts the NETDEV_UNREGISTER event handler to a work, and lowerdev is accessed in the work handler. But when the work is excuted, lowerdev has been destroyed because upper macvlan did not get reference to lowerdev correctly. In addition, add net device refcount tracker to macvlan. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/macvlan.c14
-rw-r--r--include/linux/if_macvlan.h1
2 files changed, 14 insertions, 1 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 4b77819e9328..069e8824c264 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -889,7 +889,7 @@ static void macvlan_set_lockdep_class(struct net_device *dev)
static int macvlan_init(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- const struct net_device *lowerdev = vlan->lowerdev;
+ struct net_device *lowerdev = vlan->lowerdev;
struct macvlan_port *port = vlan->port;
dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
@@ -911,6 +911,9 @@ static int macvlan_init(struct net_device *dev)
port->count += 1;
+ /* Get macvlan's reference to lowerdev */
+ dev_hold_track(lowerdev, &vlan->dev_tracker, GFP_KERNEL);
+
return 0;
}
@@ -1173,6 +1176,14 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_features_check = passthru_features_check,
};
+static void macvlan_dev_free(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ /* Get rid of the macvlan's reference to lowerdev */
+ dev_put_track(vlan->lowerdev, &vlan->dev_tracker);
+}
+
void macvlan_common_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -1184,6 +1195,7 @@ void macvlan_common_setup(struct net_device *dev)
dev->priv_flags |= IFF_UNICAST_FLT | IFF_CHANGE_PROTO_DOWN;
dev->netdev_ops = &macvlan_netdev_ops;
dev->needs_free_netdev = true;
+ dev->priv_destructor = macvlan_dev_free;
dev->header_ops = &macvlan_hard_header_ops;
dev->ethtool_ops = &macvlan_ethtool_ops;
}
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 10c94a3936ca..b42294739063 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -21,6 +21,7 @@ struct macvlan_dev {
struct hlist_node hlist;
struct macvlan_port *port;
struct net_device *lowerdev;
+ netdevice_tracker dev_tracker;
void *accel_priv;
struct vlan_pcpu_stats __percpu *pcpu_stats;