| From stable-bounces@linux.kernel.org Thu Nov 30 19:52:58 2006 |
| Date: Thu, 30 Nov 2006 19:47:59 -0800 (PST) |
| Message-Id: <20061130.194759.54187107.davem@davemloft.net> |
| To: stable@kernel.org |
| From: David Miller <davem@davemloft.net> |
| Cc: bunk@stusta.de |
| Subject: EBTABLES: Prevent wraparounds in checks for entry components' sizes. |
| |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| net/bridge/netfilter/ebtables.c | 17 +++++++++-------- |
| 1 file changed, 9 insertions(+), 8 deletions(-) |
| |
| --- linux-2.6.19.orig/net/bridge/netfilter/ebtables.c |
| +++ linux-2.6.19/net/bridge/netfilter/ebtables.c |
| @@ -338,10 +338,11 @@ ebt_check_match(struct ebt_entry_match * |
| 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_watch |
| 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, str |
| 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, str |
| |
| 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, str |
| 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); |