1973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* Manage 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/keyctl.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
18bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar#include <linux/mutex.h>
19ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells#include <linux/security.h>
201d1e97562e5e2ac60fb7b25437ba619f95f67fabSerge E. Hallyn#include <linux/user_namespace.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "internal.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* Session keyring create vs join semaphore */
25bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnarstatic DEFINE_MUTEX(key_session_mutex);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* User keyring creation semaphore */
2869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic DEFINE_MUTEX(key_user_keyring_mutex);
2969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
30973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* The root user's tracking struct */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct key_user root_key_user = {
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.usage		= ATOMIC_INIT(3),
3376181c134f87479fa13bf2548ddf2999055d34d4David Howells	.cons_lock	= __MUTEX_INITIALIZER(root_key_user.cons_lock),
346cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstra	.lock		= __SPIN_LOCK_UNLOCKED(root_key_user.lock),
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nkeys		= ATOMIC_INIT(2),
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nikeys		= ATOMIC_INIT(2),
379a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman	.uid		= GLOBAL_ROOT_UID,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
41973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install the user and user session keyrings for the current process's UID.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
438bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howellsint install_user_keyrings(void)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct user_struct *user;
46d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *cred;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *uid_keyring, *session_keyring;
4896b5c8fea6c0861621051290d705ec2e971963f1David Howells	key_perm_t user_keyring_perm;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
519a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman	uid_t uid;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5396b5c8fea6c0861621051290d705ec2e971963f1David Howells	user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL;
54d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	cred = current_cred();
55d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	user = cred->user;
569a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman	uid = from_kuid(cred->user_ns, user->uid);
57d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
589a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman	kenter("%p{%u}", user, uid);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
600da9dfdd2cd9889201bc6f6f43580c99165cd087David Howells	if (user->uid_keyring && user->session_keyring) {
6169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		kleave(" = 0 [exist]");
6269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		return 0;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_lock(&key_user_keyring_mutex);
6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	ret = 0;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (!user->uid_keyring) {
6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get the UID-specific keyring
7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * - there may be one in existence already as it may have been
7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   pinned by a session, but the user_struct pointing to it
7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   may have been destroyed by setuid */
739a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman		sprintf(buf, "_uid.%u", uid);
7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
7569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		uid_keyring = find_keyring_by_name(buf, true);
7669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(uid_keyring)) {
779a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
7896b5c8fea6c0861621051290d705ec2e971963f1David Howells						    cred, user_keyring_perm,
7996b5c8fea6c0861621051290d705ec2e971963f1David Howells						    KEY_ALLOC_IN_QUOTA, NULL);
8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(uid_keyring)) {
8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(uid_keyring);
8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get a default session keyring (which might also exist
8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * already) */
889a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman		sprintf(buf, "_uid_ses.%u", uid);
8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		session_keyring = find_keyring_by_name(buf, true);
9169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(session_keyring)) {
9269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			session_keyring =
939a56c2db49e7349c7963f0ce66c1ef578d44ebd3Eric W. Biederman				keyring_alloc(buf, user->uid, INVALID_GID,
9496b5c8fea6c0861621051290d705ec2e971963f1David Howells					      cred, user_keyring_perm,
9596b5c8fea6c0861621051290d705ec2e971963f1David Howells					      KEY_ALLOC_IN_QUOTA, NULL);
9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(session_keyring)) {
9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(session_keyring);
9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release;
9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			/* we install a link from the user session keyring to
10269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			 * the user keyring */
10369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = key_link(session_keyring, uid_keyring);
10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release_both;
10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
10769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
10869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* install the keyrings */
10969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->uid_keyring = uid_keyring;
11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->session_keyring = session_keyring;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = 0");
11569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	return 0;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both:
11869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(session_keyring);
11969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release:
12069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(uid_keyring);
121664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
12269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
12369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = %d", ret);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
12569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
128973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a fresh thread keyring directly to new credentials.  This keyring is
129973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * allowed to overrun the quota.
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
131d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_thread_keyring_to_cred(struct cred *new)
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
133d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct key *keyring;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
135d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
13696b5c8fea6c0861621051290d705ec2e971963f1David Howells				KEY_POS_ALL | KEY_USR_VIEW,
137d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells				KEY_ALLOC_QUOTA_OVERRUN, NULL);
138d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (IS_ERR(keyring))
139d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return PTR_ERR(keyring);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new->thread_keyring = keyring;
142d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return 0;
143d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
146973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a fresh thread keyring, discarding the old one.
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
148d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_thread_keyring(void)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
150d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
154d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
155d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
157d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	BUG_ON(new->thread_keyring);
158d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
159d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_thread_keyring_to_cred(new);
160d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
161d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
162d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
165d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
166d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
168d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells/*
169973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a process keyring directly to a credentials struct.
170973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
171973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns -EEXIST if there was already a process keyring, 0 if one installed,
172973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * and other value on any other error
173d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells */
174d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_process_keyring_to_cred(struct cred *new)
175d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells{
176d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct key *keyring;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1783a50597de8635cd05133bd12c95681c82fe7b878David Howells	if (new->process_keyring)
179d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -EEXIST;
180d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
18196b5c8fea6c0861621051290d705ec2e971963f1David Howells	keyring = keyring_alloc("_pid", new->uid, new->gid, new,
18296b5c8fea6c0861621051290d705ec2e971963f1David Howells				KEY_POS_ALL | KEY_USR_VIEW,
18396b5c8fea6c0861621051290d705ec2e971963f1David Howells				KEY_ALLOC_QUOTA_OVERRUN, NULL);
184d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (IS_ERR(keyring))
185d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return PTR_ERR(keyring);
186d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
1873a50597de8635cd05133bd12c95681c82fe7b878David Howells	new->process_keyring = keyring;
1883a50597de8635cd05133bd12c95681c82fe7b878David Howells	return 0;
189d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
192973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Make sure a process keyring is installed for the current process.  The
193973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * existing process keyring is not replaced.
194973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
195973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns 0 if there is a process keyring by the end of this function, some
196973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * error otherwise.
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
198d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_process_keyring(void)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
200d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
203d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
204d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
205d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_process_keyring_to_cred(new);
208d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
209d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
21027d6379894be4a81984da4d48002196a83939ca9Andi Kleen		return ret != -EEXIST ? ret : 0;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
214d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
217973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring directly to a credentials struct.
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
219685bfd2c48bb3284d31e73ff3151c957d76deda9Oleg Nesterovint install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2217e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells	unsigned long flags;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *old;
2231a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells
2241a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	might_sleep();
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* create an empty session keyring */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!keyring) {
2287e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		flags = KEY_ALLOC_QUOTA_OVERRUN;
2293a50597de8635cd05133bd12c95681c82fe7b878David Howells		if (cred->session_keyring)
2307e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells			flags = KEY_ALLOC_IN_QUOTA;
2317e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells
23296b5c8fea6c0861621051290d705ec2e971963f1David Howells		keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
23396b5c8fea6c0861621051290d705ec2e971963f1David Howells					KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
23496b5c8fea6c0861621051290d705ec2e971963f1David Howells					flags, NULL);
2351a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		if (IS_ERR(keyring))
2361a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells			return PTR_ERR(keyring);
237d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else {
238ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(keyring);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install the keyring */
2423a50597de8635cd05133bd12c95681c82fe7b878David Howells	old = cred->session_keyring;
2433a50597de8635cd05133bd12c95681c82fe7b878David Howells	rcu_assign_pointer(cred->session_keyring, keyring);
2443a50597de8635cd05133bd12c95681c82fe7b878David Howells
2453a50597de8635cd05133bd12c95681c82fe7b878David Howells	if (old)
2461a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		key_put(old);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	return 0;
249d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
252973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring, discarding the old one.  If a keyring is not
253973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * supplied, an empty one is invented.
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
255d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_session_keyring(struct key *keyring)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
257d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
258d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	int ret;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
261d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
262d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264995995378f996a8aa1cf4e4ddc0f79fbfd45496fDavid Howells	ret = install_session_keyring_to_cred(new, keyring);
265d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
266d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
267d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret;
268d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
270d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
271d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
274973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsuid changing.
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
279b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
280b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
281b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
282b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
283b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
285a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
288973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsgid changing.
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
293b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
294b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
295b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
296b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
297b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
299a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
302973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first
303973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key.
304973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
305973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * The search criteria are the type and the match function.  The description is
306973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * given to the match function as a parameter, but doesn't otherwise influence
307973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the search.  Typically the match function will compare the description
308973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * parameter to the key's description.
309973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
310973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * This can only search keyrings that grant Search permission to the supplied
311973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * credentials.  Keyrings linked to searched keyrings will also be searched if
312973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * they grant Search permission too.  Keys can only be found if they grant
313973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search permission to the credentials.
314973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
315973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with the key usage count incremented if
316973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
317973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matched negative keys.
318973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
319973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the
320973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference.
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3224bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howellskey_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
324b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_ref_t key_ref, ret, err;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * searchable, but we failed to find a key or we found a negative key;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * otherwise we want to return a sample error (probably -EACCES) if
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * none of the keyrings were searchable
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
333664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = NULL;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = NULL;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = ERR_PTR(-EAGAIN);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the thread keyring first */
3384bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	if (ctx->cred->thread_keyring) {
339664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
3404bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			make_key_ref(ctx->cred->thread_keyring, 1), ctx);
341664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
344664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
347664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
350664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the process keyring second */
3564bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	if (ctx->cred->process_keyring) {
357664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
3584bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			make_key_ref(ctx->cred->process_keyring, 1), ctx);
359664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
362664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
364fe9453a1dcb5fb146f9653267e78f4a558066f6fDavid Howells			if (ret)
365fe9453a1dcb5fb146f9653267e78f4a558066f6fDavid Howells				break;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
367664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
370664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3753e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* search the session keyring */
3764bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	if (ctx->cred->session_keyring) {
3778589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_lock();
378664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
3794bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1),
3804bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			ctx);
3818589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_unlock();
3823e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
383664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3843e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
3853e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
386664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3873e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
3883e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
3893e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
3903e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
391664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3923e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
3933e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
394664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3953e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
3963e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
397b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	}
398b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* or search the user-session keyring */
3994bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	else if (ctx->cred->user->session_keyring) {
400b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = keyring_search_aux(
4014bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			make_key_ref(ctx->cred->user->session_keyring, 1),
4024bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			ctx);
403664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4053e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
406664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4073e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
4083e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
4093e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
4103e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
411664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4123e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4133e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
414664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4153e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4163e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4178589b4e00e352f983259140f25a262d973be6bc5David Howells	}
418b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
419927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	/* no key - decide on the error we're going to go for */
420927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	key_ref = ret ? ret : err;
421927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
422927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellsfound:
423927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	return key_ref;
424927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells}
425927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
426927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells/*
427973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first
428973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key in the manner of search_my_process_keyrings(), but also search
429973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the keys attached to the assumed authorisation key using its credentials if
430973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * one is available.
431973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
432973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Return same as search_my_process_keyrings().
433927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells */
4344bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howellskey_ref_t search_process_keyrings(struct keyring_search_context *ctx)
435927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells{
436927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	struct request_key_auth *rka;
437927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
438927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
439927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	might_sleep();
440927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
4414bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	key_ref = search_my_process_keyrings(ctx);
442927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	if (!IS_ERR(key_ref))
443927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		goto found;
444927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	err = key_ref;
445927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
446b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* if this process has an instantiation authorisation key, then we also
447b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * search the keyrings of the process mentioned there
448b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * - we don't permit access to request_key auth keys via this method
449b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 */
4504bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	if (ctx->cred->request_key_auth &&
4514bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	    ctx->cred == current_cred() &&
4524bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	    ctx->index_key.type != &key_type_request_key_auth
453b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	    ) {
4544bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		const struct cred *cred = ctx->cred;
4554bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells
45604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		/* defend against the auth key being revoked */
457c69e8d9c01db2adc503464993c358901c9af9de4David Howells		down_read(&cred->request_key_auth->sem);
458b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
4594bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (key_validate(ctx->cred->request_key_auth) == 0) {
4604bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			rka = ctx->cred->request_key_auth->payload.data;
461b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
4624bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			ctx->cred = rka->cred;
4634bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			key_ref = search_process_keyrings(ctx);
4644bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			ctx->cred = cred;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
466c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
46704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
46804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			if (!IS_ERR(key_ref))
46904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				goto found;
47004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
471927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells			ret = key_ref;
47204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		} else {
473c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
4743e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no key - decide on the error we're going to go for */
478927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
479927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = ERR_PTR(-ENOKEY);
480927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	else if (err == ERR_PTR(-EACCES))
481927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = ret;
482927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	else
483927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = err;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4853e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound:
486664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
487a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
490973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * See if the key we're looking at is the target key.
491664cceb0093b755739e56572b836a99104ee8a75David Howells */
4920c903ab64feb0fe83eac9f67a06e2f5b9508de16David Howellsbool lookup_user_key_possessed(const struct key *key,
4930c903ab64feb0fe83eac9f67a06e2f5b9508de16David Howells			       const struct key_match_data *match_data)
494664cceb0093b755739e56572b836a99104ee8a75David Howells{
495462919591a1791e76042dc5c1e0148715df59bebDavid Howells	return key == match_data->raw_data;
496a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
497664cceb0093b755739e56572b836a99104ee8a75David Howells
498664cceb0093b755739e56572b836a99104ee8a75David Howells/*
499973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Look up a key ID given us by userspace with a given permissions mask to get
500973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the key it refers to.
501973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
502973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Flags can be passed to request that special keyrings be created if referred
503973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to directly, to permit partially constructed keys to be found and to skip
504973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * validity and permission checks on the found key.
505973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
506973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with an incremented usage count if successful;
507973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
508973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to a key or the best found key was a negative key; -EKEYREVOKED or
509973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
510973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * found key doesn't grant the requested permit or the LSM denied access to it;
511973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * or -ENOMEM if a special keyring couldn't be created.
512973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
513973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the
514973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference.
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5165593122eec26b061cc0b6fbff32118f1aadf4a27David Howellskey_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
5178bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			  key_perm_t perm)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5194bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	struct keyring_search_context ctx = {
520462919591a1791e76042dc5c1e0148715df59bebDavid Howells		.match_data.cmp		= lookup_user_key_possessed,
521462919591a1791e76042dc5c1e0148715df59bebDavid Howells		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
522462919591a1791e76042dc5c1e0148715df59bebDavid Howells		.flags			= KEYRING_SEARCH_NO_STATE_CHECK,
5234bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	};
5248bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	struct request_key_auth *rka;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *key;
526b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	key_ref_t key_ref, skey_ref;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
529bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellstry_again:
5304bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	ctx.cred = get_current_cred();
531664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(-ENOKEY);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (id) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_THREAD_KEYRING:
5354bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->thread_keyring) {
5365593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5398bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_thread_keyring();
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5414d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
544bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5474bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = ctx.cred->thread_keyring;
548ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
549664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_PROCESS_KEYRING:
5534bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->process_keyring) {
5545593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5578bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_process_keyring();
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5594d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
562bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5654bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = ctx.cred->process_keyring;
566ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
567664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_SESSION_KEYRING:
5714bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->session_keyring) {
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* always install a session keyring upon access if one
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * doesn't exist yet */
5748bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
57569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
57669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
5773ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			if (lflags & KEY_LOOKUP_CREATE)
5783ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				ret = join_session_keyring(NULL);
5793ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			else
5803ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				ret = install_session_keyring(
5814bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells					ctx.cred->user->session_keyring);
582d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
585bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5864bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		} else if (ctx.cred->session_keyring ==
5874bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			   ctx.cred->user->session_keyring &&
5883ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			   lflags & KEY_LOOKUP_CREATE) {
5893ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			ret = join_session_keyring(NULL);
5903ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			if (ret < 0)
5913ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				goto error;
5923ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			goto reget_creds;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5953e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_lock();
5964bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = rcu_dereference(ctx.cred->session_keyring);
597ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
5983e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_unlock();
599664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_KEYRING:
6034bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->user->uid_keyring) {
6048bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
60569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
60669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
60769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
60869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
6094bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = ctx.cred->user->uid_keyring;
610ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
611664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_SESSION_KEYRING:
6154bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->user->session_keyring) {
6168bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
61769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
61869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
61969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
62069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
6214bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = ctx.cred->user->session_keyring;
622ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
623664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_GROUP_KEYRING:
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* group keyrings are not yet supported */
6284d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter		key_ref = ERR_PTR(-EINVAL);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	case KEY_SPEC_REQKEY_AUTH_KEY:
6324bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		key = ctx.cred->request_key_auth;
633b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		if (!key)
634b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			goto error;
635b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
636ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells		__key_get(key);
637b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = make_key_ref(key, 1);
638b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		break;
639b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
6408bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	case KEY_SPEC_REQUESTOR_KEYRING:
6414bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		if (!ctx.cred->request_key_auth)
6428bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6438bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
6444bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		down_read(&ctx.cred->request_key_auth->sem);
645f67dabbdde1fe112dfff05d02890f1e0d54117a8Dan Carpenter		if (test_bit(KEY_FLAG_REVOKED,
6464bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			     &ctx.cred->request_key_auth->flags)) {
6478bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key_ref = ERR_PTR(-EKEYREVOKED);
6488bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = NULL;
6498bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		} else {
6504bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells			rka = ctx.cred->request_key_auth->payload.data;
6518bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = rka->dest_keyring;
652ccc3e6d9c9aea07a0b60b2b0bfc5b05a704b66d5David Howells			__key_get(key);
6538bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		}
6544bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		up_read(&ctx.cred->request_key_auth->sem);
6558bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		if (!key)
6568bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6578bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		key_ref = make_key_ref(key, 1);
6588bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		break;
6598bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
661664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = ERR_PTR(-EINVAL);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (id < 1)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key = key_lookup(id);
666664cceb0093b755739e56572b836a99104ee8a75David Howells		if (IS_ERR(key)) {
667e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells			key_ref = ERR_CAST(key);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
669664cceb0093b755739e56572b836a99104ee8a75David Howells		}
670664cceb0093b755739e56572b836a99104ee8a75David Howells
671664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 0);
672664cceb0093b755739e56572b836a99104ee8a75David Howells
673664cceb0093b755739e56572b836a99104ee8a75David Howells		/* check to see if we possess the key */
6744bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		ctx.index_key.type		= key->type;
6754bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		ctx.index_key.description	= key->description;
6764bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		ctx.index_key.desc_len		= strlen(key->description);
677462919591a1791e76042dc5c1e0148715df59bebDavid Howells		ctx.match_data.raw_data		= key;
6784bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		kdebug("check possessed");
6794bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		skey_ref = search_process_keyrings(&ctx);
6804bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells		kdebug("possessed=%p", skey_ref);
681664cceb0093b755739e56572b836a99104ee8a75David Howells
682664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(skey_ref)) {
683664cceb0093b755739e56572b836a99104ee8a75David Howells			key_put(key);
684664cceb0093b755739e56572b836a99104ee8a75David Howells			key_ref = skey_ref;
685664cceb0093b755739e56572b836a99104ee8a75David Howells		}
686664cceb0093b755739e56572b836a99104ee8a75David Howells
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6905593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	/* unlink does not use the nominated key in any way, so can skip all
6915593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	 * the permission checks as it is only concerned with the keyring */
6925593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
6935593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		ret = 0;
6945593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		goto error;
6955593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	}
6965593122eec26b061cc0b6fbff32118f1aadf4a27David Howells
6975593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
69876181c134f87479fa13bf2548ddf2999055d34d4David Howells		ret = wait_for_key_construction(key, true);
69976181c134f87479fa13bf2548ddf2999055d34d4David Howells		switch (ret) {
70076181c134f87479fa13bf2548ddf2999055d34d4David Howells		case -ERESTARTSYS:
70176181c134f87479fa13bf2548ddf2999055d34d4David Howells			goto invalid_key;
70276181c134f87479fa13bf2548ddf2999055d34d4David Howells		default:
70376181c134f87479fa13bf2548ddf2999055d34d4David Howells			if (perm)
70476181c134f87479fa13bf2548ddf2999055d34d4David Howells				goto invalid_key;
70576181c134f87479fa13bf2548ddf2999055d34d4David Howells		case 0:
70676181c134f87479fa13bf2548ddf2999055d34d4David Howells			break;
70776181c134f87479fa13bf2548ddf2999055d34d4David Howells		}
70876181c134f87479fa13bf2548ddf2999055d34d4David Howells	} else if (perm) {
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = key_validate(key);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto invalid_key;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EIO;
7155593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
7165593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7193e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* check the permissions */
7204bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	ret = key_task_permission(key_ref, ctx.cred, perm);
72129db9190634067c5a328ee5fcc2890251b836b4bDavid Howells	if (ret < 0)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72431d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells	key->last_used_at = current_kernel_time().tv_sec;
72531d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells
726664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
7274bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	put_cred(ctx.cred);
728664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
730664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key:
731664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref_put(key_ref);
732664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(ret);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto error;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
735bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	/* if we attempted to install a keyring, then it may have caused new
736bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	 * creds to be installed */
737bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellsreget_creds:
7384bdf0bc300314141e5475e145acb8b5ad846f00dDavid Howells	put_cred(ctx.cred);
739bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	goto try_again;
740a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
741bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
743973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Join the named keyring as the session keyring if possible else attempt to
744973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * create a new one of that name and join that.
745973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
746973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * If the name is NULL, an empty anonymous keyring will be installed as the
747973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * session keyring.
748973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
749973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Named session keyrings are joined with a semaphore held to prevent the
750973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * keyrings from going away whilst the attempt is made to going them and also
751973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to prevent a race in creating compatible session keyrings.
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name)
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
755d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *old;
756d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring;
758d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	long ret, serial;
759d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
760d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
761d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
762d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
763d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	old = current_cred();
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if no name is provided, install an anonymous keyring */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!name) {
767d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = install_session_keyring_to_cred(new, NULL);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7713a50597de8635cd05133bd12c95681c82fe7b878David Howells		serial = new->session_keyring->serial;
772d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = commit_creds(new);
773d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		if (ret == 0)
774d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			ret = serial;
775d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		goto okay;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allow the user to join or create a named keyring */
779bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_lock(&key_session_mutex);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look for an existing keyring of this name */
78269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	keyring = find_keyring_by_name(name, false);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PTR_ERR(keyring) == -ENOKEY) {
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* not found - try and create a new one */
78596b5c8fea6c0861621051290d705ec2e971963f1David Howells		keyring = keyring_alloc(
78696b5c8fea6c0861621051290d705ec2e971963f1David Howells			name, old->uid, old->gid, old,
78796b5c8fea6c0861621051290d705ec2e971963f1David Howells			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
78896b5c8fea6c0861621051290d705ec2e971963f1David Howells			KEY_ALLOC_IN_QUOTA, NULL);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(keyring)) {
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = PTR_ERR(keyring);
791bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells			goto error2;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
793d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else if (IS_ERR(keyring)) {
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(keyring);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
7963a50597de8635cd05133bd12c95681c82fe7b878David Howells	} else if (keyring == new->session_keyring) {
7973a50597de8635cd05133bd12c95681c82fe7b878David Howells		ret = 0;
7983a50597de8635cd05133bd12c95681c82fe7b878David Howells		goto error2;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we've got a keyring - now to install it */
802d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_session_keyring_to_cred(new, keyring);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
806d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	commit_creds(new);
807d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	mutex_unlock(&key_session_mutex);
808d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = keyring->serial;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(keyring);
811d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsokay:
812d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return ret;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
814664cceb0093b755739e56572b836a99104ee8a75David Howellserror2:
815bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_unlock(&key_session_mutex);
816664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
817d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	abort_creds(new);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
819d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
820ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
821ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells/*
822973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Replace a process's session keyring on behalf of one of its children when
823973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the target  process is about to resume userspace execution.
824ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells */
82567d1214551e800f9fe7dc7c47a346d2df0fafed5Al Virovoid key_change_session_keyring(struct callback_head *twork)
826ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells{
827413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	const struct cred *old = current_cred();
82867d1214551e800f9fe7dc7c47a346d2df0fafed5Al Viro	struct cred *new = container_of(twork, struct cred, rcu);
829ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
830413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	if (unlikely(current->flags & PF_EXITING)) {
831413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov		put_cred(new);
832ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells		return;
833413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	}
834ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
835ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  uid	= old->  uid;
836ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> euid	= old-> euid;
837ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> suid	= old-> suid;
838ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsuid	= old->fsuid;
839ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  gid	= old->  gid;
840ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> egid	= old-> egid;
841ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> sgid	= old-> sgid;
842ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsgid	= old->fsgid;
843ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->user	= get_uid(old->user);
844ba0e3427b03c3d1550239779eca5c1c5a53a2152Eric W. Biederman	new->user_ns	= get_user_ns(old->user_ns);
845ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->group_info	= get_group_info(old->group_info);
846ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
847ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->securebits	= old->securebits;
848ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_inheritable	= old->cap_inheritable;
849ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_permitted	= old->cap_permitted;
850ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_effective	= old->cap_effective;
851ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_bset		= old->cap_bset;
852ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
853ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->jit_keyring	= old->jit_keyring;
854ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->thread_keyring	= key_get(old->thread_keyring);
8553a50597de8635cd05133bd12c95681c82fe7b878David Howells	new->process_keyring	= key_get(old->process_keyring);
856ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
857ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	security_transfer_creds(new, old);
858ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
859ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	commit_creds(new);
860ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells}
861c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar
862c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar/*
863c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar * Make sure that root's user and user-session keyrings exist.
864c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar */
865c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zoharstatic int __init init_root_keyring(void)
866c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar{
867c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar	return install_user_keyrings();
868c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar}
869c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zohar
870c124bde28bce41f9e46e32d03d134a81e116d38cMimi Zoharlate_initcall(init_root_keyring);
871