aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDmitry Mishin <dim@openvz.org>2006-10-30 18:12:55 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-10-30 18:24:44 -0500
commit590bdf7fd2292b47c428111cb1360e312eff207e (patch)
treec44b60a5e40b5e16e3478aecb839825b4a602ced /net/ipv6
parent844dc7c88046ecd2e52596730d7cc400d6c3ad67 (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.c24
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;
780cleanup:
781 IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
774 return ret; 782 return ret;
775} 783}
776 784