forked from mirrors/linux
		
	net: socket: simplify dev_ifconf handling
The dev_ifconf() calling conventions make compat handling more complicated than necessary, simplify this by moving the in_compat_syscall() check into the function. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									b0e99d0377
								
							
						
					
					
						commit
						876f0bf9d0
					
				
					 3 changed files with 44 additions and 72 deletions
				
			
		|  | @ -4008,7 +4008,7 @@ void netdev_rx_handler_unregister(struct net_device *dev); | ||||||
| bool dev_valid_name(const char *name); | bool dev_valid_name(const char *name); | ||||||
| int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, | int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, | ||||||
| 		bool *need_copyout); | 		bool *need_copyout); | ||||||
| int dev_ifconf(struct net *net, struct ifconf *, int); | int dev_ifconf(struct net *net, struct ifconf __user *ifc); | ||||||
| int dev_ethtool(struct net *net, struct ifreq *); | int dev_ethtool(struct net *net, struct ifreq *); | ||||||
| unsigned int dev_get_flags(const struct net_device *); | unsigned int dev_get_flags(const struct net_device *); | ||||||
| int __dev_change_flags(struct net_device *dev, unsigned int flags, | int __dev_change_flags(struct net_device *dev, unsigned int flags, | ||||||
|  |  | ||||||
|  | @ -31,48 +31,51 @@ static int dev_ifname(struct net *net, struct ifreq *ifr) | ||||||
|  *	size eventually, and there is nothing I can do about it. |  *	size eventually, and there is nothing I can do about it. | ||||||
|  *	Thus we will need a 'compatibility mode'. |  *	Thus we will need a 'compatibility mode'. | ||||||
|  */ |  */ | ||||||
| 
 | int dev_ifconf(struct net *net, struct ifconf __user *uifc) | ||||||
| int dev_ifconf(struct net *net, struct ifconf *ifc, int size) |  | ||||||
| { | { | ||||||
| 	struct net_device *dev; | 	struct net_device *dev; | ||||||
| 	char __user *pos; | 	void __user *pos; | ||||||
| 	int len; | 	size_t size; | ||||||
| 	int total; | 	int len, total = 0, done; | ||||||
| 	int i; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/* both the ifconf and the ifreq structures are slightly different */ | ||||||
| 	 *	Fetch the caller's info block. | 	if (in_compat_syscall()) { | ||||||
| 	 */ | 		struct compat_ifconf ifc32; | ||||||
| 
 | 
 | ||||||
| 	pos = ifc->ifc_buf; | 		if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf))) | ||||||
| 	len = ifc->ifc_len; | 			return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 		pos = compat_ptr(ifc32.ifcbuf); | ||||||
| 	 *	Loop over the interfaces, and write an info block for each. | 		len = ifc32.ifc_len; | ||||||
| 	 */ | 		size = sizeof(struct compat_ifreq); | ||||||
|  | 	} else { | ||||||
|  | 		struct ifconf ifc; | ||||||
| 
 | 
 | ||||||
| 	total = 0; | 		if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 		pos = ifc.ifc_buf; | ||||||
|  | 		len = ifc.ifc_len; | ||||||
|  | 		size = sizeof(struct ifreq); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Loop over the interfaces, and write an info block for each. */ | ||||||
|  | 	rtnl_lock(); | ||||||
| 	for_each_netdev(net, dev) { | 	for_each_netdev(net, dev) { | ||||||
| 		int done; |  | ||||||
| 		if (!pos) | 		if (!pos) | ||||||
| 			done = inet_gifconf(dev, NULL, 0, size); | 			done = inet_gifconf(dev, NULL, 0, size); | ||||||
| 		else | 		else | ||||||
| 			done = inet_gifconf(dev, pos + total, | 			done = inet_gifconf(dev, pos + total, | ||||||
| 					    len - total, size); | 					    len - total, size); | ||||||
| 		if (done < 0) | 		if (done < 0) { | ||||||
|  | 			rtnl_unlock(); | ||||||
| 			return -EFAULT; | 			return -EFAULT; | ||||||
|  | 		} | ||||||
| 		total += done; | 		total += done; | ||||||
| 	} | 	} | ||||||
|  | 	rtnl_unlock(); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	return put_user(total, &uifc->ifc_len); | ||||||
| 	 *	All done.  Write the updated control block back to the caller. |  | ||||||
| 	 */ |  | ||||||
| 	ifc->ifc_len = total; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * 	Both BSD and Solaris return 0 here, so we do too. |  | ||||||
| 	 */ |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int dev_getifmap(struct net_device *dev, struct ifreq *ifr) | static int dev_getifmap(struct net_device *dev, struct ifreq *ifr) | ||||||
|  |  | ||||||
							
								
								
									
										59
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								net/socket.c
									
									
									
									
									
								
							|  | @ -1088,6 +1088,8 @@ EXPORT_SYMBOL(vlan_ioctl_set); | ||||||
| static long sock_do_ioctl(struct net *net, struct socket *sock, | static long sock_do_ioctl(struct net *net, struct socket *sock, | ||||||
| 			  unsigned int cmd, unsigned long arg) | 			  unsigned int cmd, unsigned long arg) | ||||||
| { | { | ||||||
|  | 	struct ifreq ifr; | ||||||
|  | 	bool need_copyout; | ||||||
| 	int err; | 	int err; | ||||||
| 	void __user *argp = (void __user *)arg; | 	void __user *argp = (void __user *)arg; | ||||||
| 
 | 
 | ||||||
|  | @ -1100,25 +1102,13 @@ static long sock_do_ioctl(struct net *net, struct socket *sock, | ||||||
| 	if (err != -ENOIOCTLCMD) | 	if (err != -ENOIOCTLCMD) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
| 	if (cmd == SIOCGIFCONF) { | 	if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) | ||||||
| 		struct ifconf ifc; | 		return -EFAULT; | ||||||
| 		if (copy_from_user(&ifc, argp, sizeof(struct ifconf))) | 	err = dev_ioctl(net, cmd, &ifr, &need_copyout); | ||||||
|  | 	if (!err && need_copyout) | ||||||
|  | 		if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) | ||||||
| 			return -EFAULT; | 			return -EFAULT; | ||||||
| 		rtnl_lock(); | 
 | ||||||
| 		err = dev_ifconf(net, &ifc, sizeof(struct ifreq)); |  | ||||||
| 		rtnl_unlock(); |  | ||||||
| 		if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf))) |  | ||||||
| 			err = -EFAULT; |  | ||||||
| 	} else { |  | ||||||
| 		struct ifreq ifr; |  | ||||||
| 		bool need_copyout; |  | ||||||
| 		if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		err = dev_ioctl(net, cmd, &ifr, &need_copyout); |  | ||||||
| 		if (!err && need_copyout) |  | ||||||
| 			if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) |  | ||||||
| 				return -EFAULT; |  | ||||||
| 	} |  | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1217,6 +1207,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | ||||||
| 						   cmd == SIOCGSTAMP_NEW, | 						   cmd == SIOCGSTAMP_NEW, | ||||||
| 						   false); | 						   false); | ||||||
| 			break; | 			break; | ||||||
|  | 
 | ||||||
|  | 		case SIOCGIFCONF: | ||||||
|  | 			err = dev_ifconf(net, argp); | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
| 		default: | 		default: | ||||||
| 			err = sock_do_ioctl(net, sock, cmd, arg); | 			err = sock_do_ioctl(net, sock, cmd, arg); | ||||||
| 			break; | 			break; | ||||||
|  | @ -3127,31 +3122,6 @@ void socket_seq_show(struct seq_file *seq) | ||||||
| #endif				/* CONFIG_PROC_FS */ | #endif				/* CONFIG_PROC_FS */ | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
| static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) |  | ||||||
| { |  | ||||||
| 	struct compat_ifconf ifc32; |  | ||||||
| 	struct ifconf ifc; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 
 |  | ||||||
| 	ifc.ifc_len = ifc32.ifc_len; |  | ||||||
| 	ifc.ifc_req = compat_ptr(ifc32.ifcbuf); |  | ||||||
| 
 |  | ||||||
| 	rtnl_lock(); |  | ||||||
| 	err = dev_ifconf(net, &ifc, sizeof(struct compat_ifreq)); |  | ||||||
| 	rtnl_unlock(); |  | ||||||
| 	if (err) |  | ||||||
| 		return err; |  | ||||||
| 
 |  | ||||||
| 	ifc32.ifc_len = ifc.ifc_len; |  | ||||||
| 	if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) | static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) | ||||||
| { | { | ||||||
| 	compat_uptr_t uptr32; | 	compat_uptr_t uptr32; | ||||||
|  | @ -3270,8 +3240,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | ||||||
| 	case SIOCSIFBR: | 	case SIOCSIFBR: | ||||||
| 	case SIOCGIFBR: | 	case SIOCGIFBR: | ||||||
| 		return old_bridge_ioctl(argp); | 		return old_bridge_ioctl(argp); | ||||||
| 	case SIOCGIFCONF: |  | ||||||
| 		return compat_dev_ifconf(net, argp); |  | ||||||
| 	case SIOCWANDEV: | 	case SIOCWANDEV: | ||||||
| 		return compat_siocwandev(net, argp); | 		return compat_siocwandev(net, argp); | ||||||
| 	case SIOCGSTAMP_OLD: | 	case SIOCGSTAMP_OLD: | ||||||
|  | @ -3299,6 +3267,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | ||||||
| 	case SIOCGSKNS: | 	case SIOCGSKNS: | ||||||
| 	case SIOCGSTAMP_NEW: | 	case SIOCGSTAMP_NEW: | ||||||
| 	case SIOCGSTAMPNS_NEW: | 	case SIOCGSTAMPNS_NEW: | ||||||
|  | 	case SIOCGIFCONF: | ||||||
| 		return sock_ioctl(file, cmd, arg); | 		return sock_ioctl(file, cmd, arg); | ||||||
| 
 | 
 | ||||||
| 	case SIOCGIFFLAGS: | 	case SIOCGIFFLAGS: | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Arnd Bergmann
						Arnd Bergmann