diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2006-11-30 22:25:21 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:31:56 -0500 |
commit | 14197d5447afc41fce6b11a91592278cad1a09eb (patch) | |
tree | 909424a8134221f4a052da21950fc526ef37324c /net/bridge | |
parent | 98a0824a0f33d051f31ca8ff59e289755b244ede (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>
Diffstat (limited to 'net/bridge')
-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, | |||
338 | const char *name, unsigned int hookmask, unsigned int *cnt) | 338 | const char *name, unsigned int hookmask, unsigned int *cnt) |
339 | { | 339 | { |
340 | struct ebt_match *match; | 340 | struct ebt_match *match; |
341 | size_t left = ((char *)e + e->watchers_offset) - (char *)m; | ||
341 | int ret; | 342 | int ret; |
342 | 343 | ||
343 | if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > | 344 | if (left < sizeof(struct ebt_entry_match) || |
344 | ((char *)e) + e->watchers_offset) | 345 | left - sizeof(struct ebt_entry_match) < m->match_size) |
345 | return -EINVAL; | 346 | return -EINVAL; |
346 | match = find_match_lock(m->u.name, &ret, &ebt_mutex); | 347 | match = find_match_lock(m->u.name, &ret, &ebt_mutex); |
347 | if (!match) | 348 | if (!match) |
@@ -367,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, | |||
367 | const char *name, unsigned int hookmask, unsigned int *cnt) | 368 | const char *name, unsigned int hookmask, unsigned int *cnt) |
368 | { | 369 | { |
369 | struct ebt_watcher *watcher; | 370 | struct ebt_watcher *watcher; |
371 | size_t left = ((char *)e + e->target_offset) - (char *)w; | ||
370 | int ret; | 372 | int ret; |
371 | 373 | ||
372 | if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > | 374 | if (left < sizeof(struct ebt_entry_watcher) || |
373 | ((char *)e) + e->target_offset) | 375 | left - sizeof(struct ebt_entry_watcher) < w->watcher_size) |
374 | return -EINVAL; | 376 | return -EINVAL; |
375 | watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); | 377 | watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); |
376 | if (!watcher) | 378 | if (!watcher) |
@@ -573,6 +575,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, | |||
573 | struct ebt_entry_target *t; | 575 | struct ebt_entry_target *t; |
574 | struct ebt_target *target; | 576 | struct ebt_target *target; |
575 | unsigned int i, j, hook = 0, hookmask = 0; | 577 | unsigned int i, j, hook = 0, hookmask = 0; |
578 | size_t gap = e->next_offset - e->target_offset; | ||
576 | int ret; | 579 | int ret; |
577 | 580 | ||
578 | /* don't mess with the struct ebt_entries */ | 581 | /* don't mess with the struct ebt_entries */ |
@@ -634,8 +637,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, | |||
634 | 637 | ||
635 | t->u.target = target; | 638 | t->u.target = target; |
636 | if (t->u.target == &ebt_standard_target) { | 639 | if (t->u.target == &ebt_standard_target) { |
637 | if (e->target_offset + sizeof(struct ebt_standard_target) > | 640 | if (gap < sizeof(struct ebt_standard_target)) { |
638 | e->next_offset) { | ||
639 | BUGPRINT("Standard target size too big\n"); | 641 | BUGPRINT("Standard target size too big\n"); |
640 | ret = -EFAULT; | 642 | ret = -EFAULT; |
641 | goto cleanup_watchers; | 643 | goto cleanup_watchers; |
@@ -646,8 +648,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, | |||
646 | ret = -EFAULT; | 648 | ret = -EFAULT; |
647 | goto cleanup_watchers; | 649 | goto cleanup_watchers; |
648 | } | 650 | } |
649 | } else if ((e->target_offset + t->target_size + | 651 | } else if (t->target_size > gap - sizeof(struct ebt_entry_target) || |
650 | sizeof(struct ebt_entry_target) > e->next_offset) || | ||
651 | (t->u.target->check && | 652 | (t->u.target->check && |
652 | t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ | 653 | t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ |
653 | module_put(t->u.target->me); | 654 | module_put(t->u.target->me); |