[EBTABLES]: Prevent wraparounds in checks for entry components' sizes.
Al Viro [Fri, 1 Dec 2006 03:25:21 +0000 (19:25 -0800)]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/bridge/netfilter/ebtables.c

index 46ab9b7..136ed7d 100644 (file)
@@ -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);