]> git.dujemihanovic.xyz Git - linux.git/commitdiff
net: socket: rework SIOC?IFMAP ioctls
authorArnd Bergmann <arnd@arndb.de>
Thu, 22 Jul 2021 14:29:00 +0000 (16:29 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 23 Jul 2021 13:20:25 +0000 (14:20 +0100)
SIOCGIFMAP and SIOCSIFMAP currently require compat_alloc_user_space()
and copy_in_user() for compat mode.

Move the compat handling into the location where the structures are
actually used, to avoid using those interfaces and get a clearer
implementation.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/dev_ioctl.c
net/socket.c

index 478d032f34acaa80bce0e306c5f4eff01f4dd2b4..62f45da7ecfe3dd91cfb6d9e62138f1bbe918ce7 100644 (file)
@@ -98,6 +98,56 @@ int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
        return 0;
 }
 
+static int dev_getifmap(struct net_device *dev, struct ifreq *ifr)
+{
+       struct ifmap *ifmap = &ifr->ifr_map;
+
+       if (in_compat_syscall()) {
+               struct compat_ifmap *cifmap = (struct compat_ifmap *)ifmap;
+
+               cifmap->mem_start = dev->mem_start;
+               cifmap->mem_end   = dev->mem_end;
+               cifmap->base_addr = dev->base_addr;
+               cifmap->irq       = dev->irq;
+               cifmap->dma       = dev->dma;
+               cifmap->port      = dev->if_port;
+
+               return 0;
+       }
+
+       ifmap->mem_start  = dev->mem_start;
+       ifmap->mem_end    = dev->mem_end;
+       ifmap->base_addr  = dev->base_addr;
+       ifmap->irq        = dev->irq;
+       ifmap->dma        = dev->dma;
+       ifmap->port       = dev->if_port;
+
+       return 0;
+}
+
+static int dev_setifmap(struct net_device *dev, struct ifreq *ifr)
+{
+       struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map;
+
+       if (!dev->netdev_ops->ndo_set_config)
+               return -EOPNOTSUPP;
+
+       if (in_compat_syscall()) {
+               struct ifmap ifmap = {
+                       .mem_start  = cifmap->mem_start,
+                       .mem_end    = cifmap->mem_end,
+                       .base_addr  = cifmap->base_addr,
+                       .irq        = cifmap->irq,
+                       .dma        = cifmap->dma,
+                       .port       = cifmap->port,
+               };
+
+               return dev->netdev_ops->ndo_set_config(dev, &ifmap);
+       }
+
+       return dev->netdev_ops->ndo_set_config(dev, &ifr->ifr_map);
+}
+
 /*
  *     Perform the SIOCxIFxxx calls, inside rcu_read_lock()
  */
@@ -128,13 +178,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm
                break;
 
        case SIOCGIFMAP:
-               ifr->ifr_map.mem_start = dev->mem_start;
-               ifr->ifr_map.mem_end   = dev->mem_end;
-               ifr->ifr_map.base_addr = dev->base_addr;
-               ifr->ifr_map.irq       = dev->irq;
-               ifr->ifr_map.dma       = dev->dma;
-               ifr->ifr_map.port      = dev->if_port;
-               return 0;
+               return dev_getifmap(dev, ifr);
 
        case SIOCGIFINDEX:
                ifr->ifr_ifindex = dev->ifindex;
@@ -275,12 +319,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                return 0;
 
        case SIOCSIFMAP:
-               if (ops->ndo_set_config) {
-                       if (!netif_device_present(dev))
-                               return -ENODEV;
-                       return ops->ndo_set_config(dev, &ifr->ifr_map);
-               }
-               return -EOPNOTSUPP;
+               return dev_setifmap(dev, ifr);
 
        case SIOCADDMULTI:
                if (!ops->ndo_set_rx_mode ||
index ec63cf6de33e23ea3286a4f90d37b742efd9eead..62005a12ec70ba5b7a86328943c212043bb929e4 100644 (file)
@@ -3241,40 +3241,6 @@ static int compat_ifreq_ioctl(struct net *net, struct socket *sock,
        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)
-               return -EFAULT;
-
-       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;
-}
-
 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
  * for some operations; this forces use of the newer bridge-utils that
  * use compatible ioctls
@@ -3308,9 +3274,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
                return compat_dev_ifconf(net, argp);
        case SIOCWANDEV:
                return compat_siocwandev(net, argp);
-       case SIOCGIFMAP:
-       case SIOCSIFMAP:
-               return compat_sioc_ifmap(net, cmd, argp);
        case SIOCGSTAMP_OLD:
        case SIOCGSTAMPNS_OLD:
                if (!sock->ops->gettstamp)
@@ -3340,6 +3303,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
 
        case SIOCGIFFLAGS:
        case SIOCSIFFLAGS:
+       case SIOCGIFMAP:
+       case SIOCSIFMAP:
        case SIOCGIFMETRIC:
        case SIOCSIFMETRIC:
        case SIOCGIFMTU: