[patch 13/32] NETFILTER: Fix iptables compat hook validation
-stable review patch. If anyone has any objections, please let us know. -- From: Dmitry Mishin <[EMAIL PROTECTED]> In compat mode, matches and targets valid hooks checks always successful due to not initialized e->comefrom field yet. This patch separates this checks from translation code and moves them after mark_source_chains() call, where these marks are initialized. Signed-off-by: Dmitry Mishin <[EMAIL PROTECTED]> Signed-off-by; Patrick McHardy <[EMAIL PROTECTED]> Signed-off-by: Chris Wright <[EMAIL PROTECTED]> --- commit 14f5487cb9bd34cd59360d2cac7dccac9b27e8ce tree fab7cabcdb7fe450ff47bf42918f845ff3da1b86 parent 756c508367e95d6f963502e4feecb8c76aeee332 author Dmitry Mishin <[EMAIL PROTECTED]> Mon, 04 Dec 2006 12:19:35 +0100 committer Patrick McHardy <[EMAIL PROTECTED]> Mon, 04 Dec 2006 12:19:35 +0100 net/ipv4/netfilter/ip_tables.c | 78 ++--- 1 file changed, 51 insertions(+), 27 deletions(-) --- linux-2.6.19.orig/net/ipv4/netfilter/ip_tables.c +++ linux-2.6.19/net/ipv4/netfilter/ip_tables.c @@ -1516,25 +1516,8 @@ static inline int compat_copy_match_from void **dstptr, compat_uint_t *size, const char *name, const struct ipt_ip *ip, unsigned int hookmask) { - 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 && 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; - } - return ret; + return 0; } static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, @@ -1556,7 +1539,7 @@ static int compat_copy_entry_from_user(s ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, name, >ip, de->comefrom); if (ret) - goto err; + return ret; de->target_offset = e->target_offset - (origsize - *size); t = ipt_get_target(e); target = t->u.kernel.target; @@ -1569,26 +1552,62 @@ static int compat_copy_entry_from_user(s 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; - t = ipt_get_target(de); + 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); 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) - goto err; - - if (t->u.kernel.target->checkentry - && !t->u.kernel.target->checkentry(name, de, target, - t->data, de->comefrom)) { + if (!ret && t->u.kernel.target->checkentry + && !t->u.kernel.target->checkentry(name, e, target, + t->data, e->comefrom)) { duprintf("ip_tables: compat: check failed for `%s'.\n", t->u.kernel.target->name); ret = -EINVAL; } -err: 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, >ip, + e->comefrom); + if (ret) + return ret; + + return
[patch 13/32] NETFILTER: Fix iptables compat hook validation
-stable review patch. If anyone has any objections, please let us know. -- From: Dmitry Mishin [EMAIL PROTECTED] In compat mode, matches and targets valid hooks checks always successful due to not initialized e-comefrom field yet. This patch separates this checks from translation code and moves them after mark_source_chains() call, where these marks are initialized. Signed-off-by: Dmitry Mishin [EMAIL PROTECTED] Signed-off-by; Patrick McHardy [EMAIL PROTECTED] Signed-off-by: Chris Wright [EMAIL PROTECTED] --- commit 14f5487cb9bd34cd59360d2cac7dccac9b27e8ce tree fab7cabcdb7fe450ff47bf42918f845ff3da1b86 parent 756c508367e95d6f963502e4feecb8c76aeee332 author Dmitry Mishin [EMAIL PROTECTED] Mon, 04 Dec 2006 12:19:35 +0100 committer Patrick McHardy [EMAIL PROTECTED] Mon, 04 Dec 2006 12:19:35 +0100 net/ipv4/netfilter/ip_tables.c | 78 ++--- 1 file changed, 51 insertions(+), 27 deletions(-) --- linux-2.6.19.orig/net/ipv4/netfilter/ip_tables.c +++ linux-2.6.19/net/ipv4/netfilter/ip_tables.c @@ -1516,25 +1516,8 @@ static inline int compat_copy_match_from void **dstptr, compat_uint_t *size, const char *name, const struct ipt_ip *ip, unsigned int hookmask) { - 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 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; - } - return ret; + return 0; } static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, @@ -1556,7 +1539,7 @@ static int compat_copy_entry_from_user(s ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, name, de-ip, de-comefrom); if (ret) - goto err; + return ret; de-target_offset = e-target_offset - (origsize - *size); t = ipt_get_target(e); target = t-u.kernel.target; @@ -1569,26 +1552,62 @@ static int compat_copy_entry_from_user(s 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; - t = ipt_get_target(de); + 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); 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) - goto err; - - if (t-u.kernel.target-checkentry - !t-u.kernel.target-checkentry(name, de, target, - t-data, de-comefrom)) { + if (!ret t-u.kernel.target-checkentry + !t-u.kernel.target-checkentry(name, e, target, + t-data, e-comefrom)) { duprintf(ip_tables: compat: check failed for `%s'.\n, t-u.kernel.target-name); ret = -EINVAL; } -err: 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); +} + static int translate_compat_table(const char