]> err.no Git - linux-2.6/blobdiff - net/bridge/netfilter/ebtables.c
[EBTABLES]: translate_table(): switch direct uses of repl->hook_info to newinfo
[linux-2.6] / net / bridge / netfilter / ebtables.c
index e79c0fbd9e89f793435306e5d8313fa9bf843fe4..3e1bf716509a99117400dc3ad25758acf9eff9d3 100644 (file)
@@ -393,48 +393,69 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
        return 0;
 }
 
-static inline int
-__ebt_verify_pointers(struct ebt_entry *e,
-   struct ebt_table_info *newinfo, char *base, char *limit,
-   struct ebt_entries **hook_entries,
-   unsigned int valid_hooks)
+static int ebt_verify_pointers(struct ebt_replace *repl,
+                              struct ebt_table_info *newinfo)
 {
-       unsigned int offset = (char *)e - newinfo->entries;
-       size_t left = (limit - base) - offset;
+       unsigned int limit = repl->entries_size;
+       unsigned int valid_hooks = repl->valid_hooks;
+       unsigned int offset = 0;
        int i;
 
-       if (left < sizeof(unsigned int))
-               goto Esmall;
+       for (i = 0; i < NF_BR_NUMHOOKS; i++)
+               newinfo->hook_entry[i] = NULL;
 
-       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-               if ((valid_hooks & (1 << i)) == 0)
-                       continue;
-               if ((char *)hook_entries[i] == base + offset)
+       newinfo->entries_size = repl->entries_size;
+       newinfo->nentries = repl->nentries;
+
+       while (offset < limit) {
+               size_t left = limit - offset;
+               struct ebt_entry *e = (void *)newinfo->entries + offset;
+
+               if (left < sizeof(unsigned int))
                        break;
+
+               for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+                       if ((valid_hooks & (1 << i)) == 0)
+                               continue;
+                       if ((char *)repl->hook_entry[i] == repl->entries + offset)
+                               break;
+               }
+
+               if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
+                       if (e->bitmask != 0) {
+                               /* we make userspace set this right,
+                                  so there is no misunderstanding */
+                               BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
+                                        "in distinguisher\n");
+                               return -EINVAL;
+                       }
+                       if (i != NF_BR_NUMHOOKS)
+                               newinfo->hook_entry[i] = (struct ebt_entries *)e;
+                       if (left < sizeof(struct ebt_entries))
+                               break;
+                       offset += sizeof(struct ebt_entries);
+               } else {
+                       if (left < sizeof(struct ebt_entry))
+                               break;
+                       if (left < e->next_offset)
+                               break;
+                       offset += e->next_offset;
+               }
+       }
+       if (offset != limit) {
+               BUGPRINT("entries_size too small\n");
+               return -EINVAL;
        }
-       if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
-               if (e->bitmask != 0) {
-                       /* we make userspace set this right,
-                          so there is no misunderstanding */
-                       BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
-                                "in distinguisher\n");
+
+       /* check if all valid hooks have a chain */
+       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+               if (!newinfo->hook_entry[i] &&
+                  (valid_hooks & (1 << i))) {
+                       BUGPRINT("Valid hook without chain\n");
                        return -EINVAL;
                }
-               if (left < sizeof(struct ebt_entries))
-                       goto Esmall;
-               if (i != NF_BR_NUMHOOKS)
-                       newinfo->hook_entry[i] = (struct ebt_entries *)e;
-               return 0;
        }
-       if (left < sizeof(struct ebt_entry))
-               goto Esmall;
-       if (left < e->next_offset)
-               goto Esmall;
        return 0;
-
-Esmall:
-       BUGPRINT("entries_size too small\n");
-       return -EINVAL;
 }
 
 /*
@@ -766,41 +787,33 @@ static int translate_table(struct ebt_replace *repl,
        int ret;
        struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
 
+       ret = ebt_verify_pointers(repl, newinfo);
+       if (ret != 0)
+               return ret;
+
        i = 0;
-       while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
+       while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
                i++;
        if (i == NF_BR_NUMHOOKS) {
                BUGPRINT("No valid hooks specified\n");
                return -EINVAL;
        }
-       if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
+       if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
                BUGPRINT("Chains don't start at beginning\n");
                return -EINVAL;
        }
        /* make sure chains are ordered after each other in same order
           as their corresponding hooks */
        for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
-               if (!(repl->valid_hooks & (1 << j)))
+               if (!newinfo->hook_entry[j])
                        continue;
-               if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
+               if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
                        BUGPRINT("Hook order must be followed\n");
                        return -EINVAL;
                }
                i = j;
        }
 
-       for (i = 0; i < NF_BR_NUMHOOKS; i++)
-               newinfo->hook_entry[i] = NULL;
-
-       newinfo->entries_size = repl->entries_size;
-       newinfo->nentries = repl->nentries;
-
-       ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-          __ebt_verify_pointers, newinfo, repl->entries,
-          repl->entries + repl->entries_size, repl->hook_entry, repl->valid_hooks);
-       if (ret != 0)
-               return ret;
-
        /* do some early checkings and initialize some things */
        i = 0; /* holds the expected nr. of entries for the chain */
        j = 0; /* holds the up to now counted entries for the chain */
@@ -825,15 +838,6 @@ static int translate_table(struct ebt_replace *repl,
                return -EINVAL;
        }
 
-       /* check if all valid hooks have a chain */
-       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-               if (newinfo->hook_entry[i] == NULL &&
-                  (repl->valid_hooks & (1 << i))) {
-                       BUGPRINT("Valid hook without chain\n");
-                       return -EINVAL;
-               }
-       }
-
        /* get the location of the udc, put them in an array
           while we're at it, allocate the chainstack */
        if (udc_cnt) {
@@ -873,7 +877,7 @@ static int translate_table(struct ebt_replace *repl,
 
        /* Check for loops */
        for (i = 0; i < NF_BR_NUMHOOKS; i++)
-               if (repl->valid_hooks & (1 << i))
+               if (newinfo->hook_entry[i])
                        if (check_chainloops(newinfo->hook_entry[i],
                           cl_s, udc_cnt, i, newinfo->entries)) {
                                vfree(cl_s);