From 927942aabbbe506bf9bc70a16dc5460ecc64c148 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 11 Jun 2010 17:31:10 +0100 Subject: 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 Signed-off-by: James Morris --- security/keys/internal.h | 5 ++++ security/keys/proc.c | 20 ++++++++++++-- security/keys/process_keys.c | 64 +++++++++++++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 23 deletions(-) (limited to 'security/keys') diff --git a/security/keys/internal.h b/security/keys/internal.h index 38783dcf6c61..addb67b169f4 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/proc.c b/security/keys/proc.c index 068b66ea2f1b..70373966816e 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 6b8e4ff4cc68..f8e7251ae2c8 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; -- cgit v1.2.3-59-g8ed1b