[NETFILTER]: Fix do_add_counters race, possible oops or info leak (CVE-2006-0039)
Linux Kernel Mailing List <[email protected]> Tue, 20 Jun 2006 14:59:02 GMT
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
commit 0e978d63375d579260d1eb930f5954f96cd37b7f tree 75f86d368a0de5b81040ff7908da59b52d538cd4 parent 11b2b42abac0225dd4cc71e8dbf9336a7b344cee author Solar Designer <[email protected]> Tue, 20 Jun 2006 13:04:17 -0700 committer David S. Miller <[email protected]> Tue, 20 Jun 2006 13:04:17 -0700 [NETFILTER]: Fix do_add_counters race, possible oops or info leak (CVE-2006-0039) Solar Designer found a race condition in do_add_counters(). The beginning of paddc is supposed to be the same as tmp which was sanity-checked above, but it might not be the same in reality. In case the integer overflow and/or the race condition are triggered, paddc->num_counters might not match the allocation size for paddc. If the check below (t->private->number != paddc->num_counters) nevertheless passes (perhaps this requires the race condition to be triggered), IPT_ENTRY_ITERATE() would read kernel memory beyond the allocation size, potentially causing an oops or leaking sensitive data (e.g., passwords from host system or from another VPS) via counter increments. This requires CAP_NET_ADMIN. Signed-off-by: Solar Designer <[email protected]> Signed-off-by: Kirill Korotaev <[email protected]> Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]> net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index d831080..dfc8b69 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -998,7 +998,7 @@ static int do_add_counters(void *user, u goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 416687b..4023022 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1202,7 +1202,7 @@ do_add_counters(void *user, unsigned int goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 02127ba..7c23298 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1283,7 +1283,7 @@ do_add_counters(void *user, unsigned int goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; }