CRED: Use RCU to access another task's creds and to release a task's own creds
[linux-3.10.git] / security / keys / process_keys.c
index 566b1cc..212601e 100644 (file)
@@ -1,6 +1,6 @@
-/* process_keys.c: management of a process's keyrings
+/* Management of a process's keyrings
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
 /* session keyring create vs join semaphore */
-static DECLARE_MUTEX(key_session_sem);
+static DEFINE_MUTEX(key_session_mutex);
+
+/* user keyring creation semaphore */
+static DEFINE_MUTEX(key_user_keyring_mutex);
 
 /* the root user's tracking struct */
 struct key_user root_key_user = {
        .usage          = ATOMIC_INIT(3),
-       .consq          = LIST_HEAD_INIT(root_key_user.consq),
-       .lock           = SPIN_LOCK_UNLOCKED,
+       .cons_lock      = __MUTEX_INITIALIZER(root_key_user.cons_lock),
+       .lock           = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
        .nkeys          = ATOMIC_INIT(2),
        .nikeys         = ATOMIC_INIT(2),
        .uid            = 0,
 };
 
-/* the root user's UID keyring */
-struct key root_user_keyring = {
-       .usage          = ATOMIC_INIT(1),
-       .serial         = 2,
-       .type           = &key_type_keyring,
-       .user           = &root_key_user,
-       .sem            = __RWSEM_INITIALIZER(root_user_keyring.sem),
-       .perm           = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-       .flags          = 1 << KEY_FLAG_INSTANTIATED,
-       .description    = "_uid.0",
-#ifdef KEY_DEBUGGING
-       .magic          = KEY_DEBUG_MAGIC,
-#endif
-};
-
-/* the root user's default session keyring */
-struct key root_session_keyring = {
-       .usage          = ATOMIC_INIT(1),
-       .serial         = 1,
-       .type           = &key_type_keyring,
-       .user           = &root_key_user,
-       .sem            = __RWSEM_INITIALIZER(root_session_keyring.sem),
-       .perm           = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-       .flags          = 1 << KEY_FLAG_INSTANTIATED,
-       .description    = "_uid_ses.0",
-#ifdef KEY_DEBUGGING
-       .magic          = KEY_DEBUG_MAGIC,
-#endif
-};
-
 /*****************************************************************************/
 /*
- * allocate the keyrings to be associated with a UID
+ * install user and user session keyrings for a particular UID
  */
-int alloc_uid_keyring(struct user_struct *user)
+int install_user_keyrings(void)
 {
+       struct user_struct *user = current->cred->user;
        struct key *uid_keyring, *session_keyring;
        char buf[20];
        int ret;
 
-       /* concoct a default session keyring */
-       sprintf(buf, "_uid_ses.%u", user->uid);
+       kenter("%p{%u}", user, user->uid);
 
-       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
-       if (IS_ERR(session_keyring)) {
-               ret = PTR_ERR(session_keyring);
-               goto error;
+       if (user->uid_keyring) {
+               kleave(" = 0 [exist]");
+               return 0;
        }
 
-       /* and a UID specific keyring, pointed to by the default session
-        * keyring */
-       sprintf(buf, "_uid.%u", user->uid);
+       mutex_lock(&key_user_keyring_mutex);
+       ret = 0;
 
-       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
-                                   session_keyring);
-       if (IS_ERR(uid_keyring)) {
-               key_put(session_keyring);
-               ret = PTR_ERR(uid_keyring);
-               goto error;
+       if (!user->uid_keyring) {
+               /* get the UID-specific keyring
+                * - there may be one in existence already as it may have been
+                *   pinned by a session, but the user_struct pointing to it
+                *   may have been destroyed by setuid */
+               sprintf(buf, "_uid.%u", user->uid);
+
+               uid_keyring = find_keyring_by_name(buf, true);
+               if (IS_ERR(uid_keyring)) {
+                       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
+                                                   current, KEY_ALLOC_IN_QUOTA,
+                                                   NULL);
+                       if (IS_ERR(uid_keyring)) {
+                               ret = PTR_ERR(uid_keyring);
+                               goto error;
+                       }
+               }
+
+               /* get a default session keyring (which might also exist
+                * already) */
+               sprintf(buf, "_uid_ses.%u", user->uid);
+
+               session_keyring = find_keyring_by_name(buf, true);
+               if (IS_ERR(session_keyring)) {
+                       session_keyring =
+                               keyring_alloc(buf, user->uid, (gid_t) -1,
+                                             current, KEY_ALLOC_IN_QUOTA,
+                                             NULL);
+                       if (IS_ERR(session_keyring)) {
+                               ret = PTR_ERR(session_keyring);
+                               goto error_release;
+                       }
+
+                       /* we install a link from the user session keyring to
+                        * the user keyring */
+                       ret = key_link(session_keyring, uid_keyring);
+                       if (ret < 0)
+                               goto error_release_both;
+               }
+
+               /* install the keyrings */
+               user->uid_keyring = uid_keyring;
+               user->session_keyring = session_keyring;
        }
 
-       /* install the keyrings */
-       user->uid_keyring = uid_keyring;
-       user->session_keyring = session_keyring;
-       ret = 0;
+       mutex_unlock(&key_user_keyring_mutex);
+       kleave(" = 0");
+       return 0;
 
+error_release_both:
+       key_put(session_keyring);
+error_release:
+       key_put(uid_keyring);
 error:
+       mutex_unlock(&key_user_keyring_mutex);
+       kleave(" = %d", ret);
        return ret;
-
-} /* end alloc_uid_keyring() */
+}
 
 /*****************************************************************************/
 /*
@@ -134,23 +147,25 @@ void switch_uid_keyring(struct user_struct *new_user)
 /*
  * install a fresh thread keyring, discarding the old one
  */
-int install_thread_keyring(struct task_struct *tsk)
+int install_thread_keyring(void)
 {
+       struct task_struct *tsk = current;
        struct key *keyring, *old;
        char buf[20];
        int ret;
 
        sprintf(buf, "_tid.%u", tsk->pid);
 
-       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+       keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
+                               KEY_ALLOC_QUOTA_OVERRUN, NULL);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        }
 
        task_lock(tsk);
-       old = tsk->thread_keyring;
-       tsk->thread_keyring = keyring;
+       old = tsk->cred->thread_keyring;
+       tsk->cred->thread_keyring = keyring;
        task_unlock(tsk);
 
        ret = 0;
@@ -165,29 +180,32 @@ error:
 /*
  * make sure a process keyring is installed
  */
-int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(void)
 {
-       unsigned long flags;
+       struct task_struct *tsk = current;
        struct key *keyring;
        char buf[20];
        int ret;
 
+       might_sleep();
+
        if (!tsk->signal->process_keyring) {
                sprintf(buf, "_pid.%u", tsk->tgid);
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
+                                       KEY_ALLOC_QUOTA_OVERRUN, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error;
                }
 
                /* attach keyring */
-               spin_lock_irqsave(&tsk->sighand->siglock, flags);
+               spin_lock_irq(&tsk->sighand->siglock);
                if (!tsk->signal->process_keyring) {
                        tsk->signal->process_keyring = keyring;
                        keyring = NULL;
                }
-               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               spin_unlock_irq(&tsk->sighand->siglock);
 
                key_put(keyring);
        }
@@ -203,41 +221,46 @@ error:
  * install a session keyring, discarding the old one
  * - if a keyring is not supplied, an empty one is invented
  */
-static int install_session_keyring(struct task_struct *tsk,
-                                  struct key *keyring)
+static int install_session_keyring(struct key *keyring)
 {
+       struct task_struct *tsk = current;
        unsigned long flags;
        struct key *old;
        char buf[20];
-       int ret;
+
+       might_sleep();
 
        /* create an empty session keyring */
        if (!keyring) {
                sprintf(buf, "_ses.%u", tsk->tgid);
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
-               if (IS_ERR(keyring)) {
-                       ret = PTR_ERR(keyring);
-                       goto error;
-               }
+               flags = KEY_ALLOC_QUOTA_OVERRUN;
+               if (tsk->signal->session_keyring)
+                       flags = KEY_ALLOC_IN_QUOTA;
+
+               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
+                                       flags, NULL);
+               if (IS_ERR(keyring))
+                       return PTR_ERR(keyring);
        }
        else {
                atomic_inc(&keyring->usage);
        }
 
        /* install the keyring */
-       spin_lock_irqsave(&tsk->sighand->siglock, flags);
-       old = rcu_dereference(tsk->signal->session_keyring);
+       spin_lock_irq(&tsk->sighand->siglock);
+       old = tsk->signal->session_keyring;
        rcu_assign_pointer(tsk->signal->session_keyring, keyring);
-       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+       spin_unlock_irq(&tsk->sighand->siglock);
 
-       ret = 0;
+       /* we're using RCU on the pointer, but there's no point synchronising
+        * on it if it didn't previously point to anything */
+       if (old) {
+               synchronize_rcu();
+               key_put(old);
+       }
 
-       /* we're using RCU on the pointer */
-       synchronize_rcu();
-       key_put(old);
-error:
-       return ret;
+       return 0;
 
 } /* end install_session_keyring() */
 
@@ -269,10 +292,15 @@ int copy_thread_group_keys(struct task_struct *tsk)
  */
 int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
 {
-       key_check(tsk->thread_keyring);
+       key_check(tsk->cred->thread_keyring);
+       key_check(tsk->cred->request_key_auth);
 
        /* no thread keyring yet */
-       tsk->thread_keyring = NULL;
+       tsk->cred->thread_keyring = NULL;
+
+       /* copy the request_key() authorisation for this thread */
+       key_get(tsk->cred->request_key_auth);
+
        return 0;
 
 } /* end copy_keys() */
@@ -290,11 +318,12 @@ void exit_thread_group_keys(struct signal_struct *tg)
 
 /*****************************************************************************/
 /*
- * dispose of keys upon thread exit
+ * dispose of per-thread keys upon thread exit
  */
 void exit_keys(struct task_struct *tsk)
 {
-       key_put(tsk->thread_keyring);
+       key_put(tsk->cred->thread_keyring);
+       key_put(tsk->cred->request_key_auth);
 
 } /* end exit_keys() */
 
@@ -304,22 +333,21 @@ void exit_keys(struct task_struct *tsk)
  */
 int exec_keys(struct task_struct *tsk)
 {
-       unsigned long flags;
        struct key *old;
 
        /* newly exec'd tasks don't get a thread keyring */
        task_lock(tsk);
-       old = tsk->thread_keyring;
-       tsk->thread_keyring = NULL;
+       old = tsk->cred->thread_keyring;
+       tsk->cred->thread_keyring = NULL;
        task_unlock(tsk);
 
        key_put(old);
 
        /* discard the process keyring from a newly exec'd task */
-       spin_lock_irqsave(&tsk->sighand->siglock, flags);
+       spin_lock_irq(&tsk->sighand->siglock);
        old = tsk->signal->process_keyring;
        tsk->signal->process_keyring = NULL;
-       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+       spin_unlock_irq(&tsk->sighand->siglock);
 
        key_put(old);
 
@@ -345,10 +373,11 @@ int suid_keys(struct task_struct *tsk)
 void key_fsuid_changed(struct task_struct *tsk)
 {
        /* update the ownership of the thread keyring */
-       if (tsk->thread_keyring) {
-               down_write(&tsk->thread_keyring->sem);
-               tsk->thread_keyring->uid = tsk->fsuid;
-               up_write(&tsk->thread_keyring->sem);
+       BUG_ON(!tsk->cred);
+       if (tsk->cred->thread_keyring) {
+               down_write(&tsk->cred->thread_keyring->sem);
+               tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
+               up_write(&tsk->cred->thread_keyring->sem);
        }
 
 } /* end key_fsuid_changed() */
@@ -360,10 +389,11 @@ void key_fsuid_changed(struct task_struct *tsk)
 void key_fsgid_changed(struct task_struct *tsk)
 {
        /* update the ownership of the thread keyring */
-       if (tsk->thread_keyring) {
-               down_write(&tsk->thread_keyring->sem);
-               tsk->thread_keyring->gid = tsk->fsgid;
-               up_write(&tsk->thread_keyring->sem);
+       BUG_ON(!tsk->cred);
+       if (tsk->cred->thread_keyring) {
+               down_write(&tsk->cred->thread_keyring->sem);
+               tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
+               up_write(&tsk->cred->thread_keyring->sem);
        }
 
 } /* end key_fsgid_changed() */
@@ -382,7 +412,12 @@ key_ref_t search_process_keyrings(struct key_type *type,
                                  struct task_struct *context)
 {
        struct request_key_auth *rka;
-       key_ref_t key_ref, ret, err, instkey_ref;
+       struct cred *cred;
+       key_ref_t key_ref, ret, err;
+
+       might_sleep();
+
+       cred = get_task_cred(context);
 
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
@@ -396,9 +431,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
        err = ERR_PTR(-EAGAIN);
 
        /* search the thread keyring first */
-       if (context->thread_keyring) {
+       if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->thread_keyring, 1),
+                       make_key_ref(cred->thread_keyring, 1),
                        context, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
@@ -461,49 +496,11 @@ key_ref_t search_process_keyrings(struct key_type *type,
                        err = key_ref;
                        break;
                }
-
-               /* if this process has a session keyring and that has an
-                * instantiation authorisation key in the bottom level, then we
-                * also search the keyrings of the process mentioned there */
-               if (context != current)
-                       goto no_key;
-
-               rcu_read_lock();
-               instkey_ref = __keyring_search_one(
-                       make_key_ref(rcu_dereference(
-                                            context->signal->session_keyring),
-                                    1),
-                       &key_type_request_key_auth, NULL, 0);
-               rcu_read_unlock();
-
-               if (IS_ERR(instkey_ref))
-                       goto no_key;
-
-               rka = key_ref_to_ptr(instkey_ref)->payload.data;
-
-               key_ref = search_process_keyrings(type, description, match,
-                                                 rka->context);
-               key_ref_put(instkey_ref);
-
-               if (!IS_ERR(key_ref))
-                       goto found;
-
-               switch (PTR_ERR(key_ref)) {
-               case -EAGAIN: /* no key */
-                       if (ret)
-                               break;
-               case -ENOKEY: /* negative key */
-                       ret = key_ref;
-                       break;
-               default:
-                       err = key_ref;
-                       break;
-               }
        }
        /* or search the user-session keyring */
-       else {
+       else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->user->session_keyring, 1),
+                       make_key_ref(cred->user->session_keyring, 1),
                        context, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
@@ -521,12 +518,49 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
 
+       /* if this process has an instantiation authorisation key, then we also
+        * search the keyrings of the process mentioned there
+        * - we don't permit access to request_key auth keys via this method
+        */
+       if (cred->request_key_auth &&
+           context == current &&
+           type != &key_type_request_key_auth
+           ) {
+               /* defend against the auth key being revoked */
+               down_read(&cred->request_key_auth->sem);
+
+               if (key_validate(cred->request_key_auth) == 0) {
+                       rka = cred->request_key_auth->payload.data;
+
+                       key_ref = search_process_keyrings(type, description,
+                                                         match, rka->context);
+
+                       up_read(&cred->request_key_auth->sem);
+
+                       if (!IS_ERR(key_ref))
+                               goto found;
+
+                       switch (PTR_ERR(key_ref)) {
+                       case -EAGAIN: /* no key */
+                               if (ret)
+                                       break;
+                       case -ENOKEY: /* negative key */
+                               ret = key_ref;
+                               break;
+                       default:
+                               err = key_ref;
+                               break;
+                       }
+               } else {
+                       up_read(&cred->request_key_auth->sem);
+               }
+       }
 
-no_key:
        /* no key - decide on the error we're going to go for */
        key_ref = ret ? ret : err;
 
 found:
+       put_cred(cred);
        return key_ref;
 
 } /* end search_process_keyrings() */
@@ -547,78 +581,93 @@ static int lookup_user_key_possessed(const struct key *key, const void *target)
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
-                         int create, int partial, key_perm_t perm)
+key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+                         key_perm_t perm)
 {
-       key_ref_t key_ref, skey_ref;
+       struct request_key_auth *rka;
+       struct task_struct *t = current;
+       struct cred *cred = current_cred();
        struct key *key;
+       key_ref_t key_ref, skey_ref;
        int ret;
 
-       if (!context)
-               context = current;
-
        key_ref = ERR_PTR(-ENOKEY);
 
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
-               if (!context->thread_keyring) {
+               if (!cred->thread_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_thread_keyring(context);
+                       ret = install_thread_keyring();
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = context->thread_keyring;
+               key = cred->thread_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_PROCESS_KEYRING:
-               if (!context->signal->process_keyring) {
+               if (!t->signal->process_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_process_keyring(context);
+                       ret = install_process_keyring();
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = context->signal->process_keyring;
+               key = t->signal->process_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_SESSION_KEYRING:
-               if (!context->signal->session_keyring) {
+               if (!t->signal->session_keyring) {
                        /* always install a session keyring upon access if one
                         * doesn't exist yet */
+                       ret = install_user_keyrings();
+                       if (ret < 0)
+                               goto error;
                        ret = install_session_keyring(
-                               context, context->user->session_keyring);
+                               cred->user->session_keyring);
                        if (ret < 0)
                                goto error;
                }
 
                rcu_read_lock();
-               key = rcu_dereference(context->signal->session_keyring);
+               key = rcu_dereference(t->signal->session_keyring);
                atomic_inc(&key->usage);
                rcu_read_unlock();
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_USER_KEYRING:
-               key = context->user->uid_keyring;
+               if (!cred->user->uid_keyring) {
+                       ret = install_user_keyrings();
+                       if (ret < 0)
+                               goto error;
+               }
+
+               key = cred->user->uid_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_USER_SESSION_KEYRING:
-               key = context->user->session_keyring;
+               if (!cred->user->session_keyring) {
+                       ret = install_user_keyrings();
+                       if (ret < 0)
+                               goto error;
+               }
+
+               key = cred->user->session_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
@@ -628,6 +677,34 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                key = ERR_PTR(-EINVAL);
                goto error;
 
+       case KEY_SPEC_REQKEY_AUTH_KEY:
+               key = cred->request_key_auth;
+               if (!key)
+                       goto error;
+
+               atomic_inc(&key->usage);
+               key_ref = make_key_ref(key, 1);
+               break;
+
+       case KEY_SPEC_REQUESTOR_KEYRING:
+               if (!cred->request_key_auth)
+                       goto error;
+
+               down_read(&cred->request_key_auth->sem);
+               if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
+                       key_ref = ERR_PTR(-EKEYREVOKED);
+                       key = NULL;
+               } else {
+                       rka = cred->request_key_auth->payload.data;
+                       key = rka->dest_keyring;
+                       atomic_inc(&key->usage);
+               }
+               up_read(&cred->request_key_auth->sem);
+               if (!key)
+                       goto error;
+               key_ref = make_key_ref(key, 1);
+               break;
+
        default:
                key_ref = ERR_PTR(-EINVAL);
                if (id < 1)
@@ -635,7 +712,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
 
                key = key_lookup(id);
                if (IS_ERR(key)) {
-                       key_ref = ERR_PTR(PTR_ERR(key));
+                       key_ref = ERR_CAST(key);
                        goto error;
                }
 
@@ -654,8 +731,18 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                break;
        }
 
-       /* check the status */
-       if (perm) {
+       if (!partial) {
+               ret = wait_for_key_construction(key, true);
+               switch (ret) {
+               case -ERESTARTSYS:
+                       goto invalid_key;
+               default:
+                       if (perm)
+                               goto invalid_key;
+               case 0:
+                       break;
+               }
+       } else if (perm) {
                ret = key_validate(key);
                if (ret < 0)
                        goto invalid_key;
@@ -666,7 +753,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                goto invalid_key;
 
        /* check the permissions */
-       ret = key_task_permission(key_ref, context, perm);
+       ret = key_task_permission(key_ref, t, perm);
        if (ret < 0)
                goto invalid_key;
 
@@ -695,7 +782,7 @@ long join_session_keyring(const char *name)
 
        /* if no name is provided, install an anonymous keyring */
        if (!name) {
-               ret = install_session_keyring(tsk, NULL);
+               ret = install_session_keyring(NULL);
                if (ret < 0)
                        goto error;
 
@@ -706,13 +793,14 @@ long join_session_keyring(const char *name)
        }
 
        /* allow the user to join or create a named keyring */
-       down(&key_session_sem);
+       mutex_lock(&key_session_mutex);
 
        /* look for an existing keyring of this name */
-       keyring = find_keyring_by_name(name, 0);
+       keyring = find_keyring_by_name(name, false);
        if (PTR_ERR(keyring) == -ENOKEY) {
                /* not found - try and create a new one */
-               keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+               keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
+                                       KEY_ALLOC_IN_QUOTA, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
@@ -724,7 +812,7 @@ long join_session_keyring(const char *name)
        }
 
        /* we've got a keyring - now to install it */
-       ret = install_session_keyring(tsk, keyring);
+       ret = install_session_keyring(keyring);
        if (ret < 0)
                goto error2;
 
@@ -732,7 +820,7 @@ long join_session_keyring(const char *name)
        key_put(keyring);
 
 error2:
-       up(&key_session_sem);
+       mutex_unlock(&key_session_mutex);
 error:
        return ret;