Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2007

kernel-2.6.18-238.el5.src.rpm

From: Vitaly Mayatskikh <vmayatsk@redhat.com>
Date: Tue, 18 May 2010 08:22:55 -0400
Subject: [misc] keys: do not find already freed keyrings
Message-id: <87tyq5obz4.wl%vmayatsk@redhat.com>
Patchwork-id: 25162
O-Subject: [RHEL-5.5 patch] bz585100: CVE-2010-1437 kernel: keyrings:
	find_keyring_by_name() can gain the freed keyring
Bugzilla: 585100
CVE: CVE-2010-1437
RH-Acked-by: David Howells <dhowells@redhat.com>

Description:
============
>From bz:

Reported by Toshiyuki Okajima. With linux-2.6.34-rc5, find_keyring_by_name()
can gain the keyring which has been already freed. And then, its space (which
is gained by find_keyring_by_name()) is broken by accessing the freed keyring
as the available keyring:

1) If the space of the freed keyring is reallocated for other purpose (ie. filp
SLUB), the data of the filp object may be destroyed by the user of the freed
keyring. (SLUB configuration can share the freed space with other same-size
slabs.)

2) If the slab space of the freed keyring is released into the system, the
system panic may happen because accessing the space of the freed keyring causes
the page-fault.

Upstream status:
================
commit cea7daa3589d6b550546a8c8963599f7c1a3ae5c

This patch is clear re-apply to RHEL-5 sources.

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index e8d02ac..d55e9ce 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -495,9 +495,8 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
 	struct key *keyring;
 	int bucket;
 
-	keyring = ERR_PTR(-EINVAL);
 	if (!name)
-		goto error;
+		return ERR_PTR(-EINVAL);
 
 	bucket = keyring_hash(name);
 
@@ -525,17 +524,18 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
 			if (keyring->serial <= bound)
 				continue;
 
-			/* we've got a match */
-			atomic_inc(&keyring->usage);
-			read_unlock(&keyring_name_lock);
-			goto error;
+			/* we've got a match but we might end up racing with
+			 * key_cleanup() if the keyring is currently 'dead'
+			 * (ie. it has a zero usage count) */
+			if (!atomic_inc_not_zero(&keyring->usage))
+				continue;
+			goto out;
 		}
 	}
 
-	read_unlock(&keyring_name_lock);
 	keyring = ERR_PTR(-ENOKEY);
-
- error:
+out:
+	read_unlock(&keyring_name_lock);
 	return keyring;
 
 } /* end find_keyring_by_name() */