[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;
 	}