The rpc server does not require that service threads take the BKL.
[safe/jmp/linux-2.6] / security / keys / key.c
index a6ca39e..e50d264 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/workqueue.h>
 #include <linux/random.h>
 #include <linux/err.h>
+#include <linux/user_namespace.h>
 #include "internal.h"
 
 static struct kmem_cache       *key_jar;
@@ -60,7 +61,7 @@ void __key_check(const struct key *key)
  * get the key quota record for a user, allocating a new record if one doesn't
  * already exist
  */
-struct key_user *key_user_lookup(uid_t uid)
+struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
 {
        struct key_user *candidate = NULL, *user;
        struct rb_node *parent = NULL;
@@ -79,6 +80,10 @@ struct key_user *key_user_lookup(uid_t uid)
                        p = &(*p)->rb_left;
                else if (uid > user->uid)
                        p = &(*p)->rb_right;
+               else if (user_ns < user->user_ns)
+                       p = &(*p)->rb_left;
+               else if (user_ns > user->user_ns)
+                       p = &(*p)->rb_right;
                else
                        goto found;
        }
@@ -106,6 +111,7 @@ struct key_user *key_user_lookup(uid_t uid)
        atomic_set(&candidate->nkeys, 0);
        atomic_set(&candidate->nikeys, 0);
        candidate->uid = uid;
+       candidate->user_ns = get_user_ns(user_ns);
        candidate->qnkeys = 0;
        candidate->qnbytes = 0;
        spin_lock_init(&candidate->lock);
@@ -136,6 +142,7 @@ void key_user_put(struct key_user *user)
        if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
                rb_erase(&user->node, &key_user_tree);
                spin_unlock(&key_user_lock);
+               put_user_ns(user->user_ns);
 
                kfree(user);
        }
@@ -218,7 +225,7 @@ serial_exists:
  *   instantiate the key or discard it before returning
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
-                     uid_t uid, gid_t gid, struct task_struct *ctx,
+                     uid_t uid, gid_t gid, const struct cred *cred,
                      key_perm_t perm, unsigned long flags)
 {
        struct key_user *user = NULL;
@@ -234,7 +241,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        quotalen = desclen + type->def_datalen;
 
        /* get hold of the key tracking for this user */
-       user = key_user_lookup(uid);
+       user = key_user_lookup(uid, cred->user->user_ns);
        if (!user)
                goto no_memory_1;
 
@@ -294,7 +301,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 #endif
 
        /* let the security module know about the key */
-       ret = security_key_alloc(key, ctx, flags);
+       ret = security_key_alloc(key, cred, flags);
        if (ret < 0)
                goto security_error;
 
@@ -391,7 +398,7 @@ static int __key_instantiate_and_link(struct key *key,
                                      const void *data,
                                      size_t datalen,
                                      struct key *keyring,
-                                     struct key *instkey)
+                                     struct key *authkey)
 {
        int ret, awaken;
 
@@ -421,8 +428,8 @@ static int __key_instantiate_and_link(struct key *key,
                                ret = __key_link(keyring, key);
 
                        /* disable the authorisation key */
-                       if (instkey)
-                               key_revoke(instkey);
+                       if (authkey)
+                               key_revoke(authkey);
                }
        }
 
@@ -444,14 +451,14 @@ int key_instantiate_and_link(struct key *key,
                             const void *data,
                             size_t datalen,
                             struct key *keyring,
-                            struct key *instkey)
+                            struct key *authkey)
 {
        int ret;
 
        if (keyring)
                down_write(&keyring->sem);
 
-       ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
+       ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);
 
        if (keyring)
                up_write(&keyring->sem);
@@ -469,7 +476,7 @@ EXPORT_SYMBOL(key_instantiate_and_link);
 int key_negate_and_link(struct key *key,
                        unsigned timeout,
                        struct key *keyring,
-                       struct key *instkey)
+                       struct key *authkey)
 {
        struct timespec now;
        int ret, awaken;
@@ -493,6 +500,7 @@ int key_negate_and_link(struct key *key,
                set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
                now = current_kernel_time();
                key->expiry = now.tv_sec + timeout;
+               key_schedule_gc(key->expiry + key_gc_delay);
 
                if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
                        awaken = 1;
@@ -504,8 +512,8 @@ int key_negate_and_link(struct key *key,
                        ret = __key_link(keyring, key);
 
                /* disable the authorisation key */
-               if (instkey)
-                       key_revoke(instkey);
+               if (authkey)
+                       key_revoke(authkey);
        }
 
        mutex_unlock(&key_construction_mutex);
@@ -635,10 +643,8 @@ struct key *key_lookup(key_serial_t id)
        goto error;
 
  found:
-       /* pretend it doesn't exist if it's dead */
-       if (atomic_read(&key->usage) == 0 ||
-           test_bit(KEY_FLAG_DEAD, &key->flags) ||
-           key->type == &key_type_dead)
+       /* pretend it doesn't exist if it is awaiting deletion */
+       if (atomic_read(&key->usage) == 0)
                goto not_found;
 
        /* this races with key_put(), but that doesn't matter since key_put()
@@ -743,6 +749,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               key_perm_t perm,
                               unsigned long flags)
 {
+       const struct cred *cred = current_cred();
        struct key_type *ktype;
        struct key *keyring, *key = NULL;
        key_ref_t key_ref;
@@ -802,8 +809,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        }
 
        /* allocate a new key */
-       key = key_alloc(ktype, description, current_fsuid(), current_fsgid(),
-                       current, perm, flags);
+       key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
+                       perm, flags);
        if (IS_ERR(key)) {
                key_ref = ERR_CAST(key);
                goto error_3;
@@ -882,6 +889,9 @@ EXPORT_SYMBOL(key_update);
  */
 void key_revoke(struct key *key)
 {
+       struct timespec now;
+       time_t time;
+
        key_check(key);
 
        /* make sure no one's trying to change or use the key when we mark it
@@ -894,6 +904,14 @@ void key_revoke(struct key *key)
            key->type->revoke)
                key->type->revoke(key);
 
+       /* set the death time to no more than the expiry time */
+       now = current_kernel_time();
+       time = now.tv_sec;
+       if (key->revoked_at == 0 || key->revoked_at > time) {
+               key->revoked_at = time;
+               key_schedule_gc(key->revoked_at + key_gc_delay);
+       }
+
        up_write(&key->sem);
 
 } /* end key_revoke() */
@@ -950,8 +968,10 @@ void unregister_key_type(struct key_type *ktype)
        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 (key->type == ktype) {
                        key->type = &key_type_dead;
+                       set_bit(KEY_FLAG_DEAD, &key->flags);
+               }
        }
 
        spin_unlock(&key_serial_lock);
@@ -976,6 +996,8 @@ void unregister_key_type(struct key_type *ktype)
        spin_unlock(&key_serial_lock);
        up_write(&key_types_sem);
 
+       key_schedule_gc(0);
+
 } /* end unregister_key_type() */
 
 EXPORT_SYMBOL(unregister_key_type);