aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/netfilter/ip_tables.c78
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
1540static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, 1523static 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
1558static 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
1578static 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 }
1588err:
1589 return ret; 1596 return ret;
1590} 1597}
1591 1598
1599static 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
1592static int 1611static int
1593translate_compat_table(const char *name, 1612translate_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)