X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=security%2Fkeys%2Fprocess_keys.c;h=217a0bef3c82b341db5c07d414b7385a8f4a00fb;hp=d42d2158ce13beba31fb2753356e244a18e3a2a1;hb=7c8ce71b092425f1e938285cab2a679c09444d9b;hpb=5833f1420b96c4f9b193b7f2fcbc0003dc032fe8 diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index d42d2158ce13..217a0bef3c82 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -16,11 +16,12 @@ #include #include #include +#include #include #include "internal.h" /* session keyring create vs join semaphore */ -static DECLARE_MUTEX(key_session_sem); +static DEFINE_MUTEX(key_session_mutex); /* the root user's tracking struct */ struct key_user root_key_user = { @@ -39,7 +40,7 @@ struct key root_user_keyring = { .type = &key_type_keyring, .user = &root_key_user, .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), - .perm = KEY_POS_ALL | KEY_USR_ALL, + .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, .flags = 1 << KEY_FLAG_INSTANTIATED, .description = "_uid.0", #ifdef KEY_DEBUGGING @@ -54,7 +55,7 @@ struct key root_session_keyring = { .type = &key_type_keyring, .user = &root_key_user, .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), - .perm = KEY_POS_ALL | KEY_USR_ALL, + .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, .flags = 1 << KEY_FLAG_INSTANTIATED, .description = "_uid_ses.0", #ifdef KEY_DEBUGGING @@ -167,11 +168,12 @@ 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); @@ -182,12 +184,12 @@ int install_process_keyring(struct task_struct *tsk) } /* 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); } @@ -206,38 +208,37 @@ error: static int install_session_keyring(struct task_struct *tsk, struct key *keyring) { - 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; - } + 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() */ @@ -270,9 +271,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); /* no thread keyring yet */ tsk->thread_keyring = NULL; + + /* copy the request_key() authorisation for this thread */ + key_get(tsk->request_key_auth); + return 0; } /* end copy_keys() */ @@ -290,11 +296,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->request_key_auth); } /* end exit_keys() */ @@ -304,7 +311,6 @@ 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 */ @@ -316,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_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); @@ -382,7 +388,7 @@ 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; + key_ref_t key_ref, ret, err; /* 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; @@ -461,30 +467,12 @@ 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); - + } + /* or search the user-session keyring */ + else { + key_ref = keyring_search_aux( + make_key_ref(context->user->session_keyring, 1), + context, type, description, match); if (!IS_ERR(key_ref)) goto found; @@ -500,11 +488,21 @@ key_ref_t search_process_keyrings(struct key_type *type, break; } } - /* or search the user-session keyring */ - else { - key_ref = keyring_search_aux( - make_key_ref(context->user->session_keyring, 1), - context, type, description, match); + + /* 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 (context->request_key_auth && + context == current && + type != &key_type_request_key_auth && + key_validate(context->request_key_auth) == 0 + ) { + rka = context->request_key_auth->payload.data; + + key_ref = search_process_keyrings(type, description, match, + rka->context); + if (!IS_ERR(key_ref)) goto found; @@ -521,8 +519,6 @@ key_ref_t search_process_keyrings(struct key_type *type, } } - -no_key: /* no key - decide on the error we're going to go for */ key_ref = ret ? ret : err; @@ -628,6 +624,15 @@ 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 = context->request_key_auth; + if (!key) + goto error; + + atomic_inc(&key->usage); + key_ref = make_key_ref(key, 1); + break; + default: key_ref = ERR_PTR(-EINVAL); if (id < 1) @@ -666,9 +671,8 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, goto invalid_key; /* check the permissions */ - ret = -EACCES; - - if (!key_task_permission(key_ref, context, perm)) + ret = key_task_permission(key_ref, context, perm); + if (ret < 0) goto invalid_key; error: @@ -707,7 +711,7 @@ 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); @@ -733,7 +737,7 @@ long join_session_keyring(const char *name) key_put(keyring); error2: - up(&key_session_sem); + mutex_unlock(&key_session_mutex); error: return ret;