OSDN Git Service

netfilter/ebtables: clean up compat {get, set}sockopt handling
authorChristoph Hellwig <hch@lst.de>
Fri, 17 Jul 2020 06:23:19 +0000 (08:23 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Jul 2020 01:16:40 +0000 (18:16 -0700)
Merge the native and compat {get,set}sockopt handlers using
in_compat_syscall().  Note that this required moving a fair
amout of code around to be done sanely.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/netfilter/ebtables.c

index c83ffe9..fe13108 100644 (file)
@@ -1451,86 +1451,6 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
           ebt_entry_to_user, entries, tmp.entries);
 }
 
-static int do_ebt_set_ctl(struct sock *sk,
-       int cmd, void __user *user, unsigned int len)
-{
-       int ret;
-       struct net *net = sock_net(sk);
-
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-               return -EPERM;
-
-       switch (cmd) {
-       case EBT_SO_SET_ENTRIES:
-               ret = do_replace(net, user, len);
-               break;
-       case EBT_SO_SET_COUNTERS:
-               ret = update_counters(net, user, len);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
-{
-       int ret;
-       struct ebt_replace tmp;
-       struct ebt_table *t;
-       struct net *net = sock_net(sk);
-
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-               return -EPERM;
-
-       if (copy_from_user(&tmp, user, sizeof(tmp)))
-               return -EFAULT;
-
-       tmp.name[sizeof(tmp.name) - 1] = '\0';
-
-       t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
-       if (!t)
-               return ret;
-
-       switch (cmd) {
-       case EBT_SO_GET_INFO:
-       case EBT_SO_GET_INIT_INFO:
-               if (*len != sizeof(struct ebt_replace)) {
-                       ret = -EINVAL;
-                       mutex_unlock(&ebt_mutex);
-                       break;
-               }
-               if (cmd == EBT_SO_GET_INFO) {
-                       tmp.nentries = t->private->nentries;
-                       tmp.entries_size = t->private->entries_size;
-                       tmp.valid_hooks = t->valid_hooks;
-               } else {
-                       tmp.nentries = t->table->nentries;
-                       tmp.entries_size = t->table->entries_size;
-                       tmp.valid_hooks = t->table->valid_hooks;
-               }
-               mutex_unlock(&ebt_mutex);
-               if (copy_to_user(user, &tmp, *len) != 0) {
-                       ret = -EFAULT;
-                       break;
-               }
-               ret = 0;
-               break;
-
-       case EBT_SO_GET_ENTRIES:
-       case EBT_SO_GET_INIT_ENTRIES:
-               ret = copy_everything_to_user(t, user, len, cmd);
-               mutex_unlock(&ebt_mutex);
-               break;
-
-       default:
-               mutex_unlock(&ebt_mutex);
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
 #ifdef CONFIG_COMPAT
 /* 32 bit-userspace compatibility definitions. */
 struct compat_ebt_replace {
@@ -2314,28 +2234,6 @@ static int compat_update_counters(struct net *net, void __user *user,
                                        hlp.num_counters, user, len);
 }
 
-static int compat_do_ebt_set_ctl(struct sock *sk,
-               int cmd, void __user *user, unsigned int len)
-{
-       int ret;
-       struct net *net = sock_net(sk);
-
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-               return -EPERM;
-
-       switch (cmd) {
-       case EBT_SO_SET_ENTRIES:
-               ret = compat_do_replace(net, user, len);
-               break;
-       case EBT_SO_SET_COUNTERS:
-               ret = compat_update_counters(net, user, len);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
 static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
                void __user *user, int *len)
 {
@@ -2344,14 +2242,6 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
        struct ebt_table *t;
        struct net *net = sock_net(sk);
 
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-               return -EPERM;
-
-       /* try real handler in case userland supplied needed padding */
-       if ((cmd == EBT_SO_GET_INFO ||
-            cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp))
-                       return do_ebt_get_ctl(sk, cmd, user, len);
-
        if (copy_from_user(&tmp, user, sizeof(tmp)))
                return -EFAULT;
 
@@ -2413,20 +2303,112 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
 }
 #endif
 
+static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+{
+       struct net *net = sock_net(sk);
+       struct ebt_replace tmp;
+       struct ebt_table *t;
+       int ret;
+
+       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+               return -EPERM;
+
+#ifdef CONFIG_COMPAT
+       /* try real handler in case userland supplied needed padding */
+       if (in_compat_syscall() &&
+           ((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
+            *len != sizeof(tmp)))
+               return compat_do_ebt_get_ctl(sk, cmd, user, len);
+#endif
+
+       if (copy_from_user(&tmp, user, sizeof(tmp)))
+               return -EFAULT;
+
+       tmp.name[sizeof(tmp.name) - 1] = '\0';
+
+       t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
+       if (!t)
+               return ret;
+
+       switch (cmd) {
+       case EBT_SO_GET_INFO:
+       case EBT_SO_GET_INIT_INFO:
+               if (*len != sizeof(struct ebt_replace)) {
+                       ret = -EINVAL;
+                       mutex_unlock(&ebt_mutex);
+                       break;
+               }
+               if (cmd == EBT_SO_GET_INFO) {
+                       tmp.nentries = t->private->nentries;
+                       tmp.entries_size = t->private->entries_size;
+                       tmp.valid_hooks = t->valid_hooks;
+               } else {
+                       tmp.nentries = t->table->nentries;
+                       tmp.entries_size = t->table->entries_size;
+                       tmp.valid_hooks = t->table->valid_hooks;
+               }
+               mutex_unlock(&ebt_mutex);
+               if (copy_to_user(user, &tmp, *len) != 0) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = 0;
+               break;
+
+       case EBT_SO_GET_ENTRIES:
+       case EBT_SO_GET_INIT_ENTRIES:
+               ret = copy_everything_to_user(t, user, len, cmd);
+               mutex_unlock(&ebt_mutex);
+               break;
+
+       default:
+               mutex_unlock(&ebt_mutex);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int do_ebt_set_ctl(struct sock *sk, int cmd, void __user *user,
+               unsigned int len)
+{
+       struct net *net = sock_net(sk);
+       int ret;
+
+       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+               return -EPERM;
+
+       switch (cmd) {
+       case EBT_SO_SET_ENTRIES:
+#ifdef CONFIG_COMPAT
+               if (in_compat_syscall())
+                       ret = compat_do_replace(net, user, len);
+               else
+#endif
+                       ret = do_replace(net, user, len);
+               break;
+       case EBT_SO_SET_COUNTERS:
+#ifdef CONFIG_COMPAT
+               if (in_compat_syscall())
+                       ret = compat_update_counters(net, user, len);
+               else
+#endif
+                       ret = update_counters(net, user, len);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
 static struct nf_sockopt_ops ebt_sockopts = {
        .pf             = PF_INET,
        .set_optmin     = EBT_BASE_CTL,
        .set_optmax     = EBT_SO_SET_MAX + 1,
        .set            = do_ebt_set_ctl,
-#ifdef CONFIG_COMPAT
-       .compat_set     = compat_do_ebt_set_ctl,
-#endif
        .get_optmin     = EBT_BASE_CTL,
        .get_optmax     = EBT_SO_GET_MAX + 1,
        .get            = do_ebt_get_ctl,
-#ifdef CONFIG_COMPAT
-       .compat_get     = compat_do_ebt_get_ctl,
-#endif
        .owner          = THIS_MODULE,
 };