netfilter: x_tables: do compat validation via translate_table
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv4 / netfilter / arp_tables.c
index a0030d56cac2ea4392e66b6053e0ce1cb5ca5947..28489d97e9c105e88cf7252c5becf92a4cfead5e 100644 (file)
@@ -1206,19 +1206,17 @@ static inline void compat_release_entry(struct compat_arpt_entry *e)
        module_put(t->u.kernel.target->me);
 }
 
-static inline int
+static int
 check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
                                  struct xt_table_info *newinfo,
                                  unsigned int *size,
                                  const unsigned char *base,
-                                 const unsigned char *limit,
-                                 const unsigned int *hook_entries,
-                                 const unsigned int *underflows)
+                                 const unsigned char *limit)
 {
        struct xt_entry_target *t;
        struct xt_target *target;
        unsigned int entry_offset;
-       int ret, off, h;
+       int ret, off;
 
        duprintf("check_compat_entry_size_and_hooks %p\n", e);
        if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
@@ -1263,17 +1261,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
        if (ret)
                goto release_target;
 
-       /* Check hooks & underflows */
-       for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
-               if ((unsigned char *)e - base == hook_entries[h])
-                       newinfo->hook_entry[h] = hook_entries[h];
-               if ((unsigned char *)e - base == underflows[h])
-                       newinfo->underflow[h] = underflows[h];
-       }
-
-       /* Clear counters and comefrom */
-       memset(&e->counters, 0, sizeof(e->counters));
-       e->comefrom = 0;
        return 0;
 
 release_target:
@@ -1323,7 +1310,7 @@ static int translate_compat_table(struct xt_table_info **pinfo,
        struct xt_table_info *newinfo, *info;
        void *pos, *entry0, *entry1;
        struct compat_arpt_entry *iter0;
-       struct arpt_entry *iter1;
+       struct arpt_replace repl;
        unsigned int size;
        int ret = 0;
 
@@ -1332,12 +1319,6 @@ static int translate_compat_table(struct xt_table_info **pinfo,
        size = compatr->size;
        info->number = compatr->num_entries;
 
-       /* Init all hooks to impossible value. */
-       for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
-               info->hook_entry[i] = 0xFFFFFFFF;
-               info->underflow[i] = 0xFFFFFFFF;
-       }
-
        duprintf("translate_compat_table: size %u\n", info->size);
        j = 0;
        xt_compat_lock(NFPROTO_ARP);
@@ -1346,9 +1327,7 @@ static int translate_compat_table(struct xt_table_info **pinfo,
        xt_entry_foreach(iter0, entry0, compatr->size) {
                ret = check_compat_entry_size_and_hooks(iter0, info, &size,
                                                        entry0,
-                                                       entry0 + compatr->size,
-                                                       compatr->hook_entry,
-                                                       compatr->underflow);
+                                                       entry0 + compatr->size);
                if (ret != 0)
                        goto out_unlock;
                ++j;
@@ -1361,23 +1340,6 @@ static int translate_compat_table(struct xt_table_info **pinfo,
                goto out_unlock;
        }
 
-       /* Check hooks all assigned */
-       for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
-               /* Only hooks which are valid */
-               if (!(compatr->valid_hooks & (1 << i)))
-                       continue;
-               if (info->hook_entry[i] == 0xFFFFFFFF) {
-                       duprintf("Invalid hook entry %u %u\n",
-                                i, info->hook_entry[i]);
-                       goto out_unlock;
-               }
-               if (info->underflow[i] == 0xFFFFFFFF) {
-                       duprintf("Invalid underflow %u %u\n",
-                                i, info->underflow[i]);
-                       goto out_unlock;
-               }
-       }
-
        ret = -ENOMEM;
        newinfo = xt_alloc_table_info(size);
        if (!newinfo)
@@ -1394,51 +1356,25 @@ static int translate_compat_table(struct xt_table_info **pinfo,
        xt_entry_foreach(iter0, entry0, compatr->size)
                compat_copy_entry_from_user(iter0, &pos, &size,
                                            newinfo, entry1);
+
+       /* all module references in entry0 are now gone */
+
        xt_compat_flush_offsets(NFPROTO_ARP);
        xt_compat_unlock(NFPROTO_ARP);
 
-       ret = -ELOOP;
-       if (!mark_source_chains(newinfo, compatr->valid_hooks, entry1))
-               goto free_newinfo;
+       memcpy(&repl, compatr, sizeof(*compatr));
 
-       i = 0;
-       xt_entry_foreach(iter1, entry1, newinfo->size) {
-               ret = check_target(iter1, compatr->name);
-               if (ret != 0)
-                       break;
-               ++i;
-               if (strcmp(arpt_get_target(iter1)->u.user.name,
-                   XT_ERROR_TARGET) == 0)
-                       ++newinfo->stacksize;
-       }
-       if (ret) {
-               /*
-                * The first i matches need cleanup_entry (calls ->destroy)
-                * because they had called ->check already. The other j-i
-                * entries need only release.
-                */
-               int skip = i;
-               j -= i;
-               xt_entry_foreach(iter0, entry0, newinfo->size) {
-                       if (skip-- > 0)
-                               continue;
-                       if (j-- == 0)
-                               break;
-                       compat_release_entry(iter0);
-               }
-               xt_entry_foreach(iter1, entry1, newinfo->size) {
-                       if (i-- == 0)
-                               break;
-                       cleanup_entry(iter1);
-               }
-               xt_free_table_info(newinfo);
-               return ret;
+       for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
+               repl.hook_entry[i] = newinfo->hook_entry[i];
+               repl.underflow[i] = newinfo->underflow[i];
        }
 
-       /* And one copy for every other CPU */
-       for_each_possible_cpu(i)
-               if (newinfo->entries[i] && newinfo->entries[i] != entry1)
-                       memcpy(newinfo->entries[i], entry1, newinfo->size);
+       repl.num_counters = 0;
+       repl.counters = NULL;
+       repl.size = newinfo->size;
+       ret = translate_table(newinfo, entry1, &repl);
+       if (ret)
+               goto free_newinfo;
 
        *pinfo = newinfo;
        *pentry0 = entry1;
@@ -1447,17 +1383,16 @@ static int translate_compat_table(struct xt_table_info **pinfo,
 
 free_newinfo:
        xt_free_table_info(newinfo);
-out:
+       return ret;
+out_unlock:
+       xt_compat_flush_offsets(NFPROTO_ARP);
+       xt_compat_unlock(NFPROTO_ARP);
        xt_entry_foreach(iter0, entry0, compatr->size) {
                if (j-- == 0)
                        break;
                compat_release_entry(iter0);
        }
        return ret;
-out_unlock:
-       xt_compat_flush_offsets(NFPROTO_ARP);
-       xt_compat_unlock(NFPROTO_ARP);
-       goto out;
 }
 
 static int compat_do_replace(struct net *net, void __user *user,