aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-09-20 15:04:08 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:19:59 -0400
commitbec71b162747708d4b45b0cd399b484f52f2901a (patch)
tree50f93845e00c9aed07383b9c9b003a2749672fd4
parent1192e403e9ea2dc23bbbe2b4fe9bdbc47e8c6056 (diff)
[NETFILTER]: ip_tables: fix module refcount leaks in compat error paths
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.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 38e1e4fba0db..3d5d4a4640c3 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1529,7 +1529,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
1529 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip, 1529 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1530 e->comefrom, &off, &j); 1530 e->comefrom, &off, &j);
1531 if (ret != 0) 1531 if (ret != 0)
1532 goto out; 1532 goto cleanup_matches;
1533 1533
1534 t = ipt_get_target(e); 1534 t = ipt_get_target(e);
1535 target = try_then_request_module(xt_find_target(AF_INET, 1535 target = try_then_request_module(xt_find_target(AF_INET,
@@ -1539,7 +1539,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
1539 if (IS_ERR(target) || !target) { 1539 if (IS_ERR(target) || !target) {
1540 duprintf("check_entry: `%s' not found\n", t->u.user.name); 1540 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1541 ret = target ? PTR_ERR(target) : -ENOENT; 1541 ret = target ? PTR_ERR(target) : -ENOENT;
1542 goto out; 1542 goto cleanup_matches;
1543 } 1543 }
1544 t->u.kernel.target = target; 1544 t->u.kernel.target = target;
1545 1545
@@ -1566,14 +1566,17 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
1566 1566
1567 (*i)++; 1567 (*i)++;
1568 return 0; 1568 return 0;
1569
1569out: 1570out:
1571 module_put(t->u.kernel.target->me);
1572cleanup_matches:
1570 IPT_MATCH_ITERATE(e, cleanup_match, &j); 1573 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1571 return ret; 1574 return ret;
1572} 1575}
1573 1576
1574static inline int compat_copy_match_from_user(struct ipt_entry_match *m, 1577static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1575 void **dstptr, compat_uint_t *size, const char *name, 1578 void **dstptr, compat_uint_t *size, const char *name,
1576 const struct ipt_ip *ip, unsigned int hookmask) 1579 const struct ipt_ip *ip, unsigned int hookmask, int *i)
1577{ 1580{
1578 struct ipt_entry_match *dm; 1581 struct ipt_entry_match *dm;
1579 struct ipt_match *match; 1582 struct ipt_match *match;
@@ -1590,16 +1593,22 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1590 name, hookmask, ip->proto, 1593 name, hookmask, ip->proto,
1591 ip->invflags & IPT_INV_PROTO); 1594 ip->invflags & IPT_INV_PROTO);
1592 if (ret) 1595 if (ret)
1593 return ret; 1596 goto err;
1594 1597
1595 if (m->u.kernel.match->checkentry 1598 if (m->u.kernel.match->checkentry
1596 && !m->u.kernel.match->checkentry(name, ip, match, dm->data, 1599 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1597 hookmask)) { 1600 hookmask)) {
1598 duprintf("ip_tables: check failed for `%s'.\n", 1601 duprintf("ip_tables: check failed for `%s'.\n",
1599 m->u.kernel.match->name); 1602 m->u.kernel.match->name);
1600 return -EINVAL; 1603 ret = -EINVAL;
1604 goto err;
1601 } 1605 }
1606 (*i)++;
1602 return 0; 1607 return 0;
1608
1609err:
1610 module_put(m->u.kernel.match->me);
1611 return ret;
1603} 1612}
1604 1613
1605static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, 1614static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
@@ -1610,18 +1619,19 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1610 struct ipt_target *target; 1619 struct ipt_target *target;
1611 struct ipt_entry *de; 1620 struct ipt_entry *de;
1612 unsigned int origsize; 1621 unsigned int origsize;
1613 int ret, h; 1622 int ret, h, j;
1614 1623
1615 ret = 0; 1624 ret = 0;
1616 origsize = *size; 1625 origsize = *size;
1617 de = (struct ipt_entry *)*dstptr; 1626 de = (struct ipt_entry *)*dstptr;
1618 memcpy(de, e, sizeof(struct ipt_entry)); 1627 memcpy(de, e, sizeof(struct ipt_entry));
1619 1628
1629 j = 0;
1620 *dstptr += sizeof(struct compat_ipt_entry); 1630 *dstptr += sizeof(struct compat_ipt_entry);
1621 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, 1631 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1622 name, &de->ip, de->comefrom); 1632 name, &de->ip, de->comefrom, &j);
1623 if (ret) 1633 if (ret)
1624 goto out; 1634 goto cleanup_matches;
1625 de->target_offset = e->target_offset - (origsize - *size); 1635 de->target_offset = e->target_offset - (origsize - *size);
1626 t = ipt_get_target(e); 1636 t = ipt_get_target(e);
1627 target = t->u.kernel.target; 1637 target = t->u.kernel.target;
@@ -1644,21 +1654,26 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1644 name, e->comefrom, e->ip.proto, 1654 name, e->comefrom, e->ip.proto,
1645 e->ip.invflags & IPT_INV_PROTO); 1655 e->ip.invflags & IPT_INV_PROTO);
1646 if (ret) 1656 if (ret)
1647 goto out; 1657 goto err;
1648 1658
1649 ret = -EINVAL; 1659 ret = -EINVAL;
1650 if (t->u.kernel.target == &ipt_standard_target) { 1660 if (t->u.kernel.target == &ipt_standard_target) {
1651 if (!standard_check(t, *size)) 1661 if (!standard_check(t, *size))
1652 goto out; 1662 goto err;
1653 } else if (t->u.kernel.target->checkentry 1663 } else if (t->u.kernel.target->checkentry
1654 && !t->u.kernel.target->checkentry(name, de, target, 1664 && !t->u.kernel.target->checkentry(name, de, target,
1655 t->data, de->comefrom)) { 1665 t->data, de->comefrom)) {
1656 duprintf("ip_tables: compat: check failed for `%s'.\n", 1666 duprintf("ip_tables: compat: check failed for `%s'.\n",
1657 t->u.kernel.target->name); 1667 t->u.kernel.target->name);
1658 goto out; 1668 goto err;
1659 } 1669 }
1660 ret = 0; 1670 ret = 0;
1661out: 1671 return ret;
1672
1673err:
1674 module_put(t->u.kernel.target->me);
1675cleanup_matches:
1676 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1662 return ret; 1677 return ret;
1663} 1678}
1664 1679