mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	net: hold netdev instance lock during ioctl operations
Convert all ndo_eth_ioctl invocations to dev_eth_ioctl which does the locking. Reflow some of the dev_siocxxx to drop else clause. Cc: Saeed Mahameed <saeed@kernel.org> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250305163732.2766420-8-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									7e4d784f58
								
							
						
					
					
						commit
						ffb7ed19ac
					
				
					 6 changed files with 80 additions and 37 deletions
				
			
		|  | @ -855,7 +855,6 @@ static int bond_check_dev_link(struct bonding *bond, | ||||||
| 			       struct net_device *slave_dev, int reporting) | 			       struct net_device *slave_dev, int reporting) | ||||||
| { | { | ||||||
| 	const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | 	const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | ||||||
| 	int (*ioctl)(struct net_device *, struct ifreq *, int); |  | ||||||
| 	struct ifreq ifr; | 	struct ifreq ifr; | ||||||
| 	struct mii_ioctl_data *mii; | 	struct mii_ioctl_data *mii; | ||||||
| 
 | 
 | ||||||
|  | @ -871,8 +870,7 @@ static int bond_check_dev_link(struct bonding *bond, | ||||||
| 			BMSR_LSTATUS : 0; | 			BMSR_LSTATUS : 0; | ||||||
| 
 | 
 | ||||||
| 	/* Ethtool can't be used, fallback to MII ioctls. */ | 	/* Ethtool can't be used, fallback to MII ioctls. */ | ||||||
| 	ioctl = slave_ops->ndo_eth_ioctl; | 	if (slave_ops->ndo_eth_ioctl) { | ||||||
| 	if (ioctl) { |  | ||||||
| 		/* TODO: set pointer to correct ioctl on a per team member
 | 		/* TODO: set pointer to correct ioctl on a per team member
 | ||||||
| 		 *       bases to make this more efficient. that is, once | 		 *       bases to make this more efficient. that is, once | ||||||
| 		 *       we determine the correct ioctl, we will always | 		 *       we determine the correct ioctl, we will always | ||||||
|  | @ -888,9 +886,10 @@ static int bond_check_dev_link(struct bonding *bond, | ||||||
| 		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */ | 		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */ | ||||||
| 		strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ); | 		strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ); | ||||||
| 		mii = if_mii(&ifr); | 		mii = if_mii(&ifr); | ||||||
| 		if (ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) { | 
 | ||||||
|  | 		if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) { | ||||||
| 			mii->reg_num = MII_BMSR; | 			mii->reg_num = MII_BMSR; | ||||||
| 			if (ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0) | 			if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0) | ||||||
| 				return mii->val_out & BMSR_LSTATUS; | 				return mii->val_out & BMSR_LSTATUS; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -4229,6 +4229,8 @@ int put_user_ifreq(struct ifreq *ifr, void __user *arg); | ||||||
| int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, | int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, | ||||||
| 		void __user *data, bool *need_copyout); | 		void __user *data, bool *need_copyout); | ||||||
| int dev_ifconf(struct net *net, struct ifconf __user *ifc); | int dev_ifconf(struct net *net, struct ifconf __user *ifc); | ||||||
|  | int dev_eth_ioctl(struct net_device *dev, | ||||||
|  | 		  struct ifreq *ifr, unsigned int cmd); | ||||||
| int generic_hwtstamp_get_lower(struct net_device *dev, | int generic_hwtstamp_get_lower(struct net_device *dev, | ||||||
| 			       struct kernel_hwtstamp_config *kernel_cfg); | 			       struct kernel_hwtstamp_config *kernel_cfg); | ||||||
| int generic_hwtstamp_set_lower(struct net_device *dev, | int generic_hwtstamp_set_lower(struct net_device *dev, | ||||||
|  | @ -4251,6 +4253,7 @@ int netif_change_net_namespace(struct net_device *dev, struct net *net, | ||||||
| int dev_change_net_namespace(struct net_device *dev, struct net *net, | int dev_change_net_namespace(struct net_device *dev, struct net *net, | ||||||
| 			     const char *pat); | 			     const char *pat); | ||||||
| int __dev_set_mtu(struct net_device *, int); | int __dev_set_mtu(struct net_device *, int); | ||||||
|  | int netif_set_mtu(struct net_device *dev, int new_mtu); | ||||||
| int dev_set_mtu(struct net_device *, int); | int dev_set_mtu(struct net_device *, int); | ||||||
| int dev_pre_changeaddr_notify(struct net_device *dev, const char *addr, | int dev_pre_changeaddr_notify(struct net_device *dev, const char *addr, | ||||||
| 			      struct netlink_ext_ack *extack); | 			      struct netlink_ext_ack *extack); | ||||||
|  |  | ||||||
|  | @ -377,7 +377,6 @@ static int vlan_hwtstamp_set(struct net_device *dev, | ||||||
| static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| { | { | ||||||
| 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; | 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; | ||||||
| 	const struct net_device_ops *ops = real_dev->netdev_ops; |  | ||||||
| 	struct ifreq ifrr; | 	struct ifreq ifrr; | ||||||
| 	int err = -EOPNOTSUPP; | 	int err = -EOPNOTSUPP; | ||||||
| 
 | 
 | ||||||
|  | @ -388,8 +387,7 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||||||
| 	case SIOCGMIIPHY: | 	case SIOCGMIIPHY: | ||||||
| 	case SIOCGMIIREG: | 	case SIOCGMIIREG: | ||||||
| 	case SIOCSMIIREG: | 	case SIOCSMIIREG: | ||||||
| 		if (netif_device_present(real_dev) && ops->ndo_eth_ioctl) | 		err = dev_eth_ioctl(real_dev, &ifrr, cmd); | ||||||
| 			err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd); |  | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9522,7 +9522,7 @@ int netif_set_mtu_ext(struct net_device *dev, int new_mtu, | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int dev_set_mtu(struct net_device *dev, int new_mtu) | int netif_set_mtu(struct net_device *dev, int new_mtu) | ||||||
| { | { | ||||||
| 	struct netlink_ext_ack extack; | 	struct netlink_ext_ack extack; | ||||||
| 	int err; | 	int err; | ||||||
|  | @ -9533,7 +9533,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) | ||||||
| 		net_err_ratelimited("%s: %s\n", dev->name, extack._msg); | 		net_err_ratelimited("%s: %s\n", dev->name, extack._msg); | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(dev_set_mtu); | EXPORT_SYMBOL(netif_set_mtu); | ||||||
| 
 | 
 | ||||||
| int netif_change_tx_queue_len(struct net_device *dev, unsigned long new_len) | int netif_change_tx_queue_len(struct net_device *dev, unsigned long new_len) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -222,3 +222,33 @@ void dev_close(struct net_device *dev) | ||||||
| 	netdev_unlock_ops(dev); | 	netdev_unlock_ops(dev); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(dev_close); | EXPORT_SYMBOL(dev_close); | ||||||
|  | 
 | ||||||
|  | int dev_eth_ioctl(struct net_device *dev, | ||||||
|  | 		  struct ifreq *ifr, unsigned int cmd) | ||||||
|  | { | ||||||
|  | 	const struct net_device_ops *ops = dev->netdev_ops; | ||||||
|  | 	int ret = -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	if (!ops->ndo_eth_ioctl) | ||||||
|  | 		return -EOPNOTSUPP; | ||||||
|  | 
 | ||||||
|  | 	netdev_lock_ops(dev); | ||||||
|  | 	if (netif_device_present(dev)) | ||||||
|  | 		ret = ops->ndo_eth_ioctl(dev, ifr, cmd); | ||||||
|  | 	netdev_unlock_ops(dev); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(dev_eth_ioctl); | ||||||
|  | 
 | ||||||
|  | int dev_set_mtu(struct net_device *dev, int new_mtu) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	netdev_lock_ops(dev); | ||||||
|  | 	ret = netif_set_mtu(dev, new_mtu); | ||||||
|  | 	netdev_unlock_ops(dev); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(dev_set_mtu); | ||||||
|  |  | ||||||
|  | @ -110,7 +110,7 @@ static int dev_getifmap(struct net_device *dev, struct ifreq *ifr) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int dev_setifmap(struct net_device *dev, struct ifreq *ifr) | static int netif_setifmap(struct net_device *dev, struct ifreq *ifr) | ||||||
| { | { | ||||||
| 	struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map; | 	struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map; | ||||||
| 
 | 
 | ||||||
|  | @ -240,20 +240,6 @@ int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int dev_eth_ioctl(struct net_device *dev, |  | ||||||
| 			 struct ifreq *ifr, unsigned int cmd) |  | ||||||
| { |  | ||||||
| 	const struct net_device_ops *ops = dev->netdev_ops; |  | ||||||
| 
 |  | ||||||
| 	if (!ops->ndo_eth_ioctl) |  | ||||||
| 		return -EOPNOTSUPP; |  | ||||||
| 
 |  | ||||||
| 	if (!netif_device_present(dev)) |  | ||||||
| 		return -ENODEV; |  | ||||||
| 
 |  | ||||||
| 	return ops->ndo_eth_ioctl(dev, ifr, cmd); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC |  * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC | ||||||
|  *	or of attached phylib PHY |  *	or of attached phylib PHY | ||||||
|  | @ -305,7 +291,9 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	kernel_cfg.ifr = ifr; | 	kernel_cfg.ifr = ifr; | ||||||
|  | 	netdev_lock_ops(dev); | ||||||
| 	err = dev_get_hwtstamp_phylib(dev, &kernel_cfg); | 	err = dev_get_hwtstamp_phylib(dev, &kernel_cfg); | ||||||
|  | 	netdev_unlock_ops(dev); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
|  | @ -429,7 +417,9 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr) | ||||||
| 	if (!netif_device_present(dev)) | 	if (!netif_device_present(dev)) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
|  | 	netdev_lock_ops(dev); | ||||||
| 	err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack); | 	err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack); | ||||||
|  | 	netdev_unlock_ops(dev); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
|  | @ -504,10 +494,14 @@ static int dev_siocbond(struct net_device *dev, | ||||||
| 	const struct net_device_ops *ops = dev->netdev_ops; | 	const struct net_device_ops *ops = dev->netdev_ops; | ||||||
| 
 | 
 | ||||||
| 	if (ops->ndo_siocbond) { | 	if (ops->ndo_siocbond) { | ||||||
|  | 		int ret = -ENODEV; | ||||||
|  | 
 | ||||||
|  | 		netdev_lock_ops(dev); | ||||||
| 		if (netif_device_present(dev)) | 		if (netif_device_present(dev)) | ||||||
| 			return ops->ndo_siocbond(dev, ifr, cmd); | 			ret = ops->ndo_siocbond(dev, ifr, cmd); | ||||||
| 		else | 		netdev_unlock_ops(dev); | ||||||
| 			return -ENODEV; | 
 | ||||||
|  | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return -EOPNOTSUPP; | 	return -EOPNOTSUPP; | ||||||
|  | @ -519,10 +513,14 @@ static int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr, | ||||||
| 	const struct net_device_ops *ops = dev->netdev_ops; | 	const struct net_device_ops *ops = dev->netdev_ops; | ||||||
| 
 | 
 | ||||||
| 	if (ops->ndo_siocdevprivate) { | 	if (ops->ndo_siocdevprivate) { | ||||||
|  | 		int ret = -ENODEV; | ||||||
|  | 
 | ||||||
|  | 		netdev_lock_ops(dev); | ||||||
| 		if (netif_device_present(dev)) | 		if (netif_device_present(dev)) | ||||||
| 			return ops->ndo_siocdevprivate(dev, ifr, data, cmd); | 			ret = ops->ndo_siocdevprivate(dev, ifr, data, cmd); | ||||||
| 		else | 		netdev_unlock_ops(dev); | ||||||
| 			return -ENODEV; | 
 | ||||||
|  | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return -EOPNOTSUPP; | 	return -EOPNOTSUPP; | ||||||
|  | @ -533,10 +531,14 @@ static int dev_siocwandev(struct net_device *dev, struct if_settings *ifs) | ||||||
| 	const struct net_device_ops *ops = dev->netdev_ops; | 	const struct net_device_ops *ops = dev->netdev_ops; | ||||||
| 
 | 
 | ||||||
| 	if (ops->ndo_siocwandev) { | 	if (ops->ndo_siocwandev) { | ||||||
|  | 		int ret = -ENODEV; | ||||||
|  | 
 | ||||||
|  | 		netdev_lock_ops(dev); | ||||||
| 		if (netif_device_present(dev)) | 		if (netif_device_present(dev)) | ||||||
| 			return ops->ndo_siocwandev(dev, ifs); | 			ret = ops->ndo_siocwandev(dev, ifs); | ||||||
| 		else | 		netdev_unlock_ops(dev); | ||||||
| 			return -ENODEV; | 
 | ||||||
|  | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return -EOPNOTSUPP; | 	return -EOPNOTSUPP; | ||||||
|  | @ -580,11 +582,16 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, | ||||||
| 		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, | 		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, | ||||||
| 		       min(sizeof(ifr->ifr_hwaddr.sa_data_min), | 		       min(sizeof(ifr->ifr_hwaddr.sa_data_min), | ||||||
| 			   (size_t)dev->addr_len)); | 			   (size_t)dev->addr_len)); | ||||||
|  | 		netdev_lock_ops(dev); | ||||||
| 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||||||
|  | 		netdev_unlock_ops(dev); | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	case SIOCSIFMAP: | 	case SIOCSIFMAP: | ||||||
| 		return dev_setifmap(dev, ifr); | 		netdev_lock_ops(dev); | ||||||
|  | 		err = netif_setifmap(dev, ifr); | ||||||
|  | 		netdev_unlock_ops(dev); | ||||||
|  | 		return err; | ||||||
| 
 | 
 | ||||||
| 	case SIOCADDMULTI: | 	case SIOCADDMULTI: | ||||||
| 		if (!ops->ndo_set_rx_mode || | 		if (!ops->ndo_set_rx_mode || | ||||||
|  | @ -592,7 +599,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		if (!netif_device_present(dev)) | 		if (!netif_device_present(dev)) | ||||||
| 			return -ENODEV; | 			return -ENODEV; | ||||||
| 		return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data); | 		netdev_lock_ops(dev); | ||||||
|  | 		err = dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data); | ||||||
|  | 		netdev_unlock_ops(dev); | ||||||
|  | 		return err; | ||||||
| 
 | 
 | ||||||
| 	case SIOCDELMULTI: | 	case SIOCDELMULTI: | ||||||
| 		if (!ops->ndo_set_rx_mode || | 		if (!ops->ndo_set_rx_mode || | ||||||
|  | @ -600,7 +610,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		if (!netif_device_present(dev)) | 		if (!netif_device_present(dev)) | ||||||
| 			return -ENODEV; | 			return -ENODEV; | ||||||
| 		return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data); | 		netdev_lock_ops(dev); | ||||||
|  | 		err = dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data); | ||||||
|  | 		netdev_unlock_ops(dev); | ||||||
|  | 		return err; | ||||||
| 
 | 
 | ||||||
| 	case SIOCSIFTXQLEN: | 	case SIOCSIFTXQLEN: | ||||||
| 		if (ifr->ifr_qlen < 0) | 		if (ifr->ifr_qlen < 0) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Stanislav Fomichev
						Stanislav Fomichev