Skip to content

Commit

Permalink
[NETFILTER]: ip_tables: ipt and ipt_compat checks unification
Browse files Browse the repository at this point in the history
Matches and targets verification is duplicated in normal and compat processing
ways. This patch refactors code in order to remove this.

Signed-off-by: Dmitry Mishin <dim@openvz.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dmitry Mishin authored and David S. Miller committed Dec 14, 2006
1 parent 11078c3 commit a96be24
Showing 1 changed file with 79 additions and 97 deletions.
176 changes: 79 additions & 97 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,47 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
}

static inline int
check_match(struct ipt_entry_match *m,
check_entry(struct ipt_entry *e, const char *name)
{
struct ipt_entry_target *t;

if (!ip_checkentry(&e->ip)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
return -EINVAL;
}

if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
return -EINVAL;

t = ipt_get_target(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;

return 0;
}

static inline int 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: check failed for `%s'.\n",
m->u.kernel.match->name);
ret = -EINVAL;
}
return ret;
}

static inline int
find_check_match(struct ipt_entry_match *m,
const char *name,
const struct ipt_ip *ip,
unsigned int hookmask,
Expand All @@ -497,87 +537,78 @@ check_match(struct ipt_entry_match *m,
m->u.user.revision),
"ipt_%s", m->u.user.name);
if (IS_ERR(match) || !match) {
duprintf("check_match: `%s' not found\n", m->u.user.name);
duprintf("find_check_match: `%s' not found\n", m->u.user.name);
return match ? PTR_ERR(match) : -ENOENT;
}
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);
ret = check_match(m, name, ip, hookmask);
if (ret)
goto err;

if (m->u.kernel.match->checkentry
&& !m->u.kernel.match->checkentry(name, ip, match, m->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 struct ipt_target ipt_standard_target;
static inline int 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 && t->u.kernel.target->checkentry
&& !t->u.kernel.target->checkentry(name, e, target,
t->data, e->comefrom)) {
duprintf("ip_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
ret = -EINVAL;
}
return ret;
}

static inline int
check_entry(struct ipt_entry *e, const char *name, unsigned int size,
find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
unsigned int *i)
{
struct ipt_entry_target *t;
struct ipt_target *target;
int ret;
unsigned int j;

if (!ip_checkentry(&e->ip)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
return -EINVAL;
}

if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
return -EINVAL;
ret = check_entry(e, name);
if (ret)
return ret;

j = 0;
ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
ret = IPT_MATCH_ITERATE(e, find_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),
"ipt_%s", t->u.user.name);
if (IS_ERR(target) || !target) {
duprintf("check_entry: `%s' not found\n", t->u.user.name);
duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
goto cleanup_matches;
}
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);
ret = check_target(e, name);
if (ret)
goto err;

if (t->u.kernel.target->checkentry
&& !t->u.kernel.target->checkentry(name, e, target, t->data,
e->comefrom)) {
duprintf("ip_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
ret = -EINVAL;
goto err;
}

(*i)++;
return 0;
err:
Expand Down Expand Up @@ -712,7 +743,7 @@ translate_table(const char *name,
/* Finally, each sanity check must pass */
i = 0;
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i);
find_check_entry, name, size, &i);

if (ret != 0) {
IPT_ENTRY_ITERATE(entry0, newinfo->size,
Expand Down Expand Up @@ -1452,14 +1483,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
return -EINVAL;
}

if (!ip_checkentry(&e->ip)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
return -EINVAL;
}

if (e->target_offset + sizeof(struct compat_xt_entry_target) >
e->next_offset)
return -EINVAL;
ret = check_entry(e, name);
if (ret)
return ret;

off = 0;
entry_offset = (void *)e - (void *)base;
Expand All @@ -1470,15 +1496,13 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
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),
"ipt_%s", t->u.user.name);
if (IS_ERR(target) || !target) {
duprintf("check_entry: `%s' not found\n", t->u.user.name);
duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
goto cleanup_matches;
}
Expand Down Expand Up @@ -1555,57 +1579,15 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
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);
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)) {
duprintf("ip_tables: compat: check failed for `%s'.\n",
t->u.kernel.target->name);
ret = -EINVAL;
}
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);
ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom);
if (ret)
return ret;

return compat_check_target(e, name);
return check_target(e, name);
}

static int
Expand Down

0 comments on commit a96be24

Please sign in to comment.