aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDmitry Mishin <dim@openvz.org>2006-10-30 18:14:27 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-10-30 18:24:47 -0500
commit920b868ae1dfdac77c5e8c97e7067b23680f043e (patch)
treecec854f186e6ac37ea0b599f34a44fbfe7d49d2c /net/ipv4
parentc073e3fa8b7f9841aa6451885f135656d455f511 (diff)
[NETFILTER]: ip_tables: compat code module refcounting fix
This patch fixes bug in iptables modules refcounting on compat error way. As we are getting modules in check_compat_entry_size_and_hooks(), in case of later error, we should put them all in translate_compat_table(), not in the compat_copy_entry_from_user() or compat_copy_match_from_user(), as it is now. Signed-off-by: Dmitry Mishin <dim@openvz.org> Acked-by: Vasily Averin <vvs@openvz.org> Acked-by: Kirill Korotaev <dev@openvz.org> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/ip_tables.c36
1 files changed, 11 insertions, 25 deletions
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 0f4835cf0e4d..8a455439b128 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1527,7 +1527,7 @@ cleanup_matches:
1527 1527
1528static inline int compat_copy_match_from_user(struct ipt_entry_match *m, 1528static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1529 void **dstptr, compat_uint_t *size, const char *name, 1529 void **dstptr, compat_uint_t *size, const char *name,
1530 const struct ipt_ip *ip, unsigned int hookmask, int *i) 1530 const struct ipt_ip *ip, unsigned int hookmask)
1531{ 1531{
1532 struct ipt_entry_match *dm; 1532 struct ipt_entry_match *dm;
1533 struct ipt_match *match; 1533 struct ipt_match *match;
@@ -1540,22 +1540,13 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1540 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), 1540 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1541 name, hookmask, ip->proto, 1541 name, hookmask, ip->proto,
1542 ip->invflags & IPT_INV_PROTO); 1542 ip->invflags & IPT_INV_PROTO);
1543 if (ret) 1543 if (!ret && m->u.kernel.match->checkentry
1544 goto err;
1545
1546 if (m->u.kernel.match->checkentry
1547 && !m->u.kernel.match->checkentry(name, ip, match, dm->data, 1544 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1548 hookmask)) { 1545 hookmask)) {
1549 duprintf("ip_tables: check failed for `%s'.\n", 1546 duprintf("ip_tables: check failed for `%s'.\n",
1550 m->u.kernel.match->name); 1547 m->u.kernel.match->name);
1551 ret = -EINVAL; 1548 ret = -EINVAL;
1552 goto err;
1553 } 1549 }
1554 (*i)++;
1555 return 0;
1556
1557err:
1558 module_put(m->u.kernel.match->me);
1559 return ret; 1550 return ret;
1560} 1551}
1561 1552
@@ -1567,19 +1558,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1567 struct ipt_target *target; 1558 struct ipt_target *target;
1568 struct ipt_entry *de; 1559 struct ipt_entry *de;
1569 unsigned int origsize; 1560 unsigned int origsize;
1570 int ret, h, j; 1561 int ret, h;
1571 1562
1572 ret = 0; 1563 ret = 0;
1573 origsize = *size; 1564 origsize = *size;
1574 de = (struct ipt_entry *)*dstptr; 1565 de = (struct ipt_entry *)*dstptr;
1575 memcpy(de, e, sizeof(struct ipt_entry)); 1566 memcpy(de, e, sizeof(struct ipt_entry));
1576 1567
1577 j = 0;
1578 *dstptr += sizeof(struct compat_ipt_entry); 1568 *dstptr += sizeof(struct compat_ipt_entry);
1579 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, 1569 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1580 name, &de->ip, de->comefrom, &j); 1570 name, &de->ip, de->comefrom);
1581 if (ret) 1571 if (ret)
1582 goto cleanup_matches; 1572 goto err;
1583 de->target_offset = e->target_offset - (origsize - *size); 1573 de->target_offset = e->target_offset - (origsize - *size);
1584 t = ipt_get_target(e); 1574 t = ipt_get_target(e);
1585 target = t->u.kernel.target; 1575 target = t->u.kernel.target;
@@ -1613,12 +1603,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1613 goto err; 1603 goto err;
1614 } 1604 }
1615 ret = 0; 1605 ret = 0;
1616 return ret;
1617
1618err: 1606err:
1619 module_put(t->u.kernel.target->me);
1620cleanup_matches:
1621 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1622 return ret; 1607 return ret;
1623} 1608}
1624 1609
@@ -1632,7 +1617,7 @@ translate_compat_table(const char *name,
1632 unsigned int *hook_entries, 1617 unsigned int *hook_entries,
1633 unsigned int *underflows) 1618 unsigned int *underflows)
1634{ 1619{
1635 unsigned int i; 1620 unsigned int i, j;
1636 struct xt_table_info *newinfo, *info; 1621 struct xt_table_info *newinfo, *info;
1637 void *pos, *entry0, *entry1; 1622 void *pos, *entry0, *entry1;
1638 unsigned int size; 1623 unsigned int size;
@@ -1650,21 +1635,21 @@ translate_compat_table(const char *name,
1650 } 1635 }
1651 1636
1652 duprintf("translate_compat_table: size %u\n", info->size); 1637 duprintf("translate_compat_table: size %u\n", info->size);
1653 i = 0; 1638 j = 0;
1654 xt_compat_lock(AF_INET); 1639 xt_compat_lock(AF_INET);
1655 /* Walk through entries, checking offsets. */ 1640 /* Walk through entries, checking offsets. */
1656 ret = IPT_ENTRY_ITERATE(entry0, total_size, 1641 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1657 check_compat_entry_size_and_hooks, 1642 check_compat_entry_size_and_hooks,
1658 info, &size, entry0, 1643 info, &size, entry0,
1659 entry0 + total_size, 1644 entry0 + total_size,
1660 hook_entries, underflows, &i, name); 1645 hook_entries, underflows, &j, name);
1661 if (ret != 0) 1646 if (ret != 0)
1662 goto out_unlock; 1647 goto out_unlock;
1663 1648
1664 ret = -EINVAL; 1649 ret = -EINVAL;
1665 if (i != number) { 1650 if (j != number) {
1666 duprintf("translate_compat_table: %u not %u entries\n", 1651 duprintf("translate_compat_table: %u not %u entries\n",
1667 i, number); 1652 j, number);
1668 goto out_unlock; 1653 goto out_unlock;
1669 } 1654 }
1670 1655
@@ -1723,6 +1708,7 @@ translate_compat_table(const char *name,
1723free_newinfo: 1708free_newinfo:
1724 xt_free_table_info(newinfo); 1709 xt_free_table_info(newinfo);
1725out: 1710out:
1711 IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
1726 return ret; 1712 return ret;
1727out_unlock: 1713out_unlock:
1728 compat_flush_offsets(); 1714 compat_flush_offsets();