Subject: linux-next: manual merge of the net-next tree with the net tree

From: Stephen Rothwell <[email-masked]>
Date: Mon, 30 Aug 2021 11:58:22 +1000

Hi all,

Today's linux-next merge of the net-next tree got conflicts in:

  include/linux/netdevice.h
  net/socket.c

between commit:

  d0efb16294d1 ("net: don't unconditionally copy_from_user a struct ifreq for socket ioctls")

from the net tree and commits:

  876f0bf9d0d5 ("net: socket: simplify dev_ifconf handling")
  29c4964822aa ("net: socket: rework compat_ifreq_ioctl()")

from the net-next tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc include/linux/netdevice.h
index d65ce093e5a7,6fd3a4d42668..000000000000
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@@ -4012,14 -4027,12 +4027,16 @@@ int netdev_rx_handler_register(struct n
  void netdev_rx_handler_unregister(struct net_device *dev);
  
  bool dev_valid_name(const char *name);
 +static inline bool is_socket_ioctl_cmd(unsigned int cmd)
 +{
 +	return _IOC_TYPE(cmd) == SOCK_IOC_TYPE;
 +}
+ int get_user_ifreq(struct ifreq *ifr, void __user **ifrdata, void __user *arg);
+ int put_user_ifreq(struct ifreq *ifr, void __user *arg);
  int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
- 		bool *need_copyout);
- int dev_ifconf(struct net *net, struct ifconf *, int);
- int dev_ethtool(struct net *net, struct ifreq *);
+ 		void __user *data, bool *need_copyout);
+ int dev_ifconf(struct net *net, struct ifconf __user *ifc);
+ int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata);
  unsigned int dev_get_flags(const struct net_device *);
  int __dev_change_flags(struct net_device *dev, unsigned int flags,
  		       struct netlink_ext_ack *extack);
diff --cc net/socket.c
index 8808b3617dac,3c10504e46d9..000000000000
--- a/net/socket.c
+++ b/net/socket.c
@@@ -1100,27 -1124,13 +1124,16 @@@ static long sock_do_ioctl(struct net *n
  	if (err != -ENOIOCTLCMD)
  		return err;
  
- 	if (cmd == SIOCGIFCONF) {
- 		struct ifconf ifc;
- 		if (copy_from_user(&ifc, argp, sizeof(struct ifconf)))
- 			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 if (is_socket_ioctl_cmd(cmd)) {
- 		struct ifreq ifr;
- 		bool need_copyout;
- 		if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
++	if (!is_socket_ioctl_cmd(cmd))
++		return -ENOTTY;
++
+ 	if (get_user_ifreq(&ifr, &data, argp))
+ 		return -EFAULT;
+ 	err = dev_ioctl(net, cmd, &ifr, data, &need_copyout);
+ 	if (!err && need_copyout)
+ 		if (put_user_ifreq(&ifr, argp))
  			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;
- 	} else {
- 		err = -ENOTTY;
- 	}
+ 
  	return err;
  }
  
@@@ -3306,99 -3216,13 +3219,15 @@@ static int compat_ifr_data_ioctl(struc
  				 struct compat_ifreq __user *u_ifreq32)
  {
  	struct ifreq ifreq;
- 	u32 data32;
+ 	void __user *data;
  
 +	if (!is_socket_ioctl_cmd(cmd))
 +		return -ENOTTY;
- 	if (copy_from_user(ifreq.ifr_name, u_ifreq32->ifr_name, IFNAMSIZ))
- 		return -EFAULT;
- 	if (get_user(data32, &u_ifreq32->ifr_data))
- 		return -EFAULT;
- 	ifreq.ifr_data = compat_ptr(data32);
- 
- 	return dev_ioctl(net, cmd, &ifreq, NULL);
- }
- 
- static int compat_ifreq_ioctl(struct net *net, struct socket *sock,
- 			      unsigned int cmd,
- 			      struct compat_ifreq __user *uifr32)
- {
- 	struct ifreq __user *uifr;
- 	int err;
- 
- 	/* Handle the fact that while struct ifreq has the same *layout* on
- 	 * 32/64 for everything but ifreq::ifru_ifmap and ifreq::ifru_data,
- 	 * which are handled elsewhere, it still has different *size* due to
- 	 * ifreq::ifru_ifmap (which is 16 bytes on 32 bit, 24 bytes on 64-bit,
- 	 * resulting in struct ifreq being 32 and 40 bytes respectively).
- 	 * As a result, if the struct happens to be at the end of a page and
- 	 * the next page isn't readable/writable, we get a fault. To prevent
- 	 * that, copy back and forth to the full size.
- 	 */
- 
- 	uifr = compat_alloc_user_space(sizeof(*uifr));
- 	if (copy_in_user(uifr, uifr32, sizeof(*uifr32)))
- 		return -EFAULT;
- 
- 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr);
- 
- 	if (!err) {
- 		switch (cmd) {
- 		case SIOCGIFFLAGS:
- 		case SIOCGIFMETRIC:
- 		case SIOCGIFMTU:
- 		case SIOCGIFMEM:
- 		case SIOCGIFHWADDR:
- 		case SIOCGIFINDEX:
- 		case SIOCGIFADDR:
- 		case SIOCGIFBRDADDR:
- 		case SIOCGIFDSTADDR:
- 		case SIOCGIFNETMASK:
- 		case SIOCGIFPFLAGS:
- 		case SIOCGIFTXQLEN:
- 		case SIOCGMIIPHY:
- 		case SIOCGMIIREG:
- 		case SIOCGIFNAME:
- 			if (copy_in_user(uifr32, uifr, sizeof(*uifr32)))
- 				err = -EFAULT;
- 			break;
- 		}
- 	}
- 	return err;
- }
- 
- static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
- 			struct compat_ifreq __user *uifr32)
- {
- 	struct ifreq ifr;
- 	struct compat_ifmap __user *uifmap32;
- 	int err;
- 
- 	uifmap32 = &uifr32->ifr_ifru.ifru_map;
- 	err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
- 	err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
- 	err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
- 	err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
- 	err |= get_user(ifr.ifr_map.irq, &uifmap32->irq);
- 	err |= get_user(ifr.ifr_map.dma, &uifmap32->dma);
- 	err |= get_user(ifr.ifr_map.port, &uifmap32->port);
- 	if (err)
+ 	if (get_user_ifreq(&ifreq, &data, u_ifreq32))
  		return -EFAULT;
+ 	ifreq.ifr_data = data;
  
- 	err = dev_ioctl(net, cmd, &ifr, NULL);
- 
- 	if (cmd == SIOCGIFMAP && !err) {
- 		err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
- 		err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
- 		err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
- 		err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
- 		err |= put_user(ifr.ifr_map.irq, &uifmap32->irq);
- 		err |= put_user(ifr.ifr_map.dma, &uifmap32->dma);
- 		err |= put_user(ifr.ifr_map.port, &uifmap32->port);
- 		if (err)
- 			err = -EFAULT;
- 	}
- 	return err;
+ 	return dev_ioctl(net, cmd, &ifreq, data, NULL);
  }
  
  /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE