diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2006-12-04 13:13:23 +0100 |
---|---|---|
committer | Adrian Bunk <bunk@stusta.de> | 2006-12-04 13:13:23 +0100 |
commit | dbb4a0ecfe7dc4c989985a23288c98b2e3c8ee0d (patch) | |
tree | dc0d05635e7352f3c66c845434f513c857f572fa | |
parent | e4a7da4a76137dab99b98ce126ec2837dd53f638 (diff) |
[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>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
-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 12a57ae1cea..8171fea2848 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -359,10 +359,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) @@ -388,10 +389,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) @@ -594,6 +596,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 */ @@ -655,8 +658,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; @@ -667,8 +669,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); |