ipv4,appletalk: move SIOCADDRT and SIOCDELRT handling into ->compat_ioctl
authorChristoph Hellwig <hch@lst.de>
Mon, 18 May 2020 06:28:08 +0000 (08:28 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 May 2020 00:35:02 +0000 (17:35 -0700)
To prepare removing the global routing_ioctl hack start lifting the code
into the ipv4 and appletalk ->compat_ioctl handlers.  Unlike the existing
handler we don't bother copying in the name - there are no compat issues for
char arrays.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/compat.h
net/appletalk/ddp.c
net/ipv4/af_inet.c
net/socket.c

index e341260642feedd7cc77f22a4a5c7915e7d07d31..2b5e1f7ba153366e628e45ec73f31a63d511ce27 100644 (file)
@@ -30,6 +30,24 @@ struct compat_cmsghdr {
        compat_int_t    cmsg_type;
 };
 
+struct compat_rtentry {
+       u32             rt_pad1;
+       struct sockaddr rt_dst;         /* target address               */
+       struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+       struct sockaddr rt_genmask;     /* target network mask (IP)     */
+       unsigned short  rt_flags;
+       short           rt_pad2;
+       u32             rt_pad3;
+       unsigned char   rt_tos;
+       unsigned char   rt_class;
+       short           rt_pad4;
+       short           rt_metric;      /* +1 for binary compatibility! */
+       compat_uptr_t   rt_dev;         /* forcing the device at add    */
+       u32             rt_mtu;         /* per route MTU/Window         */
+       u32             rt_window;      /* Window clamping              */
+       unsigned short  rt_irtt;        /* Initial RTT                  */
+};
+
 #else /* defined(CONFIG_COMPAT) */
 /*
  * To avoid compiler warnings:
index 4177a74f65436fb4379ebfd20bb277cc280844a3..15787e8c0629a094e88f0a4205173985ce0ef30e 100644 (file)
@@ -57,6 +57,7 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <net/route.h>
+#include <net/compat.h>
 #include <linux/atalk.h>
 #include <linux/highmem.h>
 
@@ -1839,20 +1840,58 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 
 #ifdef CONFIG_COMPAT
+static int atalk_compat_routing_ioctl(struct sock *sk, unsigned int cmd,
+               struct compat_rtentry __user *ur)
+{
+       compat_uptr_t rtdev;
+       struct rtentry rt;
+
+       if (copy_from_user(&rt.rt_dst, &ur->rt_dst,
+                       3 * sizeof(struct sockaddr)) ||
+           get_user(rt.rt_flags, &ur->rt_flags) ||
+           get_user(rt.rt_metric, &ur->rt_metric) ||
+           get_user(rt.rt_mtu, &ur->rt_mtu) ||
+           get_user(rt.rt_window, &ur->rt_window) ||
+           get_user(rt.rt_irtt, &ur->rt_irtt) ||
+           get_user(rtdev, &ur->rt_dev))
+               return -EFAULT;
+
+       switch (cmd) {
+       case SIOCDELRT:
+               if (rt.rt_dst.sa_family != AF_APPLETALK)
+                       return -EINVAL;
+               return atrtr_delete(&((struct sockaddr_at *)
+                                     &rt.rt_dst)->sat_addr);
+
+       case SIOCADDRT:
+               rt.rt_dev = compat_ptr(rtdev);
+               return atrtr_ioctl_addrt(&rt);
+       default:
+               return -EINVAL;
+       }
+}
 static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
+       void __user *argp = compat_ptr(arg);
+       struct sock *sk = sock->sk;
+
+       switch (cmd) {
+       case SIOCADDRT:
+       case SIOCDELRT:
+               return atalk_compat_routing_ioctl(sk, cmd, argp);
        /*
         * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we
         * cannot handle it in common code. The data we access if ifreq
         * here is compatible, so we can simply call the native
         * handler.
         */
-       if (cmd == SIOCATALKDIFADDR)
-               return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
-
-       return -ENOIOCTLCMD;
+       case SIOCATALKDIFADDR:
+               return atalk_ioctl(sock, cmd, (unsigned long)argp);
+       default:
+               return -ENOIOCTLCMD;
+       }
 }
-#endif
+#endif /* CONFIG_COMPAT */
 
 
 static const struct net_proto_family atalk_family_ops = {
index fcf0d12a407a90a5ae54a5539b51a5e4429dcdcc..c35a8b2e0499e3f70d531246065aa5555bf23a0e 100644 (file)
 #include <linux/mroute.h>
 #endif
 #include <net/l3mdev.h>
+#include <net/compat.h>
 
 #include <trace/events/sock.h>
 
@@ -970,17 +971,42 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 EXPORT_SYMBOL(inet_ioctl);
 
 #ifdef CONFIG_COMPAT
+static int inet_compat_routing_ioctl(struct sock *sk, unsigned int cmd,
+               struct compat_rtentry __user *ur)
+{
+       compat_uptr_t rtdev;
+       struct rtentry rt;
+
+       if (copy_from_user(&rt.rt_dst, &ur->rt_dst,
+                       3 * sizeof(struct sockaddr)) ||
+           get_user(rt.rt_flags, &ur->rt_flags) ||
+           get_user(rt.rt_metric, &ur->rt_metric) ||
+           get_user(rt.rt_mtu, &ur->rt_mtu) ||
+           get_user(rt.rt_window, &ur->rt_window) ||
+           get_user(rt.rt_irtt, &ur->rt_irtt) ||
+           get_user(rtdev, &ur->rt_dev))
+               return -EFAULT;
+
+       rt.rt_dev = compat_ptr(rtdev);
+       return ip_rt_ioctl(sock_net(sk), cmd, &rt);
+}
+
 static int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
+       void __user *argp = compat_ptr(arg);
        struct sock *sk = sock->sk;
-       int err = -ENOIOCTLCMD;
-
-       if (sk->sk_prot->compat_ioctl)
-               err = sk->sk_prot->compat_ioctl(sk, cmd, arg);
 
-       return err;
+       switch (cmd) {
+       case SIOCADDRT:
+       case SIOCDELRT:
+               return inet_compat_routing_ioctl(sk, cmd, argp);
+       default:
+               if (!sk->sk_prot->compat_ioctl)
+                       return -ENOIOCTLCMD;
+               return sk->sk_prot->compat_ioctl(sk, cmd, arg);
+       }
 }
-#endif
+#endif /* CONFIG_COMPAT */
 
 const struct proto_ops inet_stream_ops = {
        .family            = PF_INET,
index 68244707577534288249cbb481a04c7b6ff3e0ab..80422fc3c836e5569c0976ea82ccd1ad22f112d5 100644 (file)
@@ -3366,65 +3366,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
        return err;
 }
 
-struct rtentry32 {
-       u32             rt_pad1;
-       struct sockaddr rt_dst;         /* target address               */
-       struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
-       struct sockaddr rt_genmask;     /* target network mask (IP)     */
-       unsigned short  rt_flags;
-       short           rt_pad2;
-       u32             rt_pad3;
-       unsigned char   rt_tos;
-       unsigned char   rt_class;
-       short           rt_pad4;
-       short           rt_metric;      /* +1 for binary compatibility! */
-       /* char * */ u32 rt_dev;        /* forcing the device at add    */
-       u32             rt_mtu;         /* per route MTU/Window         */
-       u32             rt_window;      /* Window clamping              */
-       unsigned short  rt_irtt;        /* Initial RTT                  */
-};
-
-static int routing_ioctl(struct net *net, struct socket *sock,
-                        unsigned int cmd, void __user *argp)
-{
-       struct rtentry32 __user *ur4 = argp;
-       int ret;
-       void *r = NULL;
-       struct rtentry r4;
-       char devname[16];
-       u32 rtdev;
-       mm_segment_t old_fs = get_fs();
-
-       ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
-                               3 * sizeof(struct sockaddr));
-       ret |= get_user(r4.rt_flags, &(ur4->rt_flags));
-       ret |= get_user(r4.rt_metric, &(ur4->rt_metric));
-       ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu));
-       ret |= get_user(r4.rt_window, &(ur4->rt_window));
-       ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt));
-       ret |= get_user(rtdev, &(ur4->rt_dev));
-       if (rtdev) {
-               ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
-               r4.rt_dev = (char __user __force *)devname;
-               devname[15] = 0;
-       } else
-               r4.rt_dev = NULL;
-
-       r = (void *) &r4;
-
-       if (ret) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       set_fs(KERNEL_DS);
-       ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
-       set_fs(old_fs);
-
-out:
-       return ret;
-}
-
 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
  * for some operations; this forces use of the newer bridge-utils that
  * use compatible ioctls
@@ -3463,9 +3404,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
        case SIOCGIFMAP:
        case SIOCSIFMAP:
                return compat_sioc_ifmap(net, cmd, argp);
-       case SIOCADDRT:
-       case SIOCDELRT:
-               return routing_ioctl(net, sock, cmd, argp);
        case SIOCGSTAMP_OLD:
        case SIOCGSTAMPNS_OLD:
                if (!sock->ops->gettstamp)