linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / security / keys / process_keys.c
index 32150cf..74cb79e 100644 (file)
 #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 DEFINE_MUTEX(key_session_mutex);
+static DECLARE_MUTEX(key_session_sem);
 
 /* the root user's tracking struct */
 struct key_user root_key_user = {
@@ -67,8 +66,7 @@ struct key root_session_keyring = {
 /*
  * allocate the keyrings to be associated with a UID
  */
-int alloc_uid_keyring(struct user_struct *user,
-                     struct task_struct *ctx)
+int alloc_uid_keyring(struct user_struct *user)
 {
        struct key *uid_keyring, *session_keyring;
        char buf[20];
@@ -77,8 +75,7 @@ int alloc_uid_keyring(struct user_struct *user,
        /* concoct a default session keyring */
        sprintf(buf, "_uid_ses.%u", user->uid);
 
-       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
-                                       KEY_ALLOC_IN_QUOTA, NULL);
+       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
        if (IS_ERR(session_keyring)) {
                ret = PTR_ERR(session_keyring);
                goto error;
@@ -88,8 +85,8 @@ int alloc_uid_keyring(struct user_struct *user,
         * keyring */
        sprintf(buf, "_uid.%u", user->uid);
 
-       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
-                                   KEY_ALLOC_IN_QUOTA, session_keyring);
+       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);
@@ -145,8 +142,7 @@ int install_thread_keyring(struct task_struct *tsk)
 
        sprintf(buf, "_tid.%u", tsk->pid);
 
-       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-                               KEY_ALLOC_QUOTA_OVERRUN, NULL);
+       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
@@ -171,29 +167,27 @@ error:
  */
 int install_process_keyring(struct task_struct *tsk)
 {
+       unsigned long flags;
        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, tsk,
-                                       KEY_ALLOC_QUOTA_OVERRUN, NULL);
+               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error;
                }
 
                /* attach keyring */
-               spin_lock_irq(&tsk->sighand->siglock);
+               spin_lock_irqsave(&tsk->sighand->siglock, flags);
                if (!tsk->signal->process_keyring) {
                        tsk->signal->process_keyring = keyring;
                        keyring = NULL;
                }
-               spin_unlock_irq(&tsk->sighand->siglock);
+               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
                key_put(keyring);
        }
@@ -215,40 +209,35 @@ static int install_session_keyring(struct task_struct *tsk,
        unsigned long flags;
        struct key *old;
        char buf[20];
-
-       might_sleep();
+       int ret;
 
        /* create an empty session keyring */
        if (!keyring) {
                sprintf(buf, "_ses.%u", tsk->tgid);
 
-               flags = KEY_ALLOC_QUOTA_OVERRUN;
-               if (tsk->signal->session_keyring)
-                       flags = KEY_ALLOC_IN_QUOTA;
-
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-                                       flags, NULL);
-               if (IS_ERR(keyring))
-                       return PTR_ERR(keyring);
+               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+               if (IS_ERR(keyring)) {
+                       ret = PTR_ERR(keyring);
+                       goto error;
+               }
        }
        else {
                atomic_inc(&keyring->usage);
        }
 
        /* install the keyring */
-       spin_lock_irq(&tsk->sighand->siglock);
-       old = tsk->signal->session_keyring;
+       spin_lock_irqsave(&tsk->sighand->siglock, flags);
+       old = rcu_dereference(tsk->signal->session_keyring);
        rcu_assign_pointer(tsk->signal->session_keyring, keyring);
-       spin_unlock_irq(&tsk->sighand->siglock);
+       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
-       /* 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);
-       }
+       ret = 0;
 
-       return 0;
+       /* we're using RCU on the pointer */
+       synchronize_rcu();
+       key_put(old);
+error:
+       return ret;
 
 } /* end install_session_keyring() */
 
@@ -321,6 +310,7 @@ 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 */
@@ -332,10 +322,10 @@ int exec_keys(struct task_struct *tsk)
        key_put(old);
 
        /* discard the process keyring from a newly exec'd task */
-       spin_lock_irq(&tsk->sighand->siglock);
+       spin_lock_irqsave(&tsk->sighand->siglock, flags);
        old = tsk->signal->process_keyring;
        tsk->signal->process_keyring = NULL;
-       spin_unlock_irq(&tsk->sighand->siglock);
+       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
        key_put(old);
 
@@ -400,8 +390,6 @@ key_ref_t search_process_keyrings(struct key_type *type,
        struct request_key_auth *rka;
        key_ref_t key_ref, ret, err;
 
-       might_sleep();
-
        /* 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;
         * otherwise we want to return a sample error (probably -EACCES) if
@@ -507,35 +495,27 @@ key_ref_t search_process_keyrings(struct key_type *type,
         */
        if (context->request_key_auth &&
            context == current &&
-           type != &key_type_request_key_auth
+           type != &key_type_request_key_auth &&
+           key_validate(context->request_key_auth) == 0
            ) {
-               /* defend against the auth key being revoked */
-               down_read(&context->request_key_auth->sem);
-
-               if (key_validate(context->request_key_auth) == 0) {
-                       rka = context->request_key_auth->payload.data;
+               rka = context->request_key_auth->payload.data;
 
-                       key_ref = search_process_keyrings(type, description,
-                                                         match, rka->context);
+               key_ref = search_process_keyrings(type, description, match,
+                                                 rka->context);
 
-                       up_read(&context->request_key_auth->sem);
-
-                       if (!IS_ERR(key_ref))
-                               goto found;
+               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;
+               switch (PTR_ERR(key_ref)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
                                break;
-                       }
-               } else {
-                       up_read(&context->request_key_auth->sem);
+               case -ENOKEY: /* negative key */
+                       ret = key_ref;
+                       break;
+               default:
+                       err = key_ref;
+                       break;
                }
        }
 
@@ -731,14 +711,13 @@ long join_session_keyring(const char *name)
        }
 
        /* allow the user to join or create a named keyring */
-       mutex_lock(&key_session_mutex);
+       down(&key_session_sem);
 
        /* look for an existing keyring of this name */
        keyring = find_keyring_by_name(name, 0);
        if (PTR_ERR(keyring) == -ENOKEY) {
                /* not found - try and create a new one */
-               keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
-                                       KEY_ALLOC_IN_QUOTA, NULL);
+               keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
@@ -758,7 +737,7 @@ long join_session_keyring(const char *name)
        key_put(keyring);
 
 error2:
-       mutex_unlock(&key_session_mutex);
+       up(&key_session_sem);
 error:
        return ret;