Skip to content

Commit

Permalink
[NETFILTER]: Fix iptables compat hook validation
Browse files Browse the repository at this point in the history
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 <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 7, 2006
1 parent 74c9c0c commit f6677f4
Showing 1 changed file with 51 additions and 27 deletions.
78 changes: 51 additions & 27 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1516,25 +1516,8 @@ 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)
{
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,
Expand All @@ -1556,7 +1539,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
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;
Expand All @@ -1569,26 +1552,62 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
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(de);
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 *name,
unsigned int valid_hooks,
Expand Down Expand Up @@ -1677,6 +1696,11 @@ translate_compat_table(const char *name,
if (!mark_source_chains(newinfo, valid_hooks, entry1))
goto free_newinfo;

ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
name);
if (ret)
goto free_newinfo;

/* And one copy for every other CPU */
for_each_possible_cpu(i)
if (newinfo->entries[i] && newinfo->entries[i] != entry1)
Expand Down

0 comments on commit f6677f4

Please sign in to comment.