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

Commit 5593122e authored by David Howells's avatar David Howells Committed by James Morris
Browse files

KEYS: Deal with dead-type keys appropriately [try #6]



Allow keys for which the key type has been removed to be unlinked.  Currently
dead-type keys can only be disposed of by completely clearing the keyrings
that point to them.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarSerge Hallyn <serue@us.ibm.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent e0e81739
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -124,8 +124,11 @@ extern struct key *request_key_and_link(struct key_type *type,
					struct key *dest_keyring,
					unsigned long flags);

extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
				 key_perm_t perm);
#define KEY_LOOKUP_CREATE	0x01
#define KEY_LOOKUP_PARTIAL	0x02
#define KEY_LOOKUP_FOR_UNLINK	0x04

extern long join_session_keyring(const char *name);

+2 −4
Original line number Diff line number Diff line
@@ -642,10 +642,8 @@ struct key *key_lookup(key_serial_t id)
	goto error;

 found:
	/* pretend it doesn't exist if it's dead */
	if (atomic_read(&key->usage) == 0 ||
	    test_bit(KEY_FLAG_DEAD, &key->flags) ||
	    key->type == &key_type_dead)
	/* pretend it doesn't exist if it is awaiting deletion */
	if (atomic_read(&key->usage) == 0)
		goto not_found;

	/* this races with key_put(), but that doesn't matter since key_put()
+29 −21
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
	}

	/* find the target keyring (which must be writable) */
	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error3;
@@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
	/* get the destination keyring if specified */
	dest_ref = NULL;
	if (destringid) {
		dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
		dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
					   KEY_WRITE);
		if (IS_ERR(dest_ref)) {
			ret = PTR_ERR(dest_ref);
			goto error3;
@@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
long keyctl_get_keyring_ID(key_serial_t id, int create)
{
	key_ref_t key_ref;
	unsigned long lflags;
	long ret;

	key_ref = lookup_user_key(id, create, 0, KEY_SEARCH);
	lflags = create ? KEY_LOOKUP_CREATE : 0;
	key_ref = lookup_user_key(id, lflags, KEY_SEARCH);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error;
@@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id,
	}

	/* find the target key (which must be writable) */
	key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
	key_ref = lookup_user_key(id, 0, KEY_WRITE);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error2;
@@ -337,7 +340,7 @@ long keyctl_revoke_key(key_serial_t id)
	key_ref_t key_ref;
	long ret;

	key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
	key_ref = lookup_user_key(id, 0, KEY_WRITE);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error;
@@ -363,7 +366,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
	key_ref_t keyring_ref;
	long ret;

	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error;
@@ -389,13 +392,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
	key_ref_t keyring_ref, key_ref;
	long ret;

	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error;
	}

	key_ref = lookup_user_key(id, 1, 0, KEY_LINK);
	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error2;
@@ -423,13 +426,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
	key_ref_t keyring_ref, key_ref;
	long ret;

	keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE);
	keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error;
	}

	key_ref = lookup_user_key(id, 0, 0, 0);
	key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error2;
@@ -465,7 +468,7 @@ long keyctl_describe_key(key_serial_t keyid,
	char *tmpbuf;
	long ret;

	key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
	key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
	if (IS_ERR(key_ref)) {
		/* viewing a key under construction is permitted if we have the
		 * authorisation token handy */
@@ -474,7 +477,8 @@ long keyctl_describe_key(key_serial_t keyid,
			if (!IS_ERR(instkey)) {
				key_put(instkey);
				key_ref = lookup_user_key(keyid,
							  0, 1, 0);
							  KEY_LOOKUP_PARTIAL,
							  0);
				if (!IS_ERR(key_ref))
					goto okay;
			}
@@ -558,7 +562,7 @@ long keyctl_keyring_search(key_serial_t ringid,
	}

	/* get the keyring at which to begin the search */
	keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
	keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error2;
@@ -567,7 +571,8 @@ long keyctl_keyring_search(key_serial_t ringid,
	/* get the destination keyring if specified */
	dest_ref = NULL;
	if (destringid) {
		dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
		dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
					   KEY_WRITE);
		if (IS_ERR(dest_ref)) {
			ret = PTR_ERR(dest_ref);
			goto error3;
@@ -637,7 +642,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
	long ret;

	/* find the key first */
	key_ref = lookup_user_key(keyid, 0, 0, 0);
	key_ref = lookup_user_key(keyid, 0, 0);
	if (IS_ERR(key_ref)) {
		ret = -ENOKEY;
		goto error;
@@ -700,7 +705,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
	if (uid == (uid_t) -1 && gid == (gid_t) -1)
		goto error;

	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
				  KEY_SETATTR);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error;
@@ -805,7 +811,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
		goto error;

	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
				  KEY_SETATTR);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error;
@@ -847,7 +854,7 @@ static long get_instantiation_keyring(key_serial_t ringid,

	/* if a specific keyring is nominated by ID, then use that */
	if (ringid > 0) {
		dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
		dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
		if (IS_ERR(dkref))
			return PTR_ERR(dkref);
		*_dest_keyring = key_ref_to_ptr(dkref);
@@ -1083,7 +1090,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
	time_t expiry;
	long ret;

	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
				  KEY_SETATTR);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);
		goto error;
@@ -1170,7 +1178,7 @@ long keyctl_get_security(key_serial_t keyid,
	char *context;
	long ret;

	key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
	key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
	if (IS_ERR(key_ref)) {
		if (PTR_ERR(key_ref) != -EACCES)
			return PTR_ERR(key_ref);
@@ -1182,7 +1190,7 @@ long keyctl_get_security(key_serial_t keyid,
			return PTR_ERR(key_ref);
		key_put(instkey);

		key_ref = lookup_user_key(keyid, 0, 1, 0);
		key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0);
		if (IS_ERR(key_ref))
			return PTR_ERR(key_ref);
	}
+13 −5
Original line number Diff line number Diff line
@@ -487,7 +487,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target)
 * - don't create special keyrings unless so requested
 * - partially constructed keys aren't found unless requested
 */
key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
			  key_perm_t perm)
{
	struct request_key_auth *rka;
@@ -503,7 +503,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
		if (!cred->thread_keyring) {
			if (!create)
			if (!(lflags & KEY_LOOKUP_CREATE))
				goto error;

			ret = install_thread_keyring();
@@ -521,7 +521,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,

	case KEY_SPEC_PROCESS_KEYRING:
		if (!cred->tgcred->process_keyring) {
			if (!create)
			if (!(lflags & KEY_LOOKUP_CREATE))
				goto error;

			ret = install_process_keyring();
@@ -642,7 +642,14 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
		break;
	}

	if (!partial) {
	/* unlink does not use the nominated key in any way, so can skip all
	 * the permission checks as it is only concerned with the keyring */
	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
		ret = 0;
		goto error;
	}

	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
		ret = wait_for_key_construction(key, true);
		switch (ret) {
		case -ERESTARTSYS:
@@ -660,7 +667,8 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
	}

	ret = -EIO;
	if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
		goto invalid_key;

	/* check the permissions */