[EBTABLES]: Split ebt_check_entry_size_and_hooks
Al Viro [Fri, 1 Dec 2006 03:25:51 +0000 (19:25 -0800)]
Split ebt_check_entry_size_and_hooks() in two parts - one that does
sanity checks on pointers (basically, checks that we can safely
use iterator from now on) and the rest of it (looking into details
of entry).

The loop applying ebt_check_entry_size_and_hooks() is split in two.

Populating newinfo->hook_entry[] is done in the first part.

Unused arguments killed.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/bridge/netfilter/ebtables.c

index 136ed7d..e79c0fb 100644 (file)
@@ -393,15 +393,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
        return 0;
 }
 
-/*
- * this one is very careful, as it is the first function
- * to parse the userspace data
- */
 static inline int
-ebt_check_entry_size_and_hooks(struct ebt_entry *e,
+__ebt_verify_pointers(struct ebt_entry *e,
    struct ebt_table_info *newinfo, char *base, char *limit,
-   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
-   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
+   struct ebt_entries **hook_entries,
+   unsigned int valid_hooks)
 {
        unsigned int offset = (char *)e - newinfo->entries;
        size_t left = (limit - base) - offset;
@@ -416,8 +412,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                if ((char *)hook_entries[i] == base + offset)
                        break;
        }
-       /* beginning of a new chain
-          if i == NF_BR_NUMHOOKS it must be a user defined chain */
        if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
                if (e->bitmask != 0) {
                        /* we make userspace set this right,
@@ -426,6 +420,45 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                                 "in distinguisher\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;
+}
+
+/*
+ * this one is very careful, as it is the first function
+ * to parse the userspace data
+ */
+static inline int
+ebt_check_entry_size_and_hooks(struct ebt_entry *e,
+   struct ebt_table_info *newinfo, char *base,
+   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
+   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
+{
+       unsigned int offset = (char *)e - newinfo->entries;
+       int i;
+
+       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+               if ((valid_hooks & (1 << i)) == 0)
+                       continue;
+               if ((char *)hook_entries[i] == base + offset)
+                       break;
+       }
+       /* beginning of a new chain
+          if i == NF_BR_NUMHOOKS it must be a user defined chain */
+       if (i != NF_BR_NUMHOOKS || !e->bitmask) {
                /* this checks if the previous chain has as many entries
                   as it said it has */
                if (*n != *cnt) {
@@ -433,9 +466,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                                 "in the chain\n");
                        return -EINVAL;
                }
-               /* before we look at the struct, be sure it is not too big */
-               if (left < sizeof(struct ebt_entries))
-                       goto Esmall;
                if (((struct ebt_entries *)e)->policy != EBT_DROP &&
                   ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
                        /* only RETURN from udc */
@@ -447,8 +477,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                }
                if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
                        (*udc_cnt)++;
-               else
-                       newinfo->hook_entry[i] = (struct ebt_entries *)e;
                if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
                        BUGPRINT("counter_offset != totalcnt");
                        return -EINVAL;
@@ -458,8 +486,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                return 0;
        }
        /* a plain old entry, heh */
-       if (left < sizeof(struct ebt_entry))
-               goto Esmall;
        if (sizeof(struct ebt_entry) > e->watchers_offset ||
           e->watchers_offset > e->target_offset ||
           e->target_offset >= e->next_offset) {
@@ -471,16 +497,9 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                BUGPRINT("target size too small\n");
                return -EINVAL;
        }
-       if (left < e->next_offset)
-               goto Esmall;
-
        (*cnt)++;
        (*totalcnt)++;
        return 0;
-
-Esmall:
-       BUGPRINT("entries_size too small\n");
-       return -EINVAL;
 }
 
 struct ebt_cl_stack
@@ -776,6 +795,12 @@ static int translate_table(struct ebt_replace *repl,
        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 */
@@ -784,7 +809,7 @@ static int translate_table(struct ebt_replace *repl,
        udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
        ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
           ebt_check_entry_size_and_hooks, newinfo, repl->entries,
-          repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
+          repl->hook_entry, &i, &j, &k,
           &udc_cnt, repl->valid_hooks);
 
        if (ret != 0)