コード例 #1
0
/*
 * read a user key's payload
 * - the keyring must be readable or the key must be searchable from the
 *   process's keyrings
 * - if there's a buffer, we place up to buflen bytes of data into it
 * - unless there's an error, we return the amount of data in the key,
 *   irrespective of how much we may have copied
 * - implements keyctl(KEYCTL_READ)
 */
long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
{
	struct key *key;
	key_ref_t key_ref;
	long ret;

	/* find the key first */
	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
	if (IS_ERR(key_ref)) {
		ret = -ENOKEY;
		goto error;
	}

	key = key_ref_to_ptr(key_ref);

	/* see if we can read it directly */
	ret = key_permission(key_ref, KEY_READ);
	if (ret == 0)
		goto can_read_key;
	if (ret != -EACCES)
		goto error;

	/* we can't; see if it's searchable from this process's keyrings
	 * - we automatically take account of the fact that it may be
	 *   dangling off an instantiation key
	 */
	if (!is_key_possessed(key_ref)) {
		ret = -EACCES;
		goto error2;
	}

	/* the key is probably readable - now try to read it */
 can_read_key:
	ret = key_validate(key);
	if (ret == 0) {
		ret = -EOPNOTSUPP;
		if (key->type->read) {
			/* read the data with the semaphore held (since we
			 * might sleep) */
			down_read(&key->sem);
			ret = key->type->read(key, buffer, buflen);
			up_read(&key->sem);
		}
	}

 error2:
	key_put(key);
 error:
	return ret;

} /* end keyctl_read_key() */
コード例 #2
0
/*
 * lookup a key given a key ID from userspace with a given permissions mask
 * - don't create special keyrings unless so requested
 * - partially constructed keys aren't found unless requested
 */
struct key *lookup_user_key(key_serial_t id, int create, int partial,
			    key_perm_t perm)
{
	struct task_struct *tsk = current;
	unsigned long flags;
	struct key *key;
	int ret;

	key = ERR_PTR(-ENOKEY);

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
		if (!tsk->thread_keyring) {
			if (!create)
				goto error;

			ret = install_thread_keyring(tsk);
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

		key = tsk->thread_keyring;
		atomic_inc(&key->usage);
		break;

	case KEY_SPEC_PROCESS_KEYRING:
		if (!tsk->signal->process_keyring) {
			if (!create)
				goto error;

			ret = install_process_keyring(tsk);
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

		key = tsk->signal->process_keyring;
		atomic_inc(&key->usage);
		break;

	case KEY_SPEC_SESSION_KEYRING:
		if (!tsk->signal->session_keyring) {
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
			ret = install_session_keyring(
			       tsk, tsk->user->session_keyring);
			if (ret < 0)
				goto error;
		}

		spin_lock_irqsave(&tsk->sighand->siglock, flags);
		key = tsk->signal->session_keyring;
		atomic_inc(&key->usage);
		spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
		break;

	case KEY_SPEC_USER_KEYRING:
		key = tsk->user->uid_keyring;
		atomic_inc(&key->usage);
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
		key = tsk->user->session_keyring;
		atomic_inc(&key->usage);
		break;

	case KEY_SPEC_GROUP_KEYRING:
		/* group keyrings are not yet supported */
		key = ERR_PTR(-EINVAL);
		goto error;

	default:
		key = ERR_PTR(-EINVAL);
		if (id < 1)
			goto error;

		key = key_lookup(id);
		if (IS_ERR(key))
			goto error;
		break;
	}

	/* check the status and permissions */
	if (perm) {
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

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

	ret = -EACCES;
	if (!key_permission(key, perm))
		goto invalid_key;

 error:
	return key;

 invalid_key:
	key_put(key);
	key = ERR_PTR(ret);
	goto error;

} /* end lookup_user_key() */
コード例 #3
0
/*
 * search the specified keyring for a matching key
 * - the start keyring must be searchable
 * - nested keyrings may also be searched if they are searchable
 * - only keys with search permission may be found
 * - if a key is found, it will be attached to the destination keyring if
 *   there's one specified
 * - implements keyctl(KEYCTL_SEARCH)
 */
long keyctl_keyring_search(key_serial_t ringid,
			   const char __user *_type,
			   const char __user *_description,
			   key_serial_t destringid)
{
	struct key_type *ktype;
	key_ref_t keyring_ref, key_ref, dest_ref;
	char type[32], *description;
	long dlen, ret;

	/* pull the type and description into kernel space */
	ret = strncpy_from_user(type, _type, sizeof(type) - 1);
	if (ret < 0)
		goto error;
	type[31] = '\0';

	ret = -EFAULT;
	dlen = strnlen_user(_description, PAGE_SIZE - 1);
	if (dlen <= 0)
		goto error;

	ret = -EINVAL;
	if (dlen > PAGE_SIZE - 1)
		goto error;

	ret = -ENOMEM;
	description = kmalloc(dlen + 1, GFP_KERNEL);
	if (!description)
		goto error;

	ret = -EFAULT;
	if (copy_from_user(description, _description, dlen + 1) != 0)
		goto error2;

	/* get the keyring at which to begin the search */
	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
	if (IS_ERR(keyring_ref)) {
		ret = PTR_ERR(keyring_ref);
		goto error2;
	}

	/* get the destination keyring if specified */
	dest_ref = NULL;
	if (destringid) {
		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
		if (IS_ERR(dest_ref)) {
			ret = PTR_ERR(dest_ref);
			goto error3;
		}
	}

	/* find the key type */
	ktype = key_type_lookup(type);
	if (IS_ERR(ktype)) {
		ret = PTR_ERR(ktype);
		goto error4;
	}

	/* do the search */
	key_ref = keyring_search(keyring_ref, ktype, description);
	if (IS_ERR(key_ref)) {
		ret = PTR_ERR(key_ref);

		/* treat lack or presence of a negative key the same */
		if (ret == -EAGAIN)
			ret = -ENOKEY;
		goto error5;
	}

	/* link the resulting key to the destination keyring if we can */
	if (dest_ref) {
		ret = key_permission(key_ref, KEY_LINK);
		if (ret < 0)
			goto error6;

		ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
		if (ret < 0)
			goto error6;
	}

	ret = key_ref_to_ptr(key_ref)->serial;

 error6:
	key_ref_put(key_ref);
 error5:
	key_type_put(ktype);
 error4:
	key_ref_put(dest_ref);
 error3:
	key_ref_put(keyring_ref);
 error2:
	kfree(description);
 error:
	return ret;

} /* end keyctl_keyring_search() */