Merge tag 'v3.10.103' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv4 / netfilter / ip_tables.c
index e728884e5c50a72f7613d795c0c10a84b0def714..8672b124e1cc8e38f84e1c963d695b6e40c713dd 100644 (file)
@@ -562,6 +562,26 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net)
        module_put(par.match->me);
 }
 
+static int
+check_entry(const struct ipt_entry *e)
+{
+       const struct xt_entry_target *t;
+
+       if (!ip_checkentry(&e->ip))
+               return -EINVAL;
+
+       if (e->target_offset + sizeof(struct xt_entry_target) >
+           e->next_offset)
+               return -EINVAL;
+
+       t = ipt_get_target_c(e);
+       if (e->target_offset + t->u.target_size > e->next_offset)
+               return -EINVAL;
+
+       return 0;
+}
+
+
 static int
 check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
 {
@@ -718,11 +738,8 @@ check_entry_size_and_hooks(struct ipt_entry *e,
                return -EINVAL;
        }
 
-       if (!ip_checkentry(&e->ip))
-               return -EINVAL;
+       err = check_entry(e);
 
-       err = xt_check_entry_offsets(e, e->elems, e->target_offset,
-                                    e->next_offset);
        if (err)
                return err;
 
@@ -1290,56 +1307,18 @@ do_add_counters(struct net *net, const void __user *user,
        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;
-       }
+       paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
+       if (IS_ERR(paddc))
+               return PTR_ERR(paddc);
 
-       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_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;
@@ -1347,7 +1326,7 @@ do_add_counters(struct net *net, const void __user *user,
 
        local_bh_disable();
        private = t->private;
-       if (private->number != num_counters) {
+       if (private->number != tmp.num_counters) {
                ret = -EINVAL;
                goto unlock_up_free;
        }
@@ -1485,11 +1464,9 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
                return -EINVAL;
        }
 
-       if (!ip_checkentry(&e->ip))
-               return -EINVAL;
+       /* For purposes of check_entry casting the compat entry is fine */
+       ret = check_entry((struct ipt_entry *)e);
 
-       ret = xt_compat_check_entry_offsets(e, e->elems,
-                                           e->target_offset, e->next_offset);
        if (ret)
                return ret;