aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-11-30 19:25:51 -0800
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-02 21:31:56 -0800
commit22b440bf9e717226d0fbaf4f29357cbdd5279de5 (patch)
tree60ed5c4e78c0e539745ba79e75719de1cd6af59c /net
parent[EBTABLES]: Prevent wraparounds in checks for entry components' sizes. (diff)
downloadlinux-dev-22b440bf9e717226d0fbaf4f29357cbdd5279de5.tar.xz
linux-dev-22b440bf9e717226d0fbaf4f29357cbdd5279de5.zip
[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>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/ebtables.c73
1 files changed, 49 insertions, 24 deletions
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)