diff options
author | Dmitry Mishin <dim@openvz.org> | 2006-10-30 18:12:55 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-10-30 18:24:44 -0500 |
commit | 590bdf7fd2292b47c428111cb1360e312eff207e (patch) | |
tree | c44b60a5e40b5e16e3478aecb839825b4a602ced /net/ipv6 | |
parent | 844dc7c88046ecd2e52596730d7cc400d6c3ad67 (diff) |
[NETFILTER]: Missed and reordered checks in {arp,ip,ip6}_tables
There is a number of issues in parsing user-provided table in
translate_table(). Malicious user with CAP_NET_ADMIN may crash system by
passing special-crafted table to the *_tables.
The first issue is that mark_source_chains() function is called before entry
content checks. In case of standard target, mark_source_chains() function
uses t->verdict field in order to determine new position. But the check, that
this field leads no further, than the table end, is in check_entry(), which
is called later, than mark_source_chains().
The second issue, that there is no check that target_offset points inside
entry. If so, *_ITERATE_MATCH macro will follow further, than the entry
ends. As a result, we'll have oops or memory disclosure.
And the third issue, that there is no check that the target is completely
inside entry. Results are the same, as in previous issue.
Signed-off-by: Dmitry Mishin <dim@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/ipv6')
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 53bf977cca63..167c2ea88f6b 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -586,12 +586,19 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
586 | return -EINVAL; | 586 | return -EINVAL; |
587 | } | 587 | } |
588 | 588 | ||
589 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | ||
590 | e->next_offset) | ||
591 | return -EINVAL; | ||
592 | |||
589 | j = 0; | 593 | j = 0; |
590 | ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); | 594 | ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); |
591 | if (ret != 0) | 595 | if (ret != 0) |
592 | goto cleanup_matches; | 596 | goto cleanup_matches; |
593 | 597 | ||
594 | t = ip6t_get_target(e); | 598 | t = ip6t_get_target(e); |
599 | ret = -EINVAL; | ||
600 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
601 | goto cleanup_matches; | ||
595 | target = try_then_request_module(xt_find_target(AF_INET6, | 602 | target = try_then_request_module(xt_find_target(AF_INET6, |
596 | t->u.user.name, | 603 | t->u.user.name, |
597 | t->u.user.revision), | 604 | t->u.user.revision), |
@@ -751,19 +758,17 @@ translate_table(const char *name, | |||
751 | } | 758 | } |
752 | } | 759 | } |
753 | 760 | ||
754 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | ||
755 | return -ELOOP; | ||
756 | |||
757 | /* Finally, each sanity check must pass */ | 761 | /* Finally, each sanity check must pass */ |
758 | i = 0; | 762 | i = 0; |
759 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 763 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, |
760 | check_entry, name, size, &i); | 764 | check_entry, name, size, &i); |
761 | 765 | ||
762 | if (ret != 0) { | 766 | if (ret != 0) |
763 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 767 | goto cleanup; |
764 | cleanup_entry, &i); | 768 | |
765 | return ret; | 769 | ret = -ELOOP; |
766 | } | 770 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) |
771 | goto cleanup; | ||
767 | 772 | ||
768 | /* And one copy for every other CPU */ | 773 | /* And one copy for every other CPU */ |
769 | for_each_possible_cpu(i) { | 774 | for_each_possible_cpu(i) { |
@@ -771,6 +776,9 @@ translate_table(const char *name, | |||
771 | memcpy(newinfo->entries[i], entry0, newinfo->size); | 776 | memcpy(newinfo->entries[i], entry0, newinfo->size); |
772 | } | 777 | } |
773 | 778 | ||
779 | return 0; | ||
780 | cleanup: | ||
781 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); | ||
774 | return ret; | 782 | return ret; |
775 | } | 783 | } |
776 | 784 | ||