[EBTABLES]: Split ebt_check_entry_size_and_hooks

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>
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 136ed7d..e79c0fb 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -393,15 +393,11 @@
 	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 @@
 		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 @@
 			         "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 @@
 		                 "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 @@
 		}
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 	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)