Skip to content

Commit

Permalink
net: hold netdev instance lock during ndo_bpf
Browse files Browse the repository at this point in the history
Cover the paths that come via bpf system call and XSK bind.

Cc: Saeed Mahameed <saeed@kernel.org>
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20250305163732.2766420-10-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Stanislav Fomichev authored and Jakub Kicinski committed Mar 6, 2025
1 parent ad7c7b2 commit 97246d6
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 4 deletions.
1 change: 1 addition & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -4277,6 +4277,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,

int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
u8 dev_xdp_prog_count(struct net_device *dev);
int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
u8 dev_xdp_sb_prog_count(struct net_device *dev);
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
Expand Down
6 changes: 4 additions & 2 deletions kernel/bpf/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,10 @@ struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)
return ERR_PTR(-ENOMEM);

bpf_map_init_from_attr(&offmap->map, attr);

rtnl_lock();
down_write(&bpf_devs_lock);
offmap->netdev = __dev_get_by_index(net, attr->map_ifindex);
netdev_lock_ops(offmap->netdev);
down_write(&bpf_devs_lock);
err = bpf_dev_offload_check(offmap->netdev);
if (err)
goto err_unlock;
Expand All @@ -548,12 +548,14 @@ struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)

list_add_tail(&offmap->offloads, &ondev->maps);
up_write(&bpf_devs_lock);
netdev_unlock_ops(offmap->netdev);
rtnl_unlock();

return &offmap->map;

err_unlock:
up_write(&bpf_devs_lock);
netdev_unlock_ops(offmap->netdev);
rtnl_unlock();
bpf_map_area_free(offmap);
return ERR_PTR(err);
Expand Down
13 changes: 11 additions & 2 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -9852,7 +9852,7 @@ u8 dev_xdp_sb_prog_count(struct net_device *dev)
return count;
}

int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
{
if (!dev->netdev_ops->ndo_bpf)
return -EOPNOTSUPP;
Expand All @@ -9872,7 +9872,6 @@ int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)

return dev->netdev_ops->ndo_bpf(dev, bpf);
}
EXPORT_SYMBOL_GPL(dev_xdp_propagate);

u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
{
Expand Down Expand Up @@ -9902,6 +9901,8 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
struct netdev_bpf xdp;
int err;

netdev_ops_assert_locked(dev);

if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
prog && !prog->aux->xdp_has_frags) {
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
Expand Down Expand Up @@ -10134,7 +10135,9 @@ static void bpf_xdp_link_release(struct bpf_link *link)
* already NULL, in which case link was already auto-detached
*/
if (xdp_link->dev) {
netdev_lock_ops(xdp_link->dev);
WARN_ON(dev_xdp_detach_link(xdp_link->dev, NULL, xdp_link));
netdev_unlock_ops(xdp_link->dev);
xdp_link->dev = NULL;
}

Expand Down Expand Up @@ -10216,10 +10219,12 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
goto out_unlock;
}

netdev_lock_ops(xdp_link->dev);
mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags);
bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode);
err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL,
xdp_link->flags, new_prog);
netdev_unlock_ops(xdp_link->dev);
if (err)
goto out_unlock;

Expand Down Expand Up @@ -11005,7 +11010,9 @@ int register_netdevice(struct net_device *dev)
if (ret)
goto err_uninit_notify;

netdev_lock_ops(dev);
__netdev_update_features(dev);
netdev_unlock_ops(dev);

/*
* Default initial state at registry is that the
Expand Down Expand Up @@ -11945,7 +11952,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
/* Shutdown queueing discipline. */
dev_shutdown(dev);
dev_tcx_uninstall(dev);
netdev_lock_ops(dev);
dev_xdp_uninstall(dev);
netdev_unlock_ops(dev);
bpf_dev_bound_netdev_unregister(dev);
dev_memory_provider_uninstall(dev);

Expand Down
12 changes: 12 additions & 0 deletions net/core/dev_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,15 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
return ret;
}
EXPORT_SYMBOL(dev_set_mac_address);

int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
{
int ret;

netdev_lock_ops(dev);
ret = netif_xdp_propagate(dev, bpf);
netdev_unlock_ops(dev);

return ret;
}
EXPORT_SYMBOL_GPL(dev_xdp_propagate);
3 changes: 3 additions & 0 deletions net/xdp/xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
goto out_release;
}

netdev_lock_ops(dev);

if (!xs->rx && !xs->tx) {
err = -EINVAL;
goto out_unlock;
Expand Down Expand Up @@ -1315,6 +1317,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
smp_wmb();
WRITE_ONCE(xs->state, XSK_BOUND);
}
netdev_unlock_ops(dev);
out_release:
mutex_unlock(&xs->mutex);
rtnl_unlock();
Expand Down
2 changes: 2 additions & 0 deletions net/xdp/xsk_buff_pool.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/netdevice.h>
#include <net/xsk_buff_pool.h>
#include <net/xdp_sock.h>
#include <net/xdp_sock_drv.h>
Expand Down Expand Up @@ -219,6 +220,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
bpf.xsk.pool = pool;
bpf.xsk.queue_id = queue_id;

netdev_ops_assert_locked(netdev);
err = netdev->netdev_ops->ndo_bpf(netdev, &bpf);
if (err)
goto err_unreg_pool;
Expand Down

0 comments on commit 97246d6

Please sign in to comment.