security, keys: convert key.usage from atomic_t to refcount_t
refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <james.l.morris@oracle.com>
diff --git a/include/linux/key.h b/include/linux/key.h
index e45212f..9d9fac5 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -23,6 +23,7 @@
#include <linux/rwsem.h>
#include <linux/atomic.h>
#include <linux/assoc_array.h>
+#include <linux/refcount.h>
#ifdef __KERNEL__
#include <linux/uidgid.h>
@@ -135,7 +136,7 @@
* - Kerberos TGTs and tickets
*/
struct key {
- atomic_t usage; /* number of references */
+ refcount_t usage; /* number of references */
key_serial_t serial; /* key serial number */
union {
struct list_head graveyard_link;
@@ -242,7 +243,7 @@
static inline struct key *__key_get(struct key *key)
{
- atomic_inc(&key->usage);
+ refcount_inc(&key->usage);
return key;
}
diff --git a/security/keys/gc.c b/security/keys/gc.c
index addf060..4478925 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -220,7 +220,7 @@
key = rb_entry(cursor, struct key, serial_node);
cursor = rb_next(cursor);
- if (atomic_read(&key->usage) == 0)
+ if (refcount_read(&key->usage) == 0)
goto found_unreferenced_key;
if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) {
diff --git a/security/keys/key.c b/security/keys/key.c
index 346fbf2..ff92443 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -285,7 +285,7 @@
if (!key->index_key.description)
goto no_memory_3;
- atomic_set(&key->usage, 1);
+ refcount_set(&key->usage, 1);
init_rwsem(&key->sem);
lockdep_set_class(&key->sem, &type->lock_class);
key->index_key.type = type;
@@ -621,7 +621,7 @@
if (key) {
key_check(key);
- if (atomic_dec_and_test(&key->usage))
+ if (refcount_dec_and_test(&key->usage))
schedule_work(&key_gc_work);
}
}
@@ -656,7 +656,7 @@
found:
/* pretend it doesn't exist if it is awaiting deletion */
- if (atomic_read(&key->usage) == 0)
+ if (refcount_read(&key->usage) == 0)
goto not_found;
/* this races with key_put(), but that doesn't matter since key_put()
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index c91e4e0..3d95f7d 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1033,7 +1033,7 @@
/* 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))
+ if (!refcount_inc_not_zero(&keyring->usage))
continue;
keyring->last_used_at = current_kernel_time().tv_sec;
goto out;
@@ -1250,14 +1250,14 @@
struct assoc_array_edit *edit;
int ret;
- kenter("{%d,%d}", keyring->serial, atomic_read(&keyring->usage));
+ kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
key_check(keyring);
key_check(key);
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) {
- kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
+ kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
ret = __key_link_check_restriction(keyring, key);
if (ret == 0)
ret = __key_link_check_live_key(keyring, key);
@@ -1266,7 +1266,7 @@
__key_link_end(keyring, &key->index_key, edit);
}
- kleave(" = %d {%d,%d}", ret, keyring->serial, atomic_read(&keyring->usage));
+ kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage));
return ret;
}
EXPORT_SYMBOL(key_link);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index b9f531c..69199f1 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -252,7 +252,7 @@
showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
showflag(key, 'N', KEY_FLAG_NEGATIVE),
showflag(key, 'i', KEY_FLAG_INVALIDATED),
- atomic_read(&key->usage),
+ refcount_read(&key->usage),
xbuf,
key->perm,
from_kuid_munged(seq_user_ns(m), key->uid),
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 6bbe2f5..0f06215 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -213,7 +213,7 @@
if (ret < 0)
goto error_inst;
- kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage));
+ kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage));
return authkey;
auth_key_revoked: