From: Al Viro Date: Fri, 1 Dec 2006 03:25:51 +0000 (-0800) Subject: [EBTABLES]: Split ebt_check_entry_size_and_hooks X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=22b440bf9e717226d0fbaf4f29357cbdd5279de5;p=linux-beck.git [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 Signed-off-by: David S. Miller --- diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 136ed7d4bd73..e79c0fbd9e89 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -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)