Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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
+18 −2
Original line number Diff line number Diff line
@@ -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;

+43 −21
Original line number Diff line number Diff line
@@ -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,
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;
			}
		} 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 @@ key_ref_t search_process_keyrings(struct key_type *type,
/*
 * 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;