diff options
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 121 |
1 files changed, 5 insertions, 116 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index f7f9d93..4414abd 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -21,7 +21,7 @@ #include <linux/user_namespace.h> #include "internal.h" -static struct kmem_cache *key_jar; +struct kmem_cache *key_jar; struct rb_root key_serial_tree; /* tree of keys indexed by serial */ DEFINE_SPINLOCK(key_serial_lock); @@ -36,17 +36,9 @@ unsigned int key_quota_maxbytes = 20000; /* general key space quota */ static LIST_HEAD(key_types_list); static DECLARE_RWSEM(key_types_sem); -static void key_cleanup(struct work_struct *work); -static DECLARE_WORK(key_cleanup_task, key_cleanup); - /* We serialise key instantiation and link */ DEFINE_MUTEX(key_construction_mutex); -/* Any key who's type gets unegistered will be re-typed to this */ -static struct key_type key_type_dead = { - .name = "dead", -}; - #ifdef KEY_DEBUGGING void __key_check(const struct key *key) { @@ -591,71 +583,6 @@ int key_reject_and_link(struct key *key, } EXPORT_SYMBOL(key_reject_and_link); -/* - * Garbage collect keys in process context so that we don't have to disable - * interrupts all over the place. - * - * key_put() schedules this rather than trying to do the cleanup itself, which - * means key_put() doesn't have to sleep. - */ -static void key_cleanup(struct work_struct *work) -{ - struct rb_node *_n; - struct key *key; - -go_again: - /* look for a dead key in the tree */ - spin_lock(&key_serial_lock); - - for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { - key = rb_entry(_n, struct key, serial_node); - - if (atomic_read(&key->usage) == 0) - goto found_dead_key; - } - - spin_unlock(&key_serial_lock); - return; - -found_dead_key: - /* we found a dead key - once we've removed it from the tree, we can - * drop the lock */ - rb_erase(&key->serial_node, &key_serial_tree); - spin_unlock(&key_serial_lock); - - key_check(key); - - security_key_free(key); - - /* deal with the user's key tracking and quota */ - if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { - spin_lock(&key->user->lock); - key->user->qnkeys--; - key->user->qnbytes -= key->quotalen; - spin_unlock(&key->user->lock); - } - - atomic_dec(&key->user->nkeys); - if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) - atomic_dec(&key->user->nikeys); - - key_user_put(key->user); - - /* now throw away the key memory */ - if (key->type->destroy) - key->type->destroy(key); - - kfree(key->description); - -#ifdef KEY_DEBUGGING - key->magic = KEY_DEBUG_MAGIC_X; -#endif - kmem_cache_free(key_jar, key); - - /* there may, of course, be more than one key to destroy */ - goto go_again; -} - /** * key_put - Discard a reference to a key. * @key: The key to discard a reference from. @@ -670,7 +597,7 @@ void key_put(struct key *key) key_check(key); if (atomic_dec_and_test(&key->usage)) - schedule_work(&key_cleanup_task); + queue_work(system_nrt_wq, &key_gc_work); } } EXPORT_SYMBOL(key_put); @@ -1048,49 +975,11 @@ EXPORT_SYMBOL(register_key_type); */ void unregister_key_type(struct key_type *ktype) { - struct rb_node *_n; - struct key *key; - down_write(&key_types_sem); - - /* withdraw the key type */ list_del_init(&ktype->link); - - /* mark all the keys of this type dead */ - spin_lock(&key_serial_lock); - - for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { - key = rb_entry(_n, struct key, serial_node); - - if (key->type == ktype) { - key->type = &key_type_dead; - set_bit(KEY_FLAG_DEAD, &key->flags); - } - } - - spin_unlock(&key_serial_lock); - - /* make sure everyone revalidates their keys */ - synchronize_rcu(); - - /* we should now be able to destroy the payloads of all the keys of - * this type with impunity */ - spin_lock(&key_serial_lock); - - for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { - key = rb_entry(_n, struct key, serial_node); - - if (key->type == ktype) { - if (ktype->destroy) - ktype->destroy(key); - memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); - } - } - - spin_unlock(&key_serial_lock); - up_write(&key_types_sem); - - key_schedule_gc(0); + downgrade_write(&key_types_sem); + key_gc_keytype(ktype); + up_read(&key_types_sem); } EXPORT_SYMBOL(unregister_key_type); |