]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Jun 2016 15:54:10 +0000 (08:54 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Jun 2016 15:54:10 +0000 (08:54 -0700)
added patches:
netfilter-x_tables-introduce-and-use-xt_copy_counters_from_user.patch

queue-3.14/netfilter-x_tables-introduce-and-use-xt_copy_counters_from_user.patch [new file with mode: 0644]
queue-3.14/series

diff --git a/queue-3.14/netfilter-x_tables-introduce-and-use-xt_copy_counters_from_user.patch b/queue-3.14/netfilter-x_tables-introduce-and-use-xt_copy_counters_from_user.patch
new file mode 100644 (file)
index 0000000..dffc6ab
--- /dev/null
@@ -0,0 +1,336 @@
+From dd77f91a54e32f3f84a1420268302c1ad0e2cfe8 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Fri, 1 Apr 2016 15:37:59 +0200
+Subject: netfilter: x_tables: introduce and use xt_copy_counters_from_user
+
+From: Florian Westphal <fw@strlen.de>
+
+commit d7591f0c41ce3e67600a982bab6989ef0f07b3ce upstream
+
+The three variants use same copy&pasted code, condense this into a
+helper and use that.
+
+Make sure info.name is 0-terminated.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/netfilter/x_tables.h |    3 +
+ net/ipv4/netfilter/arp_tables.c    |   48 ++----------------------
+ net/ipv4/netfilter/ip_tables.c     |   48 ++----------------------
+ net/ipv6/netfilter/ip6_tables.c    |   49 ++----------------------
+ net/netfilter/x_tables.c           |   74 +++++++++++++++++++++++++++++++++++++
+ 5 files changed, 92 insertions(+), 130 deletions(-)
+
+--- a/include/linux/netfilter/x_tables.h
++++ b/include/linux/netfilter/x_tables.h
+@@ -248,6 +248,9 @@ int xt_check_match(struct xt_mtchk_param
+ int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto,
+                   bool inv_proto);
++void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
++                               struct xt_counters_info *info, bool compat);
++
+ struct xt_table *xt_register_table(struct net *net,
+                                  const struct xt_table *table,
+                                  struct xt_table_info *bootstrap,
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -1125,56 +1125,18 @@ static int do_add_counters(struct net *n
+       unsigned int i, curcpu;
+       struct xt_counters_info tmp;
+       struct xt_counters *paddc;
+-      unsigned int num_counters;
+-      const char *name;
+-      int size;
+-      void *ptmp;
+       struct xt_table *t;
+       const struct xt_table_info *private;
+       int ret = 0;
+       void *loc_cpu_entry;
+       struct arpt_entry *iter;
+       unsigned int addend;
+-#ifdef CONFIG_COMPAT
+-      struct compat_xt_counters_info compat_tmp;
+-      if (compat) {
+-              ptmp = &compat_tmp;
+-              size = sizeof(struct compat_xt_counters_info);
+-      } else
+-#endif
+-      {
+-              ptmp = &tmp;
+-              size = sizeof(struct xt_counters_info);
+-      }
+-
+-      if (copy_from_user(ptmp, user, size) != 0)
+-              return -EFAULT;
+-
+-#ifdef CONFIG_COMPAT
+-      if (compat) {
+-              num_counters = compat_tmp.num_counters;
+-              name = compat_tmp.name;
+-      } else
+-#endif
+-      {
+-              num_counters = tmp.num_counters;
+-              name = tmp.name;
+-      }
+-
+-      if (len != size + num_counters * sizeof(struct xt_counters))
+-              return -EINVAL;
+-
+-      paddc = vmalloc(len - size);
+-      if (!paddc)
+-              return -ENOMEM;
+-
+-      if (copy_from_user(paddc, user + size, len - size) != 0) {
+-              ret = -EFAULT;
+-              goto free;
+-      }
++      paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
++      if (IS_ERR(paddc))
++              return PTR_ERR(paddc);
+-      t = xt_find_table_lock(net, NFPROTO_ARP, name);
++      t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name);
+       if (IS_ERR_OR_NULL(t)) {
+               ret = t ? PTR_ERR(t) : -ENOENT;
+               goto free;
+@@ -1182,7 +1144,7 @@ static int do_add_counters(struct net *n
+       local_bh_disable();
+       private = t->private;
+-      if (private->number != num_counters) {
++      if (private->number != tmp.num_counters) {
+               ret = -EINVAL;
+               goto unlock_up_free;
+       }
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -1312,56 +1312,18 @@ do_add_counters(struct net *net, const v
+       unsigned int i, curcpu;
+       struct xt_counters_info tmp;
+       struct xt_counters *paddc;
+-      unsigned int num_counters;
+-      const char *name;
+-      int size;
+-      void *ptmp;
+       struct xt_table *t;
+       const struct xt_table_info *private;
+       int ret = 0;
+       void *loc_cpu_entry;
+       struct ipt_entry *iter;
+       unsigned int addend;
+-#ifdef CONFIG_COMPAT
+-      struct compat_xt_counters_info compat_tmp;
+-      if (compat) {
+-              ptmp = &compat_tmp;
+-              size = sizeof(struct compat_xt_counters_info);
+-      } else
+-#endif
+-      {
+-              ptmp = &tmp;
+-              size = sizeof(struct xt_counters_info);
+-      }
+-
+-      if (copy_from_user(ptmp, user, size) != 0)
+-              return -EFAULT;
+-
+-#ifdef CONFIG_COMPAT
+-      if (compat) {
+-              num_counters = compat_tmp.num_counters;
+-              name = compat_tmp.name;
+-      } else
+-#endif
+-      {
+-              num_counters = tmp.num_counters;
+-              name = tmp.name;
+-      }
+-
+-      if (len != size + num_counters * sizeof(struct xt_counters))
+-              return -EINVAL;
+-
+-      paddc = vmalloc(len - size);
+-      if (!paddc)
+-              return -ENOMEM;
+-
+-      if (copy_from_user(paddc, user + size, len - size) != 0) {
+-              ret = -EFAULT;
+-              goto free;
+-      }
++      paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
++      if (IS_ERR(paddc))
++              return PTR_ERR(paddc);
+-      t = xt_find_table_lock(net, AF_INET, name);
++      t = xt_find_table_lock(net, AF_INET, tmp.name);
+       if (IS_ERR_OR_NULL(t)) {
+               ret = t ? PTR_ERR(t) : -ENOENT;
+               goto free;
+@@ -1369,7 +1331,7 @@ do_add_counters(struct net *net, const v
+       local_bh_disable();
+       private = t->private;
+-      if (private->number != num_counters) {
++      if (private->number != tmp.num_counters) {
+               ret = -EINVAL;
+               goto unlock_up_free;
+       }
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -1322,56 +1322,17 @@ do_add_counters(struct net *net, const v
+       unsigned int i, curcpu;
+       struct xt_counters_info tmp;
+       struct xt_counters *paddc;
+-      unsigned int num_counters;
+-      char *name;
+-      int size;
+-      void *ptmp;
+       struct xt_table *t;
+       const struct xt_table_info *private;
+       int ret = 0;
+       const void *loc_cpu_entry;
+       struct ip6t_entry *iter;
+       unsigned int addend;
+-#ifdef CONFIG_COMPAT
+-      struct compat_xt_counters_info compat_tmp;
+-      if (compat) {
+-              ptmp = &compat_tmp;
+-              size = sizeof(struct compat_xt_counters_info);
+-      } else
+-#endif
+-      {
+-              ptmp = &tmp;
+-              size = sizeof(struct xt_counters_info);
+-      }
+-
+-      if (copy_from_user(ptmp, user, size) != 0)
+-              return -EFAULT;
+-
+-#ifdef CONFIG_COMPAT
+-      if (compat) {
+-              num_counters = compat_tmp.num_counters;
+-              name = compat_tmp.name;
+-      } else
+-#endif
+-      {
+-              num_counters = tmp.num_counters;
+-              name = tmp.name;
+-      }
+-
+-      if (len != size + num_counters * sizeof(struct xt_counters))
+-              return -EINVAL;
+-
+-      paddc = vmalloc(len - size);
+-      if (!paddc)
+-              return -ENOMEM;
+-
+-      if (copy_from_user(paddc, user + size, len - size) != 0) {
+-              ret = -EFAULT;
+-              goto free;
+-      }
+-
+-      t = xt_find_table_lock(net, AF_INET6, name);
++      paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
++      if (IS_ERR(paddc))
++              return PTR_ERR(paddc);
++      t = xt_find_table_lock(net, AF_INET6, tmp.name);
+       if (IS_ERR_OR_NULL(t)) {
+               ret = t ? PTR_ERR(t) : -ENOENT;
+               goto free;
+@@ -1380,7 +1341,7 @@ do_add_counters(struct net *net, const v
+       local_bh_disable();
+       private = t->private;
+-      if (private->number != num_counters) {
++      if (private->number != tmp.num_counters) {
+               ret = -EINVAL;
+               goto unlock_up_free;
+       }
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -771,6 +771,80 @@ int xt_check_target(struct xt_tgchk_para
+ }
+ EXPORT_SYMBOL_GPL(xt_check_target);
++/**
++ * xt_copy_counters_from_user - copy counters and metadata from userspace
++ *
++ * @user: src pointer to userspace memory
++ * @len: alleged size of userspace memory
++ * @info: where to store the xt_counters_info metadata
++ * @compat: true if we setsockopt call is done by 32bit task on 64bit kernel
++ *
++ * Copies counter meta data from @user and stores it in @info.
++ *
++ * vmallocs memory to hold the counters, then copies the counter data
++ * from @user to the new memory and returns a pointer to it.
++ *
++ * If @compat is true, @info gets converted automatically to the 64bit
++ * representation.
++ *
++ * The metadata associated with the counters is stored in @info.
++ *
++ * Return: returns pointer that caller has to test via IS_ERR().
++ * If IS_ERR is false, caller has to vfree the pointer.
++ */
++void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
++                               struct xt_counters_info *info, bool compat)
++{
++      void *mem;
++      u64 size;
++
++#ifdef CONFIG_COMPAT
++      if (compat) {
++              /* structures only differ in size due to alignment */
++              struct compat_xt_counters_info compat_tmp;
++
++              if (len <= sizeof(compat_tmp))
++                      return ERR_PTR(-EINVAL);
++
++              len -= sizeof(compat_tmp);
++              if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0)
++                      return ERR_PTR(-EFAULT);
++
++              strlcpy(info->name, compat_tmp.name, sizeof(info->name));
++              info->num_counters = compat_tmp.num_counters;
++              user += sizeof(compat_tmp);
++      } else
++#endif
++      {
++              if (len <= sizeof(*info))
++                      return ERR_PTR(-EINVAL);
++
++              len -= sizeof(*info);
++              if (copy_from_user(info, user, sizeof(*info)) != 0)
++                      return ERR_PTR(-EFAULT);
++
++              info->name[sizeof(info->name) - 1] = '\0';
++              user += sizeof(*info);
++      }
++
++      size = sizeof(struct xt_counters);
++      size *= info->num_counters;
++
++      if (size != (u64)len)
++              return ERR_PTR(-EINVAL);
++
++      mem = vmalloc(len);
++      if (!mem)
++              return ERR_PTR(-ENOMEM);
++
++      if (copy_from_user(mem, user, len) == 0)
++              return mem;
++
++      vfree(mem);
++      return ERR_PTR(-EFAULT);
++}
++EXPORT_SYMBOL_GPL(xt_copy_counters_from_user);
++
+ #ifdef CONFIG_COMPAT
+ int xt_compat_target_offset(const struct xt_target *target)
+ {
index cf5da033a65fde8b4e039b4e12135bfd5338cef0..e8a1cf4a47ca96141cc763a0ddc211405c220ba0 100644 (file)
@@ -34,3 +34,4 @@ netfilter-x_tables-xt_compat_match_from_user-doesn-t-need-a-retval.patch
 netfilter-ensure-number-of-counters-is-0-in-do_replace.patch
 netfilter-x_tables-do-compat-validation-via-translate_table.patch
 revert-netfilter-ensure-number-of-counters-is-0-in-do_replace.patch
+netfilter-x_tables-introduce-and-use-xt_copy_counters_from_user.patch