diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7d7ab94a7a2e73abef1f804174aed3c94abf86ac..2fdf75da7a707b6952e4549811842781e938cd69 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -480,6 +480,11 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i } t->u.kernel.target = target; + ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t), + name, e->comefrom, 0, 0); + if (ret) + goto err; + if (t->u.kernel.target == &arpt_standard_target) { if (!standard_check(t, size)) { ret = -EINVAL; @@ -490,16 +495,16 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i t->u.target_size - sizeof(*t), e->comefrom)) { - module_put(t->u.kernel.target->me); duprintf("arp_tables: check failed for `%s'.\n", t->u.kernel.target->name); ret = -EINVAL; - goto out; + goto err; } (*i)++; return 0; - +err: + module_put(t->u.kernel.target->me); out: return ret; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 16f47c675fefd8304d86174f6d4beeebdec6539b..f884ca223295208b8e3aa566b964c897e4043cdf 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -508,6 +508,7 @@ check_match(struct ipt_entry_match *m, unsigned int *i) { struct ipt_match *match; + int ret; match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, m->u.user.revision), @@ -518,18 +519,27 @@ check_match(struct ipt_entry_match *m, } m->u.kernel.match = 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) + goto err; + if (m->u.kernel.match->checkentry && !m->u.kernel.match->checkentry(name, ip, m->data, m->u.match_size - sizeof(*m), hookmask)) { - module_put(m->u.kernel.match->me); duprintf("ip_tables: check failed for `%s'.\n", m->u.kernel.match->name); - return -EINVAL; + ret = -EINVAL; + goto err; } (*i)++; return 0; +err: + module_put(m->u.kernel.match->me); + return ret; } static struct ipt_target ipt_standard_target; @@ -565,6 +575,12 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, } t->u.kernel.target = 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 == &ipt_standard_target) { if (!standard_check(t, size)) { ret = -EINVAL; @@ -575,16 +591,16 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, t->u.target_size - sizeof(*t), e->comefrom)) { - module_put(t->u.kernel.target->me); duprintf("ip_tables: check failed for `%s'.\n", t->u.kernel.target->name); ret = -EINVAL; - goto cleanup_matches; + goto err; } (*i)++; return 0; - + err: + module_put(t->u.kernel.target->me); cleanup_matches: IPT_MATCH_ITERATE(e, cleanup_match, &j); return ret; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74ff56c322f47ee45b3b873e4672d0bc9c13511a..1cd70683f2e2a52bf1c8a314bb8c37aa20d33ad4 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -575,6 +575,7 @@ check_match(struct ip6t_entry_match *m, unsigned int *i) { struct ip6t_match *match; + int ret; match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, m->u.user.revision), @@ -585,18 +586,27 @@ check_match(struct ip6t_entry_match *m, } m->u.kernel.match = match; + ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), + name, hookmask, ipv6->proto, + ipv6->invflags & IP6T_INV_PROTO); + if (ret) + goto err; + if (m->u.kernel.match->checkentry && !m->u.kernel.match->checkentry(name, ipv6, m->data, m->u.match_size - sizeof(*m), hookmask)) { - module_put(m->u.kernel.match->me); duprintf("ip_tables: check failed for `%s'.\n", m->u.kernel.match->name); - return -EINVAL; + ret = -EINVAL; + goto err; } (*i)++; return 0; +err: + module_put(m->u.kernel.match->me); + return ret; } static struct ip6t_target ip6t_standard_target; @@ -632,6 +642,12 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, } t->u.kernel.target = target; + ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), + name, e->comefrom, e->ipv6.proto, + e->ipv6.invflags & IP6T_INV_PROTO); + if (ret) + goto err; + if (t->u.kernel.target == &ip6t_standard_target) { if (!standard_check(t, size)) { ret = -EINVAL; @@ -642,16 +658,16 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, t->u.target_size - sizeof(*t), e->comefrom)) { - module_put(t->u.kernel.target->me); duprintf("ip_tables: check failed for `%s'.\n", t->u.kernel.target->name); ret = -EINVAL; - goto cleanup_matches; + goto err; } (*i)++; return 0; - + err: + module_put(t->u.kernel.target->me); cleanup_matches: IP6T_MATCH_ITERATE(e, cleanup_match, &j); return ret;