diff options
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 129 |
1 files changed, 82 insertions, 47 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index b73e6b6d5546..655c221acd1a 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -607,11 +607,55 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | |||
607 | } | 607 | } |
608 | 608 | ||
609 | static inline int | 609 | static inline int |
610 | check_match(struct ip6t_entry_match *m, | 610 | check_entry(struct ip6t_entry *e, const char *name) |
611 | const char *name, | 611 | { |
612 | const struct ip6t_ip6 *ipv6, | 612 | struct ip6t_entry_target *t; |
613 | unsigned int hookmask, | 613 | |
614 | unsigned int *i) | 614 | if (!ip6_checkentry(&e->ipv6)) { |
615 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | |||
619 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | ||
620 | e->next_offset) | ||
621 | return -EINVAL; | ||
622 | |||
623 | t = ip6t_get_target(e); | ||
624 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
625 | return -EINVAL; | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static inline int check_match(struct ip6t_entry_match *m, const char *name, | ||
631 | const struct ip6t_ip6 *ipv6, | ||
632 | unsigned int hookmask, unsigned int *i) | ||
633 | { | ||
634 | struct xt_match *match; | ||
635 | int ret; | ||
636 | |||
637 | match = m->u.kernel.match; | ||
638 | ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), | ||
639 | name, hookmask, ipv6->proto, | ||
640 | ipv6->invflags & IP6T_INV_PROTO); | ||
641 | if (!ret && m->u.kernel.match->checkentry | ||
642 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, | ||
643 | hookmask)) { | ||
644 | duprintf("ip_tables: check failed for `%s'.\n", | ||
645 | m->u.kernel.match->name); | ||
646 | ret = -EINVAL; | ||
647 | } | ||
648 | if (!ret) | ||
649 | (*i)++; | ||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static inline int | ||
654 | find_check_match(struct ip6t_entry_match *m, | ||
655 | const char *name, | ||
656 | const struct ip6t_ip6 *ipv6, | ||
657 | unsigned int hookmask, | ||
658 | unsigned int *i) | ||
615 | { | 659 | { |
616 | struct xt_match *match; | 660 | struct xt_match *match; |
617 | int ret; | 661 | int ret; |
@@ -620,86 +664,77 @@ check_match(struct ip6t_entry_match *m, | |||
620 | m->u.user.revision), | 664 | m->u.user.revision), |
621 | "ip6t_%s", m->u.user.name); | 665 | "ip6t_%s", m->u.user.name); |
622 | if (IS_ERR(match) || !match) { | 666 | if (IS_ERR(match) || !match) { |
623 | duprintf("check_match: `%s' not found\n", m->u.user.name); | 667 | duprintf("find_check_match: `%s' not found\n", m->u.user.name); |
624 | return match ? PTR_ERR(match) : -ENOENT; | 668 | return match ? PTR_ERR(match) : -ENOENT; |
625 | } | 669 | } |
626 | m->u.kernel.match = match; | 670 | m->u.kernel.match = match; |
627 | 671 | ||
628 | ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), | 672 | ret = check_match(m, name, ipv6, hookmask, i); |
629 | name, hookmask, ipv6->proto, | ||
630 | ipv6->invflags & IP6T_INV_PROTO); | ||
631 | if (ret) | 673 | if (ret) |
632 | goto err; | 674 | goto err; |
633 | 675 | ||
634 | if (m->u.kernel.match->checkentry | ||
635 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, | ||
636 | hookmask)) { | ||
637 | duprintf("ip_tables: check failed for `%s'.\n", | ||
638 | m->u.kernel.match->name); | ||
639 | ret = -EINVAL; | ||
640 | goto err; | ||
641 | } | ||
642 | |||
643 | (*i)++; | ||
644 | return 0; | 676 | return 0; |
645 | err: | 677 | err: |
646 | module_put(m->u.kernel.match->me); | 678 | module_put(m->u.kernel.match->me); |
647 | return ret; | 679 | return ret; |
648 | } | 680 | } |
649 | 681 | ||
650 | static inline int | 682 | static inline int check_target(struct ip6t_entry *e, const char *name) |
651 | check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | ||
652 | unsigned int *i) | ||
653 | { | 683 | { |
654 | struct ip6t_entry_target *t; | 684 | struct ip6t_entry_target *t; |
655 | struct xt_target *target; | 685 | struct xt_target *target; |
656 | int ret; | 686 | int ret; |
657 | unsigned int j; | ||
658 | 687 | ||
659 | if (!ip6_checkentry(&e->ipv6)) { | 688 | t = ip6t_get_target(e); |
660 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | 689 | target = t->u.kernel.target; |
661 | return -EINVAL; | 690 | ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), |
691 | name, e->comefrom, e->ipv6.proto, | ||
692 | e->ipv6.invflags & IP6T_INV_PROTO); | ||
693 | if (!ret && t->u.kernel.target->checkentry | ||
694 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | ||
695 | e->comefrom)) { | ||
696 | duprintf("ip_tables: check failed for `%s'.\n", | ||
697 | t->u.kernel.target->name); | ||
698 | ret = -EINVAL; | ||
662 | } | 699 | } |
700 | return ret; | ||
701 | } | ||
663 | 702 | ||
664 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | 703 | static inline int |
665 | e->next_offset) | 704 | find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, |
666 | return -EINVAL; | 705 | unsigned int *i) |
706 | { | ||
707 | struct ip6t_entry_target *t; | ||
708 | struct xt_target *target; | ||
709 | int ret; | ||
710 | unsigned int j; | ||
711 | |||
712 | ret = check_entry(e, name); | ||
713 | if (ret) | ||
714 | return ret; | ||
667 | 715 | ||
668 | j = 0; | 716 | j = 0; |
669 | ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); | 717 | ret = IP6T_MATCH_ITERATE(e, find_check_match, name, &e->ipv6, |
718 | e->comefrom, &j); | ||
670 | if (ret != 0) | 719 | if (ret != 0) |
671 | goto cleanup_matches; | 720 | goto cleanup_matches; |
672 | 721 | ||
673 | t = ip6t_get_target(e); | 722 | t = ip6t_get_target(e); |
674 | ret = -EINVAL; | ||
675 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
676 | goto cleanup_matches; | ||
677 | target = try_then_request_module(xt_find_target(AF_INET6, | 723 | target = try_then_request_module(xt_find_target(AF_INET6, |
678 | t->u.user.name, | 724 | t->u.user.name, |
679 | t->u.user.revision), | 725 | t->u.user.revision), |
680 | "ip6t_%s", t->u.user.name); | 726 | "ip6t_%s", t->u.user.name); |
681 | if (IS_ERR(target) || !target) { | 727 | if (IS_ERR(target) || !target) { |
682 | duprintf("check_entry: `%s' not found\n", t->u.user.name); | 728 | duprintf("find_check_entry: `%s' not found\n", t->u.user.name); |
683 | ret = target ? PTR_ERR(target) : -ENOENT; | 729 | ret = target ? PTR_ERR(target) : -ENOENT; |
684 | goto cleanup_matches; | 730 | goto cleanup_matches; |
685 | } | 731 | } |
686 | t->u.kernel.target = target; | 732 | t->u.kernel.target = target; |
687 | 733 | ||
688 | ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), | 734 | ret = check_target(e, name); |
689 | name, e->comefrom, e->ipv6.proto, | ||
690 | e->ipv6.invflags & IP6T_INV_PROTO); | ||
691 | if (ret) | 735 | if (ret) |
692 | goto err; | 736 | goto err; |
693 | 737 | ||
694 | if (t->u.kernel.target->checkentry | ||
695 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | ||
696 | e->comefrom)) { | ||
697 | duprintf("ip_tables: check failed for `%s'.\n", | ||
698 | t->u.kernel.target->name); | ||
699 | ret = -EINVAL; | ||
700 | goto err; | ||
701 | } | ||
702 | |||
703 | (*i)++; | 738 | (*i)++; |
704 | return 0; | 739 | return 0; |
705 | err: | 740 | err: |
@@ -834,7 +869,7 @@ translate_table(const char *name, | |||
834 | /* Finally, each sanity check must pass */ | 869 | /* Finally, each sanity check must pass */ |
835 | i = 0; | 870 | i = 0; |
836 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 871 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, |
837 | check_entry, name, size, &i); | 872 | find_check_entry, name, size, &i); |
838 | 873 | ||
839 | if (ret != 0) { | 874 | if (ret != 0) { |
840 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 875 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, |