Ejemplo n.º 1
0
/*
 * 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
 */
struct key *search_process_keyrings_aux(struct key_type *type,
					const void *description,
					key_match_func_t match)
{
	struct task_struct *tsk = current;
	unsigned long flags;
	struct key *key, *ret, *err, *tmp;

	/* 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
	 * none of the keyrings were searchable
	 *
	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
	 */
	key = NULL;
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
	if (tsk->thread_keyring) {
		key = keyring_search_aux(tsk->thread_keyring, type,
					 description, match);
		if (!IS_ERR(key))
			goto found;

		switch (PTR_ERR(key)) {
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
			ret = key;
			break;
		default:
			err = key;
			break;
		}
	}

	/* search the process keyring second */
	if (tsk->signal->process_keyring) {
		key = keyring_search_aux(tsk->signal->process_keyring,
					 type, description, match);
		if (!IS_ERR(key))
			goto found;

		switch (PTR_ERR(key)) {
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
			ret = key;
			break;
		default:
			err = key;
			break;
		}
	}

	/* search the session keyring last */
	spin_lock_irqsave(&tsk->sighand->siglock, flags);

	tmp = tsk->signal->session_keyring;
	if (!tmp)
		tmp = tsk->user->session_keyring;
	atomic_inc(&tmp->usage);

	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);

	key = keyring_search_aux(tmp, type, description, match);
	key_put(tmp);
	if (!IS_ERR(key))
		goto found;

	switch (PTR_ERR(key)) {
	case -EAGAIN: /* no key */
		if (ret)
			break;
	case -ENOKEY: /* negative key */
		ret = key;
		break;
	default:
		err = key;
		break;
	}

	/* no key - decide on the error we're going to go for */
	key = ret ? ret : err;

 found:
	return key;

} /* end search_process_keyrings_aux() */
Ejemplo n.º 2
0
/*
 * 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,
				  struct task_struct *context)
{
	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
	 * none of the keyrings were searchable
	 *
	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
	 */
	key_ref = NULL;
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
	if (context->thread_keyring) {
		key_ref = keyring_search_aux(
			make_key_ref(context->thread_keyring, 1),
			context, type, description, match);
		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;
		}
	}

	/* search the process keyring second */
	if (context->signal->process_keyring) {
		key_ref = keyring_search_aux(
			make_key_ref(context->signal->process_keyring, 1),
			context, type, description, match);
		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;
		}
	}

	/* search the session keyring */
	if (context->signal->session_keyring) {
		rcu_read_lock();
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
					     context->signal->session_keyring),
				     1),
			context, type, description, match);
		rcu_read_unlock();

		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;
		}
	}
	/* or search the user-session keyring */
	else {
		key_ref = keyring_search_aux(
			make_key_ref(context->user->session_keyring, 1),
			context, type, description, match);
		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;
		}
	}

	/* 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
	 */
	if (context->request_key_auth &&
	    context == current &&
	    type != &key_type_request_key_auth
	    ) {
		/* defend against the auth key being revoked */
		down_read(&context->request_key_auth->sem);

		if (key_validate(context->request_key_auth) == 0) {
			rka = context->request_key_auth->payload.data;

			key_ref = search_process_keyrings(type, description,
							  match, rka->context);

			up_read(&context->request_key_auth->sem);

			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(&context->request_key_auth->sem);
		}
	}

	/* no key - decide on the error we're going to go for */
	key_ref = ret ? ret : err;

found:
	return key_ref;

} /* end search_process_keyrings() */