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: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
9156235b34
commit
927942aabb
@ -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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* 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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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,
|
|||||||
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 @@ found:
|
|||||||
/*
|
/*
|
||||||
* 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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user