--- zzzz-none-000/linux-2.6.19.2/net/ipv4/netfilter/ip_tables.c 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5505/linux-2.6.19.2/net/ipv4/netfilter/ip_tables.c 2007-01-19 14:42:56.000000000 +0000 @@ -540,18 +540,12 @@ return -EINVAL; } - if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset) - return -EINVAL; - j = 0; ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); if (ret != 0) goto cleanup_matches; t = ipt_get_target(e); - ret = -EINVAL; - if (e->target_offset + t->u.target_size > e->next_offset) - goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -716,7 +710,7 @@ if (ret != 0) { IPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, &i); return ret; } @@ -1457,10 +1451,6 @@ return -EINVAL; } - if (e->target_offset + sizeof(struct compat_xt_entry_target) > - e->next_offset) - return -EINVAL; - off = 0; entry_offset = (void *)e - (void *)base; j = 0; @@ -1470,9 +1460,6 @@ goto cleanup_matches; t = ipt_get_target(e); - ret = -EINVAL; - if (e->target_offset + t->u.target_size > e->next_offset) - goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -1514,10 +1501,36 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, void **dstptr, compat_uint_t *size, const char *name, - const struct ipt_ip *ip, unsigned int hookmask) + const struct ipt_ip *ip, unsigned int hookmask, int *i) { + struct ipt_entry_match *dm; + struct ipt_match *match; + int ret; + + dm = (struct ipt_entry_match *)*dstptr; + match = m->u.kernel.match; xt_compat_match_from_user(m, dstptr, size); + + ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), + name, hookmask, ip->proto, + ip->invflags & IPT_INV_PROTO); + if (ret) + goto err; + + if (m->u.kernel.match->checkentry + && !m->u.kernel.match->checkentry(name, ip, match, dm->data, + hookmask)) { + duprintf("ip_tables: check failed for `%s'.\n", + m->u.kernel.match->name); + ret = -EINVAL; + goto err; + } + (*i)++; return 0; + +err: + module_put(m->u.kernel.match->me); + return ret; } static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, @@ -1528,18 +1541,19 @@ struct ipt_target *target; struct ipt_entry *de; unsigned int origsize; - int ret, h; + int ret, h, j; ret = 0; origsize = *size; de = (struct ipt_entry *)*dstptr; memcpy(de, e, sizeof(struct ipt_entry)); + j = 0; *dstptr += sizeof(struct compat_ipt_entry); ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, - name, &de->ip, de->comefrom); + name, &de->ip, de->comefrom, &j); if (ret) - return ret; + goto cleanup_matches; de->target_offset = e->target_offset - (origsize - *size); t = ipt_get_target(e); target = t->u.kernel.target; @@ -1552,60 +1566,34 @@ if ((unsigned char *)de - base < newinfo->underflow[h]) newinfo->underflow[h] -= origsize - *size; } - return ret; -} - -static inline int compat_check_match(struct ipt_entry_match *m, const char *name, - const struct ipt_ip *ip, unsigned int hookmask) -{ - struct ipt_match *match; - int ret; - - match = m->u.kernel.match; - ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m), - name, hookmask, ip->proto, - ip->invflags & IPT_INV_PROTO); - if (!ret && m->u.kernel.match->checkentry - && !m->u.kernel.match->checkentry(name, ip, match, m->data, - hookmask)) { - duprintf("ip_tables: compat: check failed for `%s'.\n", - m->u.kernel.match->name); - ret = -EINVAL; - } - return ret; -} -static inline int compat_check_target(struct ipt_entry *e, const char *name) -{ - struct ipt_entry_target *t; - struct ipt_target *target; - int ret; - - t = ipt_get_target(e); + t = ipt_get_target(de); target = t->u.kernel.target; ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), name, e->comefrom, e->ip.proto, e->ip.invflags & IPT_INV_PROTO); - if (!ret && t->u.kernel.target->checkentry - && !t->u.kernel.target->checkentry(name, e, target, - t->data, e->comefrom)) { + if (ret) + goto err; + + ret = -EINVAL; + if (t->u.kernel.target == &ipt_standard_target) { + if (!standard_check(t, *size)) + goto err; + } else if (t->u.kernel.target->checkentry + && !t->u.kernel.target->checkentry(name, de, target, + t->data, de->comefrom)) { duprintf("ip_tables: compat: check failed for `%s'.\n", t->u.kernel.target->name); - ret = -EINVAL; + goto err; } + ret = 0; return ret; -} - -static inline int compat_check_entry(struct ipt_entry *e, const char *name) -{ - int ret; - ret = IPT_MATCH_ITERATE(e, compat_check_match, name, &e->ip, - e->comefrom); - if (ret) - return ret; - - return compat_check_target(e, name); +err: + module_put(t->u.kernel.target->me); +cleanup_matches: + IPT_MATCH_ITERATE(e, cleanup_match, &j); + return ret; } static int @@ -1618,7 +1606,7 @@ unsigned int *hook_entries, unsigned int *underflows) { - unsigned int i, j; + unsigned int i; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; unsigned int size; @@ -1636,21 +1624,21 @@ } duprintf("translate_compat_table: size %u\n", info->size); - j = 0; + i = 0; xt_compat_lock(AF_INET); /* Walk through entries, checking offsets. */ ret = IPT_ENTRY_ITERATE(entry0, total_size, check_compat_entry_size_and_hooks, info, &size, entry0, entry0 + total_size, - hook_entries, underflows, &j, name); + hook_entries, underflows, &i, name); if (ret != 0) goto out_unlock; ret = -EINVAL; - if (j != number) { + if (i != number) { duprintf("translate_compat_table: %u not %u entries\n", - j, number); + i, number); goto out_unlock; } @@ -1714,10 +1702,8 @@ free_newinfo: xt_free_table_info(newinfo); out: - IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j); return ret; out_unlock: - compat_flush_offsets(); xt_compat_unlock(AF_INET); goto out; }