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() */