X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fbridge%2Fnetfilter%2Febtables.c;h=3e1bf716509a99117400dc3ad25758acf9eff9d3;hb=1f072c96fdf1a0caa11c6e8078dd96925bd02db5;hp=e79c0fbd9e89f793435306e5d8313fa9bf843fe4;hpb=22b440bf9e717226d0fbaf4f29357cbdd5279de5;p=linux-2.6 diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index e79c0fbd9e..3e1bf71650 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -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);