mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	net: hold netdev instance lock during ndo_bpf
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>
This commit is contained in:
		
							parent
							
								
									ad7c7b2172
								
							
						
					
					
						commit
						97246d6d21
					
				
					 6 changed files with 33 additions and 4 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -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) | ||||
| { | ||||
|  | @ -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"); | ||||
|  | @ -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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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; | ||||
| 
 | ||||
|  | @ -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 | ||||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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> | ||||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Stanislav Fomichev
						Stanislav Fomichev