CRED: Separate task security context from task_struct
[linux-2.6-block.git] / security / keys / process_keys.c
index 5be6d018759abf43d469bc786d04305223464574..b0904cdda2e7b03f5e2ec0d0fdb2f2c474b85dcb 100644 (file)
@@ -40,9 +40,9 @@ struct key_user root_key_user = {
 /*
  * install user and user session keyrings for a particular UID
  */
-static int install_user_keyrings(struct task_struct *tsk)
+int install_user_keyrings(void)
 {
-       struct user_struct *user = tsk->user;
+       struct user_struct *user = current->cred->user;
        struct key *uid_keyring, *session_keyring;
        char buf[20];
        int ret;
@@ -67,7 +67,7 @@ static int install_user_keyrings(struct task_struct *tsk)
                uid_keyring = find_keyring_by_name(buf, true);
                if (IS_ERR(uid_keyring)) {
                        uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
-                                                   tsk, KEY_ALLOC_IN_QUOTA,
+                                                   current, KEY_ALLOC_IN_QUOTA,
                                                    NULL);
                        if (IS_ERR(uid_keyring)) {
                                ret = PTR_ERR(uid_keyring);
@@ -83,7 +83,8 @@ static int install_user_keyrings(struct task_struct *tsk)
                if (IS_ERR(session_keyring)) {
                        session_keyring =
                                keyring_alloc(buf, user->uid, (gid_t) -1,
-                                             tsk, KEY_ALLOC_IN_QUOTA, NULL);
+                                             current, KEY_ALLOC_IN_QUOTA,
+                                             NULL);
                        if (IS_ERR(session_keyring)) {
                                ret = PTR_ERR(session_keyring);
                                goto error_release;
@@ -146,15 +147,16 @@ 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, tsk,
+       keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
                                KEY_ALLOC_QUOTA_OVERRUN, NULL);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
@@ -162,8 +164,8 @@ int install_thread_keyring(struct task_struct *tsk)
        }
 
        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;
@@ -178,8 +180,9 @@ error:
 /*
  * make sure a process keyring is installed
  */
-int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(void)
 {
+       struct task_struct *tsk = current;
        struct key *keyring;
        char buf[20];
        int ret;
@@ -189,7 +192,7 @@ int install_process_keyring(struct task_struct *tsk)
        if (!tsk->signal->process_keyring) {
                sprintf(buf, "_pid.%u", tsk->tgid);
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
                                        KEY_ALLOC_QUOTA_OVERRUN, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
@@ -218,9 +221,9 @@ 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];
@@ -235,7 +238,7 @@ static int install_session_keyring(struct task_struct *tsk,
                if (tsk->signal->session_keyring)
                        flags = KEY_ALLOC_IN_QUOTA;
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
                                        flags, NULL);
                if (IS_ERR(keyring))
                        return PTR_ERR(keyring);
@@ -289,14 +292,14 @@ 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->request_key_auth);
+       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->request_key_auth);
+       key_get(tsk->cred->request_key_auth);
 
        return 0;
 
@@ -319,8 +322,8 @@ void exit_thread_group_keys(struct signal_struct *tg)
  */
 void exit_keys(struct task_struct *tsk)
 {
-       key_put(tsk->thread_keyring);
-       key_put(tsk->request_key_auth);
+       key_put(tsk->cred->thread_keyring);
+       key_put(tsk->cred->request_key_auth);
 
 } /* end exit_keys() */
 
@@ -334,8 +337,8 @@ int exec_keys(struct task_struct *tsk)
 
        /* 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);
@@ -370,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() */
@@ -385,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() */
@@ -423,9 +428,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 (context->cred->thread_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->thread_keyring, 1),
+                       make_key_ref(context->cred->thread_keyring, 1),
                        context, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
@@ -490,9 +495,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
        /* or search the user-session keyring */
-       else if (context->user->session_keyring) {
+       else if (context->cred->user->session_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->user->session_keyring, 1),
+                       make_key_ref(context->cred->user->session_keyring, 1),
                        context, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
@@ -514,20 +519,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
         * search the keyrings of the process mentioned there
         * - we don't permit access to request_key auth keys via this method
         */
-       if (context->request_key_auth &&
+       if (context->cred->request_key_auth &&
            context == current &&
            type != &key_type_request_key_auth
            ) {
                /* defend against the auth key being revoked */
-               down_read(&context->request_key_auth->sem);
+               down_read(&context->cred->request_key_auth->sem);
 
-               if (key_validate(context->request_key_auth) == 0) {
-                       rka = context->request_key_auth->payload.data;
+               if (key_validate(context->cred->request_key_auth) == 0) {
+                       rka = context->cred->request_key_auth->payload.data;
 
                        key_ref = search_process_keyrings(type, description,
                                                          match, rka->context);
 
-                       up_read(&context->request_key_auth->sem);
+                       up_read(&context->cred->request_key_auth->sem);
 
                        if (!IS_ERR(key_ref))
                                goto found;
@@ -544,7 +549,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
                                break;
                        }
                } else {
-                       up_read(&context->request_key_auth->sem);
+                       up_read(&context->cred->request_key_auth->sem);
                }
        }
 
@@ -572,93 +577,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 = t->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(context);
+                       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:
-               if (!context->user->uid_keyring) {
-                       ret = install_user_keyrings(context);
+               if (!cred->user->uid_keyring) {
+                       ret = install_user_keyrings();
                        if (ret < 0)
                                goto error;
                }
 
-               key = context->user->uid_keyring;
+               key = cred->user->uid_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_USER_SESSION_KEYRING:
-               if (!context->user->session_keyring) {
-                       ret = install_user_keyrings(context);
+               if (!cred->user->session_keyring) {
+                       ret = install_user_keyrings();
                        if (ret < 0)
                                goto error;
                }
 
-               key = context->user->session_keyring;
+               key = cred->user->session_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
@@ -669,7 +674,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                goto error;
 
        case KEY_SPEC_REQKEY_AUTH_KEY:
-               key = context->request_key_auth;
+               key = cred->request_key_auth;
                if (!key)
                        goto error;
 
@@ -677,6 +682,25 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                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)
@@ -725,7 +749,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;
 
@@ -754,7 +778,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;
 
@@ -771,7 +795,7 @@ long join_session_keyring(const char *name)
        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, tsk,
+               keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
                                        KEY_ALLOC_IN_QUOTA, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
@@ -784,7 +808,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;