diff options
author | Dmitry Mishin <dim@openvz.org> | 2006-12-05 16:44:07 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-06 21:39:03 -0500 |
commit | f6677f4312ee74f8ca68c4cc4060465607b72b41 (patch) | |
tree | 75cdd6d87c4ddbd2ae9080f205da86a76fa0118c | |
parent | 74c9c0c17dea729d6089c0c82762babd02e65f84 (diff) |
[NETFILTER]: Fix iptables compat hook validation
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>
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2bddf8491982..0ff2956d35e5 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -1516,25 +1516,8 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, | |||
1516 | void **dstptr, compat_uint_t *size, const char *name, | 1516 | void **dstptr, compat_uint_t *size, const char *name, |
1517 | const struct ipt_ip *ip, unsigned int hookmask) | 1517 | const struct ipt_ip *ip, unsigned int hookmask) |
1518 | { | 1518 | { |
1519 | struct ipt_entry_match *dm; | ||
1520 | struct ipt_match *match; | ||
1521 | int ret; | ||
1522 | |||
1523 | dm = (struct ipt_entry_match *)*dstptr; | ||
1524 | match = m->u.kernel.match; | ||
1525 | xt_compat_match_from_user(m, dstptr, size); | 1519 | xt_compat_match_from_user(m, dstptr, size); |
1526 | 1520 | return 0; | |
1527 | ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), | ||
1528 | name, hookmask, ip->proto, | ||
1529 | ip->invflags & IPT_INV_PROTO); | ||
1530 | if (!ret && m->u.kernel.match->checkentry | ||
1531 | && !m->u.kernel.match->checkentry(name, ip, match, dm->data, | ||
1532 | hookmask)) { | ||
1533 | duprintf("ip_tables: check failed for `%s'.\n", | ||
1534 | m->u.kernel.match->name); | ||
1535 | ret = -EINVAL; | ||
1536 | } | ||
1537 | return ret; | ||
1538 | } | 1521 | } |
1539 | 1522 | ||
1540 | static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | 1523 | static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, |
@@ -1556,7 +1539,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1556 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, | 1539 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, |
1557 | name, &de->ip, de->comefrom); | 1540 | name, &de->ip, de->comefrom); |
1558 | if (ret) | 1541 | if (ret) |
1559 | goto err; | 1542 | return ret; |
1560 | de->target_offset = e->target_offset - (origsize - *size); | 1543 | de->target_offset = e->target_offset - (origsize - *size); |
1561 | t = ipt_get_target(e); | 1544 | t = ipt_get_target(e); |
1562 | target = t->u.kernel.target; | 1545 | target = t->u.kernel.target; |
@@ -1569,26 +1552,62 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1569 | if ((unsigned char *)de - base < newinfo->underflow[h]) | 1552 | if ((unsigned char *)de - base < newinfo->underflow[h]) |
1570 | newinfo->underflow[h] -= origsize - *size; | 1553 | newinfo->underflow[h] -= origsize - *size; |
1571 | } | 1554 | } |
1555 | return ret; | ||
1556 | } | ||
1557 | |||
1558 | static inline int compat_check_match(struct ipt_entry_match *m, const char *name, | ||
1559 | const struct ipt_ip *ip, unsigned int hookmask) | ||
1560 | { | ||
1561 | struct ipt_match *match; | ||
1562 | int ret; | ||
1563 | |||
1564 | match = m->u.kernel.match; | ||
1565 | ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m), | ||
1566 | name, hookmask, ip->proto, | ||
1567 | ip->invflags & IPT_INV_PROTO); | ||
1568 | if (!ret && m->u.kernel.match->checkentry | ||
1569 | && !m->u.kernel.match->checkentry(name, ip, match, m->data, | ||
1570 | hookmask)) { | ||
1571 | duprintf("ip_tables: compat: check failed for `%s'.\n", | ||
1572 | m->u.kernel.match->name); | ||
1573 | ret = -EINVAL; | ||
1574 | } | ||
1575 | return ret; | ||
1576 | } | ||
1577 | |||
1578 | static inline int compat_check_target(struct ipt_entry *e, const char *name) | ||
1579 | { | ||
1580 | struct ipt_entry_target *t; | ||
1581 | struct ipt_target *target; | ||
1582 | int ret; | ||
1572 | 1583 | ||
1573 | t = ipt_get_target(de); | 1584 | t = ipt_get_target(e); |
1574 | target = t->u.kernel.target; | 1585 | target = t->u.kernel.target; |
1575 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), | 1586 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), |
1576 | name, e->comefrom, e->ip.proto, | 1587 | name, e->comefrom, e->ip.proto, |
1577 | e->ip.invflags & IPT_INV_PROTO); | 1588 | e->ip.invflags & IPT_INV_PROTO); |
1578 | if (ret) | 1589 | if (!ret && t->u.kernel.target->checkentry |
1579 | goto err; | 1590 | && !t->u.kernel.target->checkentry(name, e, target, |
1580 | 1591 | t->data, e->comefrom)) { | |
1581 | if (t->u.kernel.target->checkentry | ||
1582 | && !t->u.kernel.target->checkentry(name, de, target, | ||
1583 | t->data, de->comefrom)) { | ||
1584 | duprintf("ip_tables: compat: check failed for `%s'.\n", | 1592 | duprintf("ip_tables: compat: check failed for `%s'.\n", |
1585 | t->u.kernel.target->name); | 1593 | t->u.kernel.target->name); |
1586 | ret = -EINVAL; | 1594 | ret = -EINVAL; |
1587 | } | 1595 | } |
1588 | err: | ||
1589 | return ret; | 1596 | return ret; |
1590 | } | 1597 | } |
1591 | 1598 | ||
1599 | static inline int compat_check_entry(struct ipt_entry *e, const char *name) | ||
1600 | { | ||
1601 | int ret; | ||
1602 | |||
1603 | ret = IPT_MATCH_ITERATE(e, compat_check_match, name, &e->ip, | ||
1604 | e->comefrom); | ||
1605 | if (ret) | ||
1606 | return ret; | ||
1607 | |||
1608 | return compat_check_target(e, name); | ||
1609 | } | ||
1610 | |||
1592 | static int | 1611 | static int |
1593 | translate_compat_table(const char *name, | 1612 | translate_compat_table(const char *name, |
1594 | unsigned int valid_hooks, | 1613 | unsigned int valid_hooks, |
@@ -1677,6 +1696,11 @@ translate_compat_table(const char *name, | |||
1677 | if (!mark_source_chains(newinfo, valid_hooks, entry1)) | 1696 | if (!mark_source_chains(newinfo, valid_hooks, entry1)) |
1678 | goto free_newinfo; | 1697 | goto free_newinfo; |
1679 | 1698 | ||
1699 | ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | ||
1700 | name); | ||
1701 | if (ret) | ||
1702 | goto free_newinfo; | ||
1703 | |||
1680 | /* And one copy for every other CPU */ | 1704 | /* And one copy for every other CPU */ |
1681 | for_each_possible_cpu(i) | 1705 | for_each_possible_cpu(i) |
1682 | if (newinfo->entries[i] && newinfo->entries[i] != entry1) | 1706 | if (newinfo->entries[i] && newinfo->entries[i] != entry1) |