diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2006-11-30 19:25:21 -0800 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-02 21:31:56 -0800 |
commit | 14197d5447afc41fce6b11a91592278cad1a09eb (patch) | |
tree | 909424a8134221f4a052da21950fc526ef37324c | |
parent | 98a0824a0f33d051f31ca8ff59e289755b244ede (diff) | |
download | lwn-14197d5447afc41fce6b11a91592278cad1a09eb.tar.gz lwn-14197d5447afc41fce6b11a91592278cad1a09eb.zip |
[EBTABLES]: Prevent wraparounds in checks for entry components' sizes.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 46ab9b759269..136ed7d4bd73 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -338,10 +338,11 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, const char *name, unsigned int hookmask, unsigned int *cnt) { struct ebt_match *match; + size_t left = ((char *)e + e->watchers_offset) - (char *)m; int ret; - if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > - ((char *)e) + e->watchers_offset) + if (left < sizeof(struct ebt_entry_match) || + left - sizeof(struct ebt_entry_match) < m->match_size) return -EINVAL; match = find_match_lock(m->u.name, &ret, &ebt_mutex); if (!match) @@ -367,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, const char *name, unsigned int hookmask, unsigned int *cnt) { struct ebt_watcher *watcher; + size_t left = ((char *)e + e->target_offset) - (char *)w; int ret; - if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > - ((char *)e) + e->target_offset) + if (left < sizeof(struct ebt_entry_watcher) || + left - sizeof(struct ebt_entry_watcher) < w->watcher_size) return -EINVAL; watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); if (!watcher) @@ -573,6 +575,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, struct ebt_entry_target *t; struct ebt_target *target; unsigned int i, j, hook = 0, hookmask = 0; + size_t gap = e->next_offset - e->target_offset; int ret; /* don't mess with the struct ebt_entries */ @@ -634,8 +637,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, t->u.target = target; if (t->u.target == &ebt_standard_target) { - if (e->target_offset + sizeof(struct ebt_standard_target) > - e->next_offset) { + if (gap < sizeof(struct ebt_standard_target)) { BUGPRINT("Standard target size too big\n"); ret = -EFAULT; goto cleanup_watchers; @@ -646,8 +648,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, ret = -EFAULT; goto cleanup_watchers; } - } else if ((e->target_offset + t->target_size + - sizeof(struct ebt_entry_target) > e->next_offset) || + } else if (t->target_size > gap - sizeof(struct ebt_entry_target) || (t->u.target->check && t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ module_put(t->u.target->me); |