process_keys.c revision 69664cf16af4f31cd54d77948a4baf9c7e0ca7b9
169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* Management of a process's keyrings
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by David Howells (dhowells@redhat.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/keyctl.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
19bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar#include <linux/mutex.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "internal.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* session keyring create vs join semaphore */
24bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnarstatic DEFINE_MUTEX(key_session_mutex);
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* user keyring creation semaphore */
2769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic DEFINE_MUTEX(key_user_keyring_mutex);
2869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the root user's tracking struct */
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct key_user root_key_user = {
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.usage		= ATOMIC_INIT(3),
3276181c134f87479fa13bf2548ddf2999055d34d4David Howells	.cons_lock	= __MUTEX_INITIALIZER(root_key_user.cons_lock),
336cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstra	.lock		= __SPIN_LOCK_UNLOCKED(root_key_user.lock),
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nkeys		= ATOMIC_INIT(2),
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nikeys		= ATOMIC_INIT(2),
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.uid		= 0,
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * install user and user session keyrings for a particular UID
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic int install_user_keyrings(struct task_struct *tsk)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	struct user_struct *user = tsk->user;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *uid_keyring, *session_keyring;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kenter("%p{%u}", user, user->uid);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (user->uid_keyring) {
5369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		kleave(" = 0 [exist]");
5469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		return 0;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_lock(&key_user_keyring_mutex);
5869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	ret = 0;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (!user->uid_keyring) {
6169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get the UID-specific keyring
6269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * - there may be one in existence already as it may have been
6369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   pinned by a session, but the user_struct pointing to it
6469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   may have been destroyed by setuid */
6569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid.%u", user->uid);
6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
6769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		uid_keyring = find_keyring_by_name(buf, true);
6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(uid_keyring)) {
6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells						    tsk, KEY_ALLOC_IN_QUOTA,
7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells						    NULL);
7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(uid_keyring)) {
7369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(uid_keyring);
7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
7569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
7669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
7769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
7869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get a default session keyring (which might also exist
7969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * already) */
8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid_ses.%u", user->uid);
8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		session_keyring = find_keyring_by_name(buf, true);
8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(session_keyring)) {
8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			session_keyring =
8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				keyring_alloc(buf, user->uid, (gid_t) -1,
8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells					      tsk, KEY_ALLOC_IN_QUOTA, NULL);
8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(session_keyring)) {
8869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(session_keyring);
8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release;
9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
9169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
9269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			/* we install a link from the user session keyring to
9369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			 * the user keyring */
9469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = key_link(session_keyring, uid_keyring);
9569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release_both;
9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* install the keyrings */
10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->uid_keyring = uid_keyring;
10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->session_keyring = session_keyring;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = 0");
10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	return 0;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both:
10969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(session_keyring);
11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release:
11169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(uid_keyring);
112664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
11369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = %d", ret);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
11669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deal with the UID changing
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid switch_uid_keyring(struct user_struct *new_user)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* do nothing for now */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *old;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* switch to the new user's session keyring if we were running under
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * root's default session keyring */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_user->uid != 0 &&
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    current->session_keyring == &root_session_keyring
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ) {
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&new_user->session_keyring->usage);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		task_lock(current);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old = current->session_keyring;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current->session_keyring = new_user->session_keyring;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		task_unlock(current);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_put(old);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end switch_uid_keyring() */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * install a fresh thread keyring, discarding the old one
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint install_thread_keyring(struct task_struct *tsk)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring, *old;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(buf, "_tid.%u", tsk->pid);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1577e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
1587e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells				KEY_ALLOC_QUOTA_OVERRUN, NULL);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(keyring)) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(keyring);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	task_lock(tsk);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old = tsk->thread_keyring;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->thread_keyring = keyring;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	task_unlock(tsk);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(old);
172664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end install_thread_keyring() */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make sure a process keyring is installed
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1813e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsint install_process_keyring(struct task_struct *tsk)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	might_sleep();
1881a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tsk->signal->process_keyring) {
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(buf, "_pid.%u", tsk->tgid);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1927e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
1937e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells					KEY_ALLOC_QUOTA_OVERRUN, NULL);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(keyring)) {
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = PTR_ERR(keyring);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1998589b4e00e352f983259140f25a262d973be6bc5David Howells		/* attach keyring */
2001a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		spin_lock_irq(&tsk->sighand->siglock);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tsk->signal->process_keyring) {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tsk->signal->process_keyring = keyring;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			keyring = NULL;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2051a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		spin_unlock_irq(&tsk->sighand->siglock);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_put(keyring);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
211664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end install_process_keyring() */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * install a session keyring, discarding the old one
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - if a keyring is not supplied, an empty one is invented
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int install_session_keyring(struct task_struct *tsk,
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   struct key *keyring)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2247e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells	unsigned long flags;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *old;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
2271a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells
2281a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	might_sleep();
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* create an empty session keyring */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!keyring) {
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(buf, "_ses.%u", tsk->tgid);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2347e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		flags = KEY_ALLOC_QUOTA_OVERRUN;
2357e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		if (tsk->signal->session_keyring)
2367e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells			flags = KEY_ALLOC_IN_QUOTA;
2377e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells
2387e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
2397e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells					flags, NULL);
2401a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		if (IS_ERR(keyring))
2411a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells			return PTR_ERR(keyring);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&keyring->usage);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install the keyring */
2481a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	spin_lock_irq(&tsk->sighand->siglock);
2491a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	old = tsk->signal->session_keyring;
2508589b4e00e352f983259140f25a262d973be6bc5David Howells	rcu_assign_pointer(tsk->signal->session_keyring, keyring);
2511a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	spin_unlock_irq(&tsk->sighand->siglock);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	/* we're using RCU on the pointer, but there's no point synchronising
2541a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	 * on it if it didn't previously point to anything */
2551a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	if (old) {
2561a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		synchronize_rcu();
2571a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		key_put(old);
2581a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	return 0;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end install_session_keyring() */
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copy the keys in a thread group for fork without CLONE_THREAD
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint copy_thread_group_keys(struct task_struct *tsk)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_check(current->thread_group->session_keyring);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_check(current->thread_group->process_keyring);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no process keyring yet */
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->signal->process_keyring = NULL;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* same session keyring */
2778589b4e00e352f983259140f25a262d973be6bc5David Howells	rcu_read_lock();
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->signal->session_keyring =
2798589b4e00e352f983259140f25a262d973be6bc5David Howells		key_get(rcu_dereference(current->signal->session_keyring));
2808589b4e00e352f983259140f25a262d973be6bc5David Howells	rcu_read_unlock();
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end copy_thread_group_keys() */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copy the keys for fork
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint copy_keys(unsigned long clone_flags, struct task_struct *tsk)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_check(tsk->thread_keyring);
293b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_check(tsk->request_key_auth);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no thread keyring yet */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->thread_keyring = NULL;
297b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
298b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* copy the request_key() authorisation for this thread */
299b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_get(tsk->request_key_auth);
300b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end copy_keys() */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dispose of thread group keys upon thread group destruction
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid exit_thread_group_keys(struct signal_struct *tg)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(tg->session_keyring);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(tg->process_keyring);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end exit_thread_group_keys() */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
318b5f545c880a2a47947ba2118b2509644ab7a2969David Howells * dispose of per-thread keys upon thread exit
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid exit_keys(struct task_struct *tsk)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(tsk->thread_keyring);
323b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_put(tsk->request_key_auth);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end exit_keys() */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deal with execve()
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint exec_keys(struct task_struct *tsk)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *old;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* newly exec'd tasks don't get a thread keyring */
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	task_lock(tsk);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old = tsk->thread_keyring;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->thread_keyring = NULL;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	task_unlock(tsk);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(old);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* discard the process keyring from a newly exec'd task */
3441a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	spin_lock_irq(&tsk->sighand->siglock);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old = tsk->signal->process_keyring;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tsk->signal->process_keyring = NULL;
3471a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	spin_unlock_irq(&tsk->sighand->siglock);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(old);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end exec_keys() */
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deal with SUID programs
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we might want to make this invent a new session keyring
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint suid_keys(struct task_struct *tsk)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end suid_keys() */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem user ID changed
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tsk->thread_keyring) {
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down_write(&tsk->thread_keyring->sem);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tsk->thread_keyring->uid = tsk->fsuid;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up_write(&tsk->thread_keyring->sem);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsuid_changed() */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem group ID changed
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk)
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tsk->thread_keyring) {
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down_write(&tsk->thread_keyring->sem);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tsk->thread_keyring->gid = tsk->fsgid;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up_write(&tsk->thread_keyring->sem);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsgid_changed() */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search the process keyrings for the first matching key
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we use the supplied match function to see if the description (or other
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   feature of interest) matches
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -EAGAIN if we didn't find any matching key
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -ENOKEY if we found only negative matching keys
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
404664cceb0093b755739e56572b836a99104ee8a75David Howellskey_ref_t search_process_keyrings(struct key_type *type,
405664cceb0093b755739e56572b836a99104ee8a75David Howells				  const void *description,
406664cceb0093b755739e56572b836a99104ee8a75David Howells				  key_match_func_t match,
407664cceb0093b755739e56572b836a99104ee8a75David Howells				  struct task_struct *context)
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4093e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	struct request_key_auth *rka;
410b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_ref_t key_ref, ret, err;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells	might_sleep();
41304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * searchable, but we failed to find a key or we found a negative key;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * otherwise we want to return a sample error (probably -EACCES) if
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * none of the keyrings were searchable
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
421664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = NULL;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = NULL;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = ERR_PTR(-EAGAIN);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the thread keyring first */
4263e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	if (context->thread_keyring) {
427664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
428664cceb0093b755739e56572b836a99104ee8a75David Howells			make_key_ref(context->thread_keyring, 1),
429664cceb0093b755739e56572b836a99104ee8a75David Howells			context, type, description, match);
430664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
438664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
441664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the process keyring second */
4473e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	if (context->signal->process_keyring) {
448664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
449664cceb0093b755739e56572b836a99104ee8a75David Howells			make_key_ref(context->signal->process_keyring, 1),
450664cceb0093b755739e56572b836a99104ee8a75David Howells			context, type, description, match);
451664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
454664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
459664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
462664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4673e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* search the session keyring */
4683e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	if (context->signal->session_keyring) {
4698589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_lock();
470664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
471664cceb0093b755739e56572b836a99104ee8a75David Howells			make_key_ref(rcu_dereference(
472664cceb0093b755739e56572b836a99104ee8a75David Howells					     context->signal->session_keyring),
473664cceb0093b755739e56572b836a99104ee8a75David Howells				     1),
4743e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			context, type, description, match);
4758589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_unlock();
4763e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
477664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4783e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4793e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
480664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4813e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
4823e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
4833e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
4843e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
485664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4863e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4873e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
488664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4893e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4903e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
491b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	}
492b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* or search the user-session keyring */
49369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	else if (context->user->session_keyring) {
494b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = keyring_search_aux(
495b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			make_key_ref(context->user->session_keyring, 1),
496b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			context, type, description, match);
497664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4983e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4993e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
500664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
5013e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
5023e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
5033e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
5043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
505664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
5063e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
5073e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
508664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
5093e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
5103e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
5118589b4e00e352f983259140f25a262d973be6bc5David Howells	}
512b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
513b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* if this process has an instantiation authorisation key, then we also
514b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * search the keyrings of the process mentioned there
515b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * - we don't permit access to request_key auth keys via this method
516b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 */
517b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	if (context->request_key_auth &&
518b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	    context == current &&
51904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells	    type != &key_type_request_key_auth
520b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	    ) {
52104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		/* defend against the auth key being revoked */
52204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		down_read(&context->request_key_auth->sem);
523b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
52404c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		if (key_validate(context->request_key_auth) == 0) {
52504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			rka = context->request_key_auth->payload.data;
526b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
52704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			key_ref = search_process_keyrings(type, description,
52804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells							  match, rka->context);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			up_read(&context->request_key_auth->sem);
53104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
53204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			if (!IS_ERR(key_ref))
53304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				goto found;
53404c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
53504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			switch (PTR_ERR(key_ref)) {
53604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			case -EAGAIN: /* no key */
53704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				if (ret)
53804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells					break;
53904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			case -ENOKEY: /* negative key */
54004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				ret = key_ref;
5413e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
54204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			default:
54304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				err = key_ref;
54404c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				break;
54504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			}
54604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		} else {
54704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			up_read(&context->request_key_auth->sem);
5483e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no key - decide on the error we're going to go for */
552664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ret ? ret : err;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5543e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound:
555664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end search_process_keyrings() */
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
561664cceb0093b755739e56572b836a99104ee8a75David Howells * see if the key we're looking at is the target key
562664cceb0093b755739e56572b836a99104ee8a75David Howells */
563664cceb0093b755739e56572b836a99104ee8a75David Howellsstatic int lookup_user_key_possessed(const struct key *key, const void *target)
564664cceb0093b755739e56572b836a99104ee8a75David Howells{
565664cceb0093b755739e56572b836a99104ee8a75David Howells	return key == target;
566664cceb0093b755739e56572b836a99104ee8a75David Howells
567664cceb0093b755739e56572b836a99104ee8a75David Howells} /* end lookup_user_key_possessed() */
568664cceb0093b755739e56572b836a99104ee8a75David Howells
569664cceb0093b755739e56572b836a99104ee8a75David Howells/*****************************************************************************/
570664cceb0093b755739e56572b836a99104ee8a75David Howells/*
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - don't create special keyrings unless so requested
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - partially constructed keys aren't found unless requested
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
575664cceb0093b755739e56572b836a99104ee8a75David Howellskey_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
576664cceb0093b755739e56572b836a99104ee8a75David Howells			  int create, int partial, key_perm_t perm)
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
578664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref_t key_ref, skey_ref;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *key;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5823e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	if (!context)
5833e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		context = current;
5843e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
585664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(-ENOKEY);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (id) {
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_THREAD_KEYRING:
5893e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		if (!context->thread_keyring) {
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!create)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5933e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			ret = install_thread_keyring(context);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				key = ERR_PTR(ret);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6003e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		key = context->thread_keyring;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
602664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_PROCESS_KEYRING:
6063e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		if (!context->signal->process_keyring) {
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!create)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6103e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			ret = install_process_keyring(context);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				key = ERR_PTR(ret);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6173e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		key = context->signal->process_keyring;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
619664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_SESSION_KEYRING:
6233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		if (!context->signal->session_keyring) {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* always install a session keyring upon access if one
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * doesn't exist yet */
62669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = install_user_keyrings(context);
62769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
62869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = install_session_keyring(
630664cceb0093b755739e56572b836a99104ee8a75David Howells				context, context->user->session_keyring);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6353e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_lock();
6363e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		key = rcu_dereference(context->signal->session_keyring);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
6383e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_unlock();
639664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_KEYRING:
64369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (!context->user->uid_keyring) {
64469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = install_user_keyrings(context);
64569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
64669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
64769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
64869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
6493e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		key = context->user->uid_keyring;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
651664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_SESSION_KEYRING:
65569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (!context->user->session_keyring) {
65669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = install_user_keyrings(context);
65769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
65869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
65969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
66069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
6613e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		key = context->user->session_keyring;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
663664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_GROUP_KEYRING:
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* group keyrings are not yet supported */
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key = ERR_PTR(-EINVAL);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	case KEY_SPEC_REQKEY_AUTH_KEY:
672b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key = context->request_key_auth;
673b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		if (!key)
674b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			goto error;
675b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
676b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		atomic_inc(&key->usage);
677b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = make_key_ref(key, 1);
678b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		break;
679b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
681664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = ERR_PTR(-EINVAL);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (id < 1)
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key = key_lookup(id);
686664cceb0093b755739e56572b836a99104ee8a75David Howells		if (IS_ERR(key)) {
687e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells			key_ref = ERR_CAST(key);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
689664cceb0093b755739e56572b836a99104ee8a75David Howells		}
690664cceb0093b755739e56572b836a99104ee8a75David Howells
691664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 0);
692664cceb0093b755739e56572b836a99104ee8a75David Howells
693664cceb0093b755739e56572b836a99104ee8a75David Howells		/* check to see if we possess the key */
694664cceb0093b755739e56572b836a99104ee8a75David Howells		skey_ref = search_process_keyrings(key->type, key,
695664cceb0093b755739e56572b836a99104ee8a75David Howells						   lookup_user_key_possessed,
696664cceb0093b755739e56572b836a99104ee8a75David Howells						   current);
697664cceb0093b755739e56572b836a99104ee8a75David Howells
698664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(skey_ref)) {
699664cceb0093b755739e56572b836a99104ee8a75David Howells			key_put(key);
700664cceb0093b755739e56572b836a99104ee8a75David Howells			key_ref = skey_ref;
701664cceb0093b755739e56572b836a99104ee8a75David Howells		}
702664cceb0093b755739e56572b836a99104ee8a75David Howells
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70676181c134f87479fa13bf2548ddf2999055d34d4David Howells	if (!partial) {
70776181c134f87479fa13bf2548ddf2999055d34d4David Howells		ret = wait_for_key_construction(key, true);
70876181c134f87479fa13bf2548ddf2999055d34d4David Howells		switch (ret) {
70976181c134f87479fa13bf2548ddf2999055d34d4David Howells		case -ERESTARTSYS:
71076181c134f87479fa13bf2548ddf2999055d34d4David Howells			goto invalid_key;
71176181c134f87479fa13bf2548ddf2999055d34d4David Howells		default:
71276181c134f87479fa13bf2548ddf2999055d34d4David Howells			if (perm)
71376181c134f87479fa13bf2548ddf2999055d34d4David Howells				goto invalid_key;
71476181c134f87479fa13bf2548ddf2999055d34d4David Howells		case 0:
71576181c134f87479fa13bf2548ddf2999055d34d4David Howells			break;
71676181c134f87479fa13bf2548ddf2999055d34d4David Howells		}
71776181c134f87479fa13bf2548ddf2999055d34d4David Howells	} else if (perm) {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = key_validate(key);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto invalid_key;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EIO;
72476d8aeabfeb1c42641a81c44280177b9a08670d8David Howells	if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7273e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* check the permissions */
72829db9190634067c5a328ee5fcc2890251b836b4bDavid Howells	ret = key_task_permission(key_ref, context, perm);
72929db9190634067c5a328ee5fcc2890251b836b4bDavid Howells	if (ret < 0)
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
732664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
733664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
735664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key:
736664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref_put(key_ref);
737664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(ret);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto error;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end lookup_user_key() */
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create a new one of that name if not
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - named session keyring joining is done with a semaphore held
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name)
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct task_struct *tsk = current;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long ret;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if no name is provided, install an anonymous keyring */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!name) {
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = install_session_keyring(tsk, NULL);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7613e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_lock();
7623e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		ret = rcu_dereference(tsk->signal->session_keyring)->serial;
7633e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_unlock();
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allow the user to join or create a named keyring */
768bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_lock(&key_session_mutex);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look for an existing keyring of this name */
77169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	keyring = find_keyring_by_name(name, false);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PTR_ERR(keyring) == -ENOKEY) {
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* not found - try and create a new one */
7747e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
7757e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells					KEY_ALLOC_IN_QUOTA, NULL);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(keyring)) {
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = PTR_ERR(keyring);
778bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells			goto error2;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (IS_ERR(keyring)) {
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(keyring);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we've got a keyring - now to install it */
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = install_session_keyring(tsk, keyring);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = keyring->serial;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(keyring);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
794664cceb0093b755739e56572b836a99104ee8a75David Howellserror2:
795bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_unlock(&key_session_mutex);
796664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end join_session_keyring() */
800