process_keys.c revision 67d1214551e800f9fe7dc7c47a346d2df0fafed5
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),
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.uid		= 0,
381d1e97562e5e2ac60fb7b25437ba619f95f67fabSerge E. Hallyn	.user_ns	= &init_user_ns,
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
42973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install the user and user session keyrings for the current process's UID.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
448bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howellsint install_user_keyrings(void)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct user_struct *user;
47d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *cred;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *uid_keyring, *session_keyring;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	cred = current_cred();
53d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	user = cred->user;
54d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
5569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kenter("%p{%u}", user, user->uid);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (user->uid_keyring) {
5869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		kleave(" = 0 [exist]");
5969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		return 0;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_lock(&key_user_keyring_mutex);
6369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	ret = 0;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (!user->uid_keyring) {
6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get the UID-specific keyring
6769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * - there may be one in existence already as it may have been
6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   pinned by a session, but the user_struct pointing to it
6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   may have been destroyed by setuid */
7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid.%u", user->uid);
7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		uid_keyring = find_keyring_by_name(buf, true);
7369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(uid_keyring)) {
7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
75d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells						    cred, KEY_ALLOC_IN_QUOTA,
7669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells						    NULL);
7769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(uid_keyring)) {
7869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(uid_keyring);
7969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get a default session keyring (which might also exist
8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * already) */
8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid_ses.%u", user->uid);
8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		session_keyring = find_keyring_by_name(buf, true);
8869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(session_keyring)) {
8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			session_keyring =
9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				keyring_alloc(buf, user->uid, (gid_t) -1,
91d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells					      cred, KEY_ALLOC_IN_QUOTA, NULL);
9269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(session_keyring)) {
9369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(session_keyring);
9469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release;
9569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			/* we install a link from the user session keyring to
9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			 * the user keyring */
9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = key_link(session_keyring, uid_keyring);
10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release_both;
10269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
10369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* install the keyrings */
10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->uid_keyring = uid_keyring;
10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->session_keyring = session_keyring;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = 0");
11169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	return 0;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both:
11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(session_keyring);
11569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release:
11669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(uid_keyring);
117664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
11869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
11969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = %d", ret);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
12169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
124973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a fresh thread keyring directly to new credentials.  This keyring is
125973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * allowed to overrun the quota.
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
127d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_thread_keyring_to_cred(struct cred *new)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
129d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct key *keyring;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
132d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells				KEY_ALLOC_QUOTA_OVERRUN, NULL);
133d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (IS_ERR(keyring))
134d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return PTR_ERR(keyring);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
136d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new->thread_keyring = keyring;
137d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return 0;
138d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
141973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a fresh thread keyring, discarding the old one.
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
143d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_thread_keyring(void)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
149d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
150d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	BUG_ON(new->thread_keyring);
153d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
154d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_thread_keyring_to_cred(new);
155d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
156d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
157d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
160d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
161d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells/*
164973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a process keyring directly to a credentials struct.
165973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
166973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns -EEXIST if there was already a process keyring, 0 if one installed,
167973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * and other value on any other error
168d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells */
169d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_process_keyring_to_cred(struct cred *new)
170d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells{
171d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct key *keyring;
172d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	int ret;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
174d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (new->tgcred->process_keyring)
175d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -EEXIST;
176d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
177d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	keyring = keyring_alloc("_pid", new->uid, new->gid,
178d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
179d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (IS_ERR(keyring))
180d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return PTR_ERR(keyring);
181d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
182d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_lock_irq(&new->tgcred->lock);
183d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new->tgcred->process_keyring) {
184d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		new->tgcred->process_keyring = keyring;
185d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = NULL;
186d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = 0;
187d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else {
188d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = -EEXIST;
189d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	}
190d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_unlock_irq(&new->tgcred->lock);
191d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	key_put(keyring);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
193d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
196973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Make sure a process keyring is installed for the current process.  The
197973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * existing process keyring is not replaced.
198973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
199973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns 0 if there is a process keyring by the end of this function, some
200973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * error otherwise.
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
202d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_process_keyring(void)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
204d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
208d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
209d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_process_keyring_to_cred(new);
212d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
213d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
21427d6379894be4a81984da4d48002196a83939ca9Andi Kleen		return ret != -EEXIST ? ret : 0;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
218d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
221973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring directly to a credentials struct.
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
223685bfd2c48bb3284d31e73ff3151c957d76deda9Oleg Nesterovint install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2257e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells	unsigned long flags;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *old;
2271a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells
2281a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	might_sleep();
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* create an empty session keyring */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!keyring) {
2327e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells		flags = KEY_ALLOC_QUOTA_OVERRUN;
233d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		if (cred->tgcred->session_keyring)
2347e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells			flags = KEY_ALLOC_IN_QUOTA;
2357e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells
236d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = keyring_alloc("_ses", cred->uid, cred->gid,
237d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells					cred, flags, NULL);
2381a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		if (IS_ERR(keyring))
2391a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells			return PTR_ERR(keyring);
240d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&keyring->usage);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install the keyring */
245d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_lock_irq(&cred->tgcred->lock);
246d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	old = cred->tgcred->session_keyring;
247d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
248d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_unlock_irq(&cred->tgcred->lock);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	/* we're using RCU on the pointer, but there's no point synchronising
2511a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	 * on it if it didn't previously point to anything */
2521a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	if (old) {
2531a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		synchronize_rcu();
2541a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		key_put(old);
2551a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	return 0;
258d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
261973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring, discarding the old one.  If a keyring is not
262973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * supplied, an empty one is invented.
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
264d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_session_keyring(struct key *keyring)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
266d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
267d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	int ret;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
270d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
271d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
273995995378f996a8aa1cf4e4ddc0f79fbfd45496fDavid Howells	ret = install_session_keyring_to_cred(new, keyring);
274d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
275d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
276d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret;
277d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
279d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
280d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
283973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsuid changing.
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
288b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
289b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
290b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
291b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
292b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
294a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
297973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsgid changing.
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
302b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
303b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
304b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
305b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
306b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
308a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
311973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first
312973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key.
313973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
314973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * The search criteria are the type and the match function.  The description is
315973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * given to the match function as a parameter, but doesn't otherwise influence
316973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the search.  Typically the match function will compare the description
317973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * parameter to the key's description.
318973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
319973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * This can only search keyrings that grant Search permission to the supplied
320973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * credentials.  Keyrings linked to searched keyrings will also be searched if
321973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * they grant Search permission too.  Keys can only be found if they grant
322973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search permission to the credentials.
323973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
324973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with the key usage count incremented if
325973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
326973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matched negative keys.
327973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
328973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the
329973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference.
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
331927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellskey_ref_t search_my_process_keyrings(struct key_type *type,
332927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				     const void *description,
333927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				     key_match_func_t match,
33478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells				     bool no_state_check,
335927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				     const struct cred *cred)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
337b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_ref_t key_ref, ret, err;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * searchable, but we failed to find a key or we found a negative key;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * otherwise we want to return a sample error (probably -EACCES) if
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * none of the keyrings were searchable
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
346664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = NULL;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = NULL;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = ERR_PTR(-EAGAIN);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the thread keyring first */
351c69e8d9c01db2adc503464993c358901c9af9de4David Howells	if (cred->thread_keyring) {
352664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
353c69e8d9c01db2adc503464993c358901c9af9de4David Howells			make_key_ref(cred->thread_keyring, 1),
35478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells			cred, type, description, match, no_state_check);
355664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
358664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
363664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
366664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the process keyring second */
372bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	if (cred->tgcred->process_keyring) {
373664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
374bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			make_key_ref(cred->tgcred->process_keyring, 1),
37578b7280cce23293f7570ad52c1ffe1485c6d9669David Howells			cred, type, description, match, no_state_check);
376664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
379664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
384664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
387664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3923e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* search the session keyring */
393bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	if (cred->tgcred->session_keyring) {
3948589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_lock();
395664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
396664cceb0093b755739e56572b836a99104ee8a75David Howells			make_key_ref(rcu_dereference(
397bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells					     cred->tgcred->session_keyring),
398664cceb0093b755739e56572b836a99104ee8a75David Howells				     1),
39978b7280cce23293f7570ad52c1ffe1485c6d9669David Howells			cred, type, description, match, no_state_check);
4008589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_unlock();
4013e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
402664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4033e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
405664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4063e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
4073e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
4083e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
4093e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
410664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4113e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4123e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
413664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4143e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4153e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
416b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	}
417b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* or search the user-session keyring */
418c69e8d9c01db2adc503464993c358901c9af9de4David Howells	else if (cred->user->session_keyring) {
419b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = keyring_search_aux(
420c69e8d9c01db2adc503464993c358901c9af9de4David Howells			make_key_ref(cred->user->session_keyring, 1),
42178b7280cce23293f7570ad52c1ffe1485c6d9669David Howells			cred, type, description, match, no_state_check);
422664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4243e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
425664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4263e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
4273e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
4283e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
4293e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
430664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4313e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4323e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
433664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4343e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4353e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4368589b4e00e352f983259140f25a262d973be6bc5David Howells	}
437b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
438927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	/* no key - decide on the error we're going to go for */
439927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	key_ref = ret ? ret : err;
440927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
441927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellsfound:
442927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	return key_ref;
443927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells}
444927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
445927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells/*
446973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first
447973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key in the manner of search_my_process_keyrings(), but also search
448973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the keys attached to the assumed authorisation key using its credentials if
449973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * one is available.
450973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
451973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Return same as search_my_process_keyrings().
452927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells */
453927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellskey_ref_t search_process_keyrings(struct key_type *type,
454927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				  const void *description,
455927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				  key_match_func_t match,
456927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells				  const struct cred *cred)
457927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells{
458927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	struct request_key_auth *rka;
459927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
460927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
461927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	might_sleep();
462927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
46378b7280cce23293f7570ad52c1ffe1485c6d9669David Howells	key_ref = search_my_process_keyrings(type, description, match,
46478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells					     false, cred);
465927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	if (!IS_ERR(key_ref))
466927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		goto found;
467927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	err = key_ref;
468927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells
469b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* if this process has an instantiation authorisation key, then we also
470b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * search the keyrings of the process mentioned there
471b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * - we don't permit access to request_key auth keys via this method
472b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 */
473c69e8d9c01db2adc503464993c358901c9af9de4David Howells	if (cred->request_key_auth &&
474d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	    cred == current_cred() &&
47504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells	    type != &key_type_request_key_auth
476b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	    ) {
47704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		/* defend against the auth key being revoked */
478c69e8d9c01db2adc503464993c358901c9af9de4David Howells		down_read(&cred->request_key_auth->sem);
479b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
480c69e8d9c01db2adc503464993c358901c9af9de4David Howells		if (key_validate(cred->request_key_auth) == 0) {
481c69e8d9c01db2adc503464993c358901c9af9de4David Howells			rka = cred->request_key_auth->payload.data;
482b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
48304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			key_ref = search_process_keyrings(type, description,
484d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells							  match, rka->cred);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
486c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
48704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
48804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			if (!IS_ERR(key_ref))
48904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				goto found;
49004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
491927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells			ret = key_ref;
49204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		} else {
493c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
4943e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no key - decide on the error we're going to go for */
498927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
499927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = ERR_PTR(-ENOKEY);
500927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	else if (err == ERR_PTR(-EACCES))
501927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = ret;
502927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells	else
503927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells		key_ref = err;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5053e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound:
506664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
507a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
510973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * See if the key we're looking at is the target key.
511664cceb0093b755739e56572b836a99104ee8a75David Howells */
512927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellsint lookup_user_key_possessed(const struct key *key, const void *target)
513664cceb0093b755739e56572b836a99104ee8a75David Howells{
514664cceb0093b755739e56572b836a99104ee8a75David Howells	return key == target;
515a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
516664cceb0093b755739e56572b836a99104ee8a75David Howells
517664cceb0093b755739e56572b836a99104ee8a75David Howells/*
518973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Look up a key ID given us by userspace with a given permissions mask to get
519973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the key it refers to.
520973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
521973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Flags can be passed to request that special keyrings be created if referred
522973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to directly, to permit partially constructed keys to be found and to skip
523973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * validity and permission checks on the found key.
524973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
525973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with an incremented usage count if successful;
526973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
527973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to a key or the best found key was a negative key; -EKEYREVOKED or
528973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
529973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * found key doesn't grant the requested permit or the LSM denied access to it;
530973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * or -ENOMEM if a special keyring couldn't be created.
531973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
532973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the
533973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference.
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5355593122eec26b061cc0b6fbff32118f1aadf4a27David Howellskey_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
5368bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			  key_perm_t perm)
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5388bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	struct request_key_auth *rka;
539d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *cred;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *key;
541b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	key_ref_t key_ref, skey_ref;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
544bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellstry_again:
545bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	cred = get_current_cred();
546664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(-ENOKEY);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (id) {
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_THREAD_KEYRING:
550b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->thread_keyring) {
5515593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5548bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_thread_keyring();
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5564d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
559bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
562b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->thread_keyring;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
564664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_PROCESS_KEYRING:
568bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		if (!cred->tgcred->process_keyring) {
5695593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5728bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_process_keyring();
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5744d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
577bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
580bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		key = cred->tgcred->process_keyring;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
582664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_SESSION_KEYRING:
586bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		if (!cred->tgcred->session_keyring) {
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* always install a session keyring upon access if one
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * doesn't exist yet */
5898bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
59069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
59169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
5923ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			if (lflags & KEY_LOOKUP_CREATE)
5933ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				ret = join_session_keyring(NULL);
5943ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			else
5953ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				ret = install_session_keyring(
5963ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells					cred->user->session_keyring);
597d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0)
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
600bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
6013ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells		} else if (cred->tgcred->session_keyring ==
6023ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			   cred->user->session_keyring &&
6033ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			   lflags & KEY_LOOKUP_CREATE) {
6043ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			ret = join_session_keyring(NULL);
6053ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			if (ret < 0)
6063ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells				goto error;
6073ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells			goto reget_creds;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6103e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_lock();
611bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		key = rcu_dereference(cred->tgcred->session_keyring);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
6133e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_unlock();
614664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_KEYRING:
618b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->user->uid_keyring) {
6198bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
62069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
62169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
62269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
62369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
624b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->user->uid_keyring;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
626664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_SESSION_KEYRING:
630b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->user->session_keyring) {
6318bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
63269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
63369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
63469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
63569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
636b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->user->session_keyring;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
638664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_GROUP_KEYRING:
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* group keyrings are not yet supported */
6434d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter		key_ref = ERR_PTR(-EINVAL);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
646b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	case KEY_SPEC_REQKEY_AUTH_KEY:
647b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->request_key_auth;
648b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		if (!key)
649b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			goto error;
650b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
651b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		atomic_inc(&key->usage);
652b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = make_key_ref(key, 1);
653b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		break;
654b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
6558bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	case KEY_SPEC_REQUESTOR_KEYRING:
656b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->request_key_auth)
6578bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6588bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
659b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_read(&cred->request_key_auth->sem);
660f67dabbdde1fe112dfff05d02890f1e0d54117a8Dan Carpenter		if (test_bit(KEY_FLAG_REVOKED,
661f67dabbdde1fe112dfff05d02890f1e0d54117a8Dan Carpenter			     &cred->request_key_auth->flags)) {
6628bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key_ref = ERR_PTR(-EKEYREVOKED);
6638bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = NULL;
6648bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		} else {
665b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells			rka = cred->request_key_auth->payload.data;
6668bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = rka->dest_keyring;
6678bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			atomic_inc(&key->usage);
6688bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		}
669b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_read(&cred->request_key_auth->sem);
6708bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		if (!key)
6718bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6728bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		key_ref = make_key_ref(key, 1);
6738bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		break;
6748bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
676664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = ERR_PTR(-EINVAL);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (id < 1)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key = key_lookup(id);
681664cceb0093b755739e56572b836a99104ee8a75David Howells		if (IS_ERR(key)) {
682e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells			key_ref = ERR_CAST(key);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
684664cceb0093b755739e56572b836a99104ee8a75David Howells		}
685664cceb0093b755739e56572b836a99104ee8a75David Howells
686664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 0);
687664cceb0093b755739e56572b836a99104ee8a75David Howells
688664cceb0093b755739e56572b836a99104ee8a75David Howells		/* check to see if we possess the key */
689664cceb0093b755739e56572b836a99104ee8a75David Howells		skey_ref = search_process_keyrings(key->type, key,
690664cceb0093b755739e56572b836a99104ee8a75David Howells						   lookup_user_key_possessed,
691d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells						   cred);
692664cceb0093b755739e56572b836a99104ee8a75David Howells
693664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(skey_ref)) {
694664cceb0093b755739e56572b836a99104ee8a75David Howells			key_put(key);
695664cceb0093b755739e56572b836a99104ee8a75David Howells			key_ref = skey_ref;
696664cceb0093b755739e56572b836a99104ee8a75David Howells		}
697664cceb0093b755739e56572b836a99104ee8a75David Howells
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7015593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	/* unlink does not use the nominated key in any way, so can skip all
7025593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	 * the permission checks as it is only concerned with the keyring */
7035593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
7045593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		ret = 0;
7055593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		goto error;
7065593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	}
7075593122eec26b061cc0b6fbff32118f1aadf4a27David Howells
7085593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
70976181c134f87479fa13bf2548ddf2999055d34d4David Howells		ret = wait_for_key_construction(key, true);
71076181c134f87479fa13bf2548ddf2999055d34d4David Howells		switch (ret) {
71176181c134f87479fa13bf2548ddf2999055d34d4David Howells		case -ERESTARTSYS:
71276181c134f87479fa13bf2548ddf2999055d34d4David Howells			goto invalid_key;
71376181c134f87479fa13bf2548ddf2999055d34d4David Howells		default:
71476181c134f87479fa13bf2548ddf2999055d34d4David Howells			if (perm)
71576181c134f87479fa13bf2548ddf2999055d34d4David Howells				goto invalid_key;
71676181c134f87479fa13bf2548ddf2999055d34d4David Howells		case 0:
71776181c134f87479fa13bf2548ddf2999055d34d4David Howells			break;
71876181c134f87479fa13bf2548ddf2999055d34d4David Howells		}
71976181c134f87479fa13bf2548ddf2999055d34d4David Howells	} else if (perm) {
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = key_validate(key);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto invalid_key;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EIO;
7265593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
7275593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7303e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* check the permissions */
731d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = key_task_permission(key_ref, cred, perm);
73229db9190634067c5a328ee5fcc2890251b836b4bDavid Howells	if (ret < 0)
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73531d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells	key->last_used_at = current_kernel_time().tv_sec;
73631d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells
737664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
738bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	put_cred(cred);
739664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key:
742664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref_put(key_ref);
743664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(ret);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto error;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
746bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	/* if we attempted to install a keyring, then it may have caused new
747bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	 * creds to be installed */
748bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellsreget_creds:
749bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	put_cred(cred);
750bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	goto try_again;
751a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells}
752bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
754973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Join the named keyring as the session keyring if possible else attempt to
755973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * create a new one of that name and join that.
756973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
757973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * If the name is NULL, an empty anonymous keyring will be installed as the
758973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * session keyring.
759973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells *
760973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Named session keyrings are joined with a semaphore held to prevent the
761973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * keyrings from going away whilst the attempt is made to going them and also
762973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to prevent a race in creating compatible session keyrings.
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
766d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *old;
767d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring;
769d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	long ret, serial;
770d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
771d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	/* only permit this if there's a single thread in the thread group -
772d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	 * this avoids us having to adjust the creds on all threads and risking
773d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	 * ENOMEM */
7745bb459bb45d1ad3c177485dcf0af01580aa31125Oleg Nesterov	if (!current_is_single_threaded())
775d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -EMLINK;
776d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
777d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
778d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
779d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
780d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	old = current_cred();
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if no name is provided, install an anonymous keyring */
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!name) {
784d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = install_session_keyring_to_cred(new, NULL);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
788d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		serial = new->tgcred->session_keyring->serial;
789d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = commit_creds(new);
790d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		if (ret == 0)
791d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			ret = serial;
792d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		goto okay;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allow the user to join or create a named keyring */
796bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_lock(&key_session_mutex);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look for an existing keyring of this name */
79969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	keyring = find_keyring_by_name(name, false);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PTR_ERR(keyring) == -ENOKEY) {
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* not found - try and create a new one */
802d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = keyring_alloc(name, old->uid, old->gid, old,
8037e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells					KEY_ALLOC_IN_QUOTA, NULL);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(keyring)) {
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = PTR_ERR(keyring);
806bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells			goto error2;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
808d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else if (IS_ERR(keyring)) {
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(keyring);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we've got a keyring - now to install it */
814d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_session_keyring_to_cred(new, keyring);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
818d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	commit_creds(new);
819d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	mutex_unlock(&key_session_mutex);
820d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = keyring->serial;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(keyring);
823d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsokay:
824d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return ret;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
826664cceb0093b755739e56572b836a99104ee8a75David Howellserror2:
827bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_unlock(&key_session_mutex);
828664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
829d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	abort_creds(new);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
831d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
832ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
833ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells/*
834973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Replace a process's session keyring on behalf of one of its children when
835973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the target  process is about to resume userspace execution.
836ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells */
83767d1214551e800f9fe7dc7c47a346d2df0fafed5Al Virovoid key_change_session_keyring(struct callback_head *twork)
838ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells{
839413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	const struct cred *old = current_cred();
84067d1214551e800f9fe7dc7c47a346d2df0fafed5Al Viro	struct cred *new = container_of(twork, struct cred, rcu);
841ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
842413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	if (unlikely(current->flags & PF_EXITING)) {
843413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov		put_cred(new);
844ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells		return;
845413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov	}
846ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
847ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  uid	= old->  uid;
848ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> euid	= old-> euid;
849ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> suid	= old-> suid;
850ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsuid	= old->fsuid;
851ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  gid	= old->  gid;
852ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> egid	= old-> egid;
853ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> sgid	= old-> sgid;
854ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsgid	= old->fsgid;
855ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->user	= get_uid(old->user);
8560093ccb68f3753c0ba4d74c89d7e0f444b8d6123Eric W. Biederman	new->user_ns	= get_user_ns(new->user_ns);
857ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->group_info	= get_group_info(old->group_info);
858ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
859ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->securebits	= old->securebits;
860ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_inheritable	= old->cap_inheritable;
861ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_permitted	= old->cap_permitted;
862ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_effective	= old->cap_effective;
863ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_bset		= old->cap_bset;
864ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
865ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->jit_keyring	= old->jit_keyring;
866ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->thread_keyring	= key_get(old->thread_keyring);
867ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->tgcred->tgid	= old->tgcred->tgid;
868ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
869ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
870ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	security_transfer_creds(new, old);
871ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
872ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	commit_creds(new);
873ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells}
874