Commit fff29291 authored by Elena Reshetova's avatar Elena Reshetova Committed by James Morris

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: default avatarElena Reshetova <elena.reshetova@intel.com>
Signed-off-by: default avatarHans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarDavid Windsor <dwindsor@gmail.com>
Acked-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarJames Morris <james.l.morris@oracle.com>
parent 8291798d
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/assoc_array.h> #include <linux/assoc_array.h>
#include <linux/refcount.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/uidgid.h> #include <linux/uidgid.h>
...@@ -135,7 +136,7 @@ static inline bool is_key_possessed(const key_ref_t key_ref) ...@@ -135,7 +136,7 @@ static inline bool is_key_possessed(const key_ref_t key_ref)
* - Kerberos TGTs and tickets * - Kerberos TGTs and tickets
*/ */
struct key { struct key {
atomic_t usage; /* number of references */ refcount_t usage; /* number of references */
key_serial_t serial; /* key serial number */ key_serial_t serial; /* key serial number */
union { union {
struct list_head graveyard_link; struct list_head graveyard_link;
...@@ -242,7 +243,7 @@ extern void key_put(struct key *key); ...@@ -242,7 +243,7 @@ extern void key_put(struct key *key);
static inline struct key *__key_get(struct key *key) static inline struct key *__key_get(struct key *key)
{ {
atomic_inc(&key->usage); refcount_inc(&key->usage);
return key; return key;
} }
......
...@@ -220,7 +220,7 @@ static void key_garbage_collector(struct work_struct *work) ...@@ -220,7 +220,7 @@ static void key_garbage_collector(struct work_struct *work)
key = rb_entry(cursor, struct key, serial_node); key = rb_entry(cursor, struct key, serial_node);
cursor = rb_next(cursor); cursor = rb_next(cursor);
if (atomic_read(&key->usage) == 0) if (refcount_read(&key->usage) == 0)
goto found_unreferenced_key; goto found_unreferenced_key;
if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) {
......
...@@ -285,7 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, ...@@ -285,7 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
if (!key->index_key.description) if (!key->index_key.description)
goto no_memory_3; goto no_memory_3;
atomic_set(&key->usage, 1); refcount_set(&key->usage, 1);
init_rwsem(&key->sem); init_rwsem(&key->sem);
lockdep_set_class(&key->sem, &type->lock_class); lockdep_set_class(&key->sem, &type->lock_class);
key->index_key.type = type; key->index_key.type = type;
...@@ -621,7 +621,7 @@ void key_put(struct key *key) ...@@ -621,7 +621,7 @@ void key_put(struct key *key)
if (key) { if (key) {
key_check(key); key_check(key);
if (atomic_dec_and_test(&key->usage)) if (refcount_dec_and_test(&key->usage))
schedule_work(&key_gc_work); schedule_work(&key_gc_work);
} }
} }
...@@ -656,7 +656,7 @@ struct key *key_lookup(key_serial_t id) ...@@ -656,7 +656,7 @@ struct key *key_lookup(key_serial_t id)
found: found:
/* pretend it doesn't exist if it is awaiting deletion */ /* 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; goto not_found;
/* this races with key_put(), but that doesn't matter since key_put() /* this races with key_put(), but that doesn't matter since key_put()
......
...@@ -1033,7 +1033,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) ...@@ -1033,7 +1033,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
/* we've got a match but we might end up racing with /* we've got a match but we might end up racing with
* key_cleanup() if the keyring is currently 'dead' * key_cleanup() if the keyring is currently 'dead'
* (ie. it has a zero usage count) */ * (ie. it has a zero usage count) */
if (!atomic_inc_not_zero(&keyring->usage)) if (!refcount_inc_not_zero(&keyring->usage))
continue; continue;
keyring->last_used_at = current_kernel_time().tv_sec; keyring->last_used_at = current_kernel_time().tv_sec;
goto out; goto out;
...@@ -1250,14 +1250,14 @@ int key_link(struct key *keyring, struct key *key) ...@@ -1250,14 +1250,14 @@ int key_link(struct key *keyring, struct key *key)
struct assoc_array_edit *edit; struct assoc_array_edit *edit;
int ret; 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(keyring);
key_check(key); key_check(key);
ret = __key_link_begin(keyring, &key->index_key, &edit); ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) { 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); ret = __key_link_check_restriction(keyring, key);
if (ret == 0) if (ret == 0)
ret = __key_link_check_live_key(keyring, key); ret = __key_link_check_live_key(keyring, key);
...@@ -1266,7 +1266,7 @@ int key_link(struct key *keyring, struct key *key) ...@@ -1266,7 +1266,7 @@ int key_link(struct key *keyring, struct key *key)
__key_link_end(keyring, &key->index_key, edit); __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; return ret;
} }
EXPORT_SYMBOL(key_link); EXPORT_SYMBOL(key_link);
......
...@@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
showflag(key, 'N', KEY_FLAG_NEGATIVE), showflag(key, 'N', KEY_FLAG_NEGATIVE),
showflag(key, 'i', KEY_FLAG_INVALIDATED), showflag(key, 'i', KEY_FLAG_INVALIDATED),
atomic_read(&key->usage), refcount_read(&key->usage),
xbuf, xbuf,
key->perm, key->perm,
from_kuid_munged(seq_user_ns(m), key->uid), from_kuid_munged(seq_user_ns(m), key->uid),
......
...@@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, ...@@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
if (ret < 0) if (ret < 0)
goto error_inst; goto error_inst;
kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage));
return authkey; return authkey;
auth_key_revoked: auth_key_revoked:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment