diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/internal.h | 5 | ||||
-rw-r--r-- | security/keys/keyctl.c | 29 | ||||
-rw-r--r-- | security/keys/proc.c | 20 | ||||
-rw-r--r-- | security/keys/process_keys.c | 64 | ||||
-rw-r--r-- | security/keys/request_key.c | 3 |
5 files changed, 90 insertions, 31 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index 38783dcf6c6..addb67b169f 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -114,6 +114,10 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, const void *description, key_match_func_t match); +extern key_ref_t search_my_process_keyrings(struct key_type *type, + const void *description, + key_match_func_t match, + const struct cred *cred); extern key_ref_t search_process_keyrings(struct key_type *type, const void *description, key_match_func_t match, @@ -134,6 +138,7 @@ extern struct key *request_key_and_link(struct key_type *type, struct key *dest_keyring, unsigned long flags); +extern int lookup_user_key_possessed(const struct key *key, const void *target); extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, key_perm_t perm); #define KEY_LOOKUP_CREATE 0x01 diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6261745e445..b2b0998d6ab 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -505,13 +505,11 @@ okay: ret = snprintf(tmpbuf, PAGE_SIZE - 1, "%s;%d;%d;%08x;%s", - key_ref_to_ptr(key_ref)->type->name, - key_ref_to_ptr(key_ref)->uid, - key_ref_to_ptr(key_ref)->gid, - key_ref_to_ptr(key_ref)->perm, - key_ref_to_ptr(key_ref)->description ? - key_ref_to_ptr(key_ref)->description : "" - ); + key->type->name, + key->uid, + key->gid, + key->perm, + key->description ?: ""); /* include a NUL char at the end of the data */ if (ret > PAGE_SIZE - 1) @@ -1091,7 +1089,7 @@ error: long keyctl_set_timeout(key_serial_t id, unsigned timeout) { struct timespec now; - struct key *key; + struct key *key, *instkey; key_ref_t key_ref; time_t expiry; long ret; @@ -1099,10 +1097,25 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, KEY_SETATTR); if (IS_ERR(key_ref)) { + /* setting the timeout on a key under construction is permitted + * if we have the authorisation token handy */ + if (PTR_ERR(key_ref) == -EACCES) { + instkey = key_get_instantiation_authkey(id); + if (!IS_ERR(instkey)) { + key_put(instkey); + key_ref = lookup_user_key(id, + KEY_LOOKUP_PARTIAL, + 0); + if (!IS_ERR(key_ref)) + goto okay; + } + } + ret = PTR_ERR(key_ref); goto error; } +okay: key = key_ref_to_ptr(key_ref); /* make the changes with the locks held to prevent races */ diff --git a/security/keys/proc.c b/security/keys/proc.c index 068b66ea2f1..70373966816 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -184,20 +184,36 @@ static void proc_keys_stop(struct seq_file *p, void *v) static int proc_keys_show(struct seq_file *m, void *v) { + const struct cred *cred = current_cred(); struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); struct timespec now; unsigned long timo; + key_ref_t key_ref, skey_ref; char xbuf[12]; int rc; + key_ref = make_key_ref(key, 0); + + /* determine if the key is possessed by this process (a test we can + * skip if the key does not indicate the possessor can view it + */ + if (key->perm & KEY_POS_VIEW) { + skey_ref = search_my_process_keyrings(key->type, key, + lookup_user_key_possessed, + cred); + if (!IS_ERR(skey_ref)) { + key_ref_put(skey_ref); + key_ref = make_key_ref(key, 1); + } + } + /* check whether the current task is allowed to view the key (assuming * non-possession) * - the caller holds a spinlock, and thus the RCU read lock, making our * access to __current_cred() safe */ - rc = key_task_permission(make_key_ref(key, 0), current_cred(), - KEY_VIEW); + rc = key_task_permission(key_ref, cred, KEY_VIEW); if (rc < 0) return 0; diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 6b8e4ff4cc6..f8e7251ae2c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -309,22 +309,19 @@ void key_fsgid_changed(struct task_struct *tsk) /*****************************************************************************/ /* - * search the process keyrings for the first matching key + * search only my process keyrings for the first matching key * - we use the supplied match function to see if the description (or other * feature of interest) matches * - we return -EAGAIN if we didn't find any matching key * - we return -ENOKEY if we found only negative matching keys */ -key_ref_t search_process_keyrings(struct key_type *type, - const void *description, - key_match_func_t match, - const struct cred *cred) +key_ref_t search_my_process_keyrings(struct key_type *type, + const void *description, + key_match_func_t match, + const struct cred *cred) { - 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 @@ -424,6 +421,36 @@ key_ref_t search_process_keyrings(struct key_type *type, } } + /* no key - decide on the error we're going to go for */ + key_ref = ret ? ret : err; + +found: + return key_ref; +} + +/*****************************************************************************/ +/* + * search the process keyrings for the first matching key + * - we use the supplied match function to see if the description (or other + * feature of interest) matches + * - we return -EAGAIN if we didn't find any matching key + * - we return -ENOKEY if we found only negative matching keys + */ +key_ref_t search_process_keyrings(struct key_type *type, + const void *description, + key_match_func_t match, + const struct cred *cred) +{ + struct request_key_auth *rka; + key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; + + might_sleep(); + + key_ref = search_my_process_keyrings(type, description, match, cred); + if (!IS_ERR(key_ref)) + goto found; + err = key_ref; + /* 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 @@ -446,24 +473,19 @@ key_ref_t search_process_keyrings(struct key_type *type, 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; - } + ret = key_ref; } else { up_read(&cred->request_key_auth->sem); } } /* no key - decide on the error we're going to go for */ - key_ref = ret ? ret : err; + if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) + key_ref = ERR_PTR(-ENOKEY); + else if (err == ERR_PTR(-EACCES)) + key_ref = ret; + else + key_ref = err; found: return key_ref; @@ -474,7 +496,7 @@ found: /* * see if the key we're looking at is the target key */ -static int lookup_user_key_possessed(const struct key *key, const void *target) +int lookup_user_key_possessed(const struct key *key, const void *target) { return key == target; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index f5ec9ac5d57..0088dd8bf68 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -144,6 +144,7 @@ static int call_sbin_request_key(struct key_construction *cons, prkey = 0; if (cred->tgcred->process_keyring) prkey = cred->tgcred->process_keyring->serial; + sprintf(keyring_str[1], "%d", prkey); rcu_read_lock(); session = rcu_dereference(cred->tgcred->session_keyring); @@ -536,6 +537,8 @@ int wait_for_key_construction(struct key *key, bool intr) intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (ret < 0) return ret; + if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + return -ENOKEY; return key_validate(key); } EXPORT_SYMBOL(wait_for_key_construction); |