Commit 927942aa authored by David Howells's avatar David Howells Committed by James Morris

KEYS: Make /proc/keys check to see if a key is possessed before security check

Make /proc/keys check to see if the calling process possesses each key before
performing the security check.  The possession check can be skipped if the key
doesn't have the possessor-view permission bit set.

This causes the keys a process possesses to show up in /proc/keys, even if they
don't have matching user/group/other view permissions.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 9156235b
...@@ -114,6 +114,10 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -114,6 +114,10 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const void *description, const void *description,
key_match_func_t match); 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, extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
...@@ -134,6 +138,7 @@ extern struct key *request_key_and_link(struct key_type *type, ...@@ -134,6 +138,7 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring, struct key *dest_keyring,
unsigned long flags); 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, extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
key_perm_t perm); key_perm_t perm);
#define KEY_LOOKUP_CREATE 0x01 #define KEY_LOOKUP_CREATE 0x01
......
...@@ -184,20 +184,36 @@ static void proc_keys_stop(struct seq_file *p, void *v) ...@@ -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) static int proc_keys_show(struct seq_file *m, void *v)
{ {
const struct cred *cred = current_cred();
struct rb_node *_p = v; struct rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node); struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now; struct timespec now;
unsigned long timo; unsigned long timo;
key_ref_t key_ref, skey_ref;
char xbuf[12]; char xbuf[12];
int rc; 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 /* check whether the current task is allowed to view the key (assuming
* non-possession) * non-possession)
* - the caller holds a spinlock, and thus the RCU read lock, making our * - the caller holds a spinlock, and thus the RCU read lock, making our
* access to __current_cred() safe * access to __current_cred() safe
*/ */
rc = key_task_permission(make_key_ref(key, 0), current_cred(), rc = key_task_permission(key_ref, cred, KEY_VIEW);
KEY_VIEW);
if (rc < 0) if (rc < 0)
return 0; return 0;
......
...@@ -309,22 +309,19 @@ void key_fsgid_changed(struct task_struct *tsk) ...@@ -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 * - we use the supplied match function to see if the description (or other
* feature of interest) matches * feature of interest) matches
* - we return -EAGAIN if we didn't find any matching key * - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys * - we return -ENOKEY if we found only negative matching keys
*/ */
key_ref_t search_process_keyrings(struct key_type *type, key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
const struct cred *cred) const struct cred *cred)
{ {
struct request_key_auth *rka;
key_ref_t key_ref, ret, err; key_ref_t key_ref, ret, err;
might_sleep();
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were /* 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; * 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 * 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, ...@@ -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 /* if this process has an instantiation authorisation key, then we also
* search the keyrings of the process mentioned there * search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method * - 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, ...@@ -446,24 +473,19 @@ key_ref_t search_process_keyrings(struct key_type *type,
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key_ref)) { ret = key_ref;
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
ret = key_ref;
break;
default:
err = key_ref;
break;
}
} else { } else {
up_read(&cred->request_key_auth->sem); up_read(&cred->request_key_auth->sem);
} }
} }
/* no key - decide on the error we're going to go for */ /* 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: found:
return key_ref; return key_ref;
...@@ -474,7 +496,7 @@ key_ref_t search_process_keyrings(struct key_type *type, ...@@ -474,7 +496,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
/* /*
* see if the key we're looking at is the target key * 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; return key == target;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment