process_keys.c revision 685bfd2c48bb3284d31e73ff3151c957d76deda9
169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* Management of a process's keyrings
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by David Howells (dhowells@redhat.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/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
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* session keyring create vs join semaphore */
25bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnarstatic DEFINE_MUTEX(key_session_mutex);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* user keyring creation semaphore */
2869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic DEFINE_MUTEX(key_user_keyring_mutex);
2969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 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/*****************************************************************************/
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * install user and user session keyrings for a particular UID
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
458bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howellsint install_user_keyrings(void)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct user_struct *user;
48d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *cred;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *uid_keyring, *session_keyring;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[20];
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	cred = current_cred();
54d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	user = cred->user;
55d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
5669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kenter("%p{%u}", user, user->uid);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (user->uid_keyring) {
5969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		kleave(" = 0 [exist]");
6069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		return 0;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_lock(&key_user_keyring_mutex);
6469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	ret = 0;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	if (!user->uid_keyring) {
6769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get the UID-specific keyring
6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * - there may be one in existence already as it may have been
6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   pinned by a session, but the user_struct pointing to it
7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 *   may have been destroyed by setuid */
7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid.%u", user->uid);
7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
7369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		uid_keyring = find_keyring_by_name(buf, true);
7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(uid_keyring)) {
7569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
76d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells						    cred, KEY_ALLOC_IN_QUOTA,
7769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells						    NULL);
7869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(uid_keyring)) {
7969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(uid_keyring);
8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* get a default session keyring (which might also exist
8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		 * already) */
8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		sprintf(buf, "_uid_ses.%u", user->uid);
8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
8869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		session_keyring = find_keyring_by_name(buf, true);
8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		if (IS_ERR(session_keyring)) {
9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			session_keyring =
9169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				keyring_alloc(buf, user->uid, (gid_t) -1,
92d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells					      cred, KEY_ALLOC_IN_QUOTA, NULL);
9369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (IS_ERR(session_keyring)) {
9469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				ret = PTR_ERR(session_keyring);
9569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release;
9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			}
9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			/* we install a link from the user session keyring to
9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			 * the user keyring */
10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			ret = key_link(session_keyring, uid_keyring);
10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
10269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error_release_both;
10369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		/* install the keyrings */
10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->uid_keyring = uid_keyring;
10769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		user->session_keyring = session_keyring;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
11169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = 0");
11269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	return 0;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both:
11569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(session_keyring);
11669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release:
11769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	key_put(uid_keyring);
118664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
11969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	mutex_unlock(&key_user_keyring_mutex);
12069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	kleave(" = %d", ret);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
12269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
125d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a fresh thread keyring directly to new credentials
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/*
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 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/*
164d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a process keyring directly to a credentials struct
165d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - returns -EEXIST if there was already a process keyring, 0 if one installed,
166d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells *   and other -ve on any other error
167d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells */
168d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_process_keyring_to_cred(struct cred *new)
169d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells{
170d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct key *keyring;
171d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	int ret;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
173d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (new->tgcred->process_keyring)
174d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -EEXIST;
175d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
176d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	keyring = keyring_alloc("_pid", new->uid, new->gid,
177d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
178d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (IS_ERR(keyring))
179d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return PTR_ERR(keyring);
180d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
181d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_lock_irq(&new->tgcred->lock);
182d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new->tgcred->process_keyring) {
183d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		new->tgcred->process_keyring = keyring;
184d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = NULL;
185d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = 0;
186d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else {
187d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = -EEXIST;
188d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	}
189d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_unlock_irq(&new->tgcred->lock);
190d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	key_put(keyring);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
192d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make sure a process keyring is installed
196d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - we
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);
210d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret != -EEXIST ?: 0;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
214d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
217d84f4f992cbd76e8f39c488cf0c5d123843923b1David 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;
229d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		if (cred->tgcred->session_keyring)
2307e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells			flags = KEY_ALLOC_IN_QUOTA;
2317e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells
232d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = keyring_alloc("_ses", cred->uid, cred->gid,
233d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells					cred, flags, NULL);
2341a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		if (IS_ERR(keyring))
2351a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells			return PTR_ERR(keyring);
236d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&keyring->usage);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install the keyring */
241d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_lock_irq(&cred->tgcred->lock);
242d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	old = cred->tgcred->session_keyring;
243d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
244d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	spin_unlock_irq(&cred->tgcred->lock);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	/* we're using RCU on the pointer, but there's no point synchronising
2471a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	 * on it if it didn't previously point to anything */
2481a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	if (old) {
2491a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		synchronize_rcu();
2501a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells		key_put(old);
2511a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells	return 0;
254d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
257d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a session keyring, discarding the old one
258d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - if a keyring is not supplied, an empty one is invented
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
260d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_session_keyring(struct key *keyring)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
262d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
263d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	int ret;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
265d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
266d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
267d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_session_keyring_to_cred(new, NULL);
270d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (ret < 0) {
271d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		abort_creds(new);
272d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return ret;
273d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	}
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
275d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return commit_creds(new);
276d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem user ID changed
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk)
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
285b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
286b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
287b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
288b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
289b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsuid_changed() */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem group ID changed
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the ownership of the thread keyring */
301b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	BUG_ON(!tsk->cred);
302b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	if (tsk->cred->thread_keyring) {
303b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_write(&tsk->cred->thread_keyring->sem);
304b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
305b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_write(&tsk->cred->thread_keyring->sem);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsgid_changed() */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search the process keyrings for the first matching key
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we use the supplied match function to see if the description (or other
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   feature of interest) matches
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -EAGAIN if we didn't find any matching key
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -ENOKEY if we found only negative matching keys
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
318664cceb0093b755739e56572b836a99104ee8a75David Howellskey_ref_t search_process_keyrings(struct key_type *type,
319664cceb0093b755739e56572b836a99104ee8a75David Howells				  const void *description,
320664cceb0093b755739e56572b836a99104ee8a75David Howells				  key_match_func_t match,
321d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells				  const struct cred *cred)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	struct request_key_auth *rka;
324b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	key_ref_t key_ref, ret, err;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells	might_sleep();
32704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * searchable, but we failed to find a key or we found a negative key;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * otherwise we want to return a sample error (probably -EACCES) if
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * none of the keyrings were searchable
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
335664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = NULL;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = NULL;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = ERR_PTR(-EAGAIN);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the thread keyring first */
340c69e8d9c01db2adc503464993c358901c9af9de4David Howells	if (cred->thread_keyring) {
341664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
342c69e8d9c01db2adc503464993c358901c9af9de4David Howells			make_key_ref(cred->thread_keyring, 1),
343d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			cred, type, description, match);
344664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
347664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
352664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
355664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search the process keyring second */
361bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	if (cred->tgcred->process_keyring) {
362664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
363bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			make_key_ref(cred->tgcred->process_keyring, 1),
364d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			cred, type, description, match);
365664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
368664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -EAGAIN: /* no key */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case -ENOKEY: /* negative key */
373664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
376664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3813e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* search the session keyring */
382bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	if (cred->tgcred->session_keyring) {
3838589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_lock();
384664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = keyring_search_aux(
385664cceb0093b755739e56572b836a99104ee8a75David Howells			make_key_ref(rcu_dereference(
386bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells					     cred->tgcred->session_keyring),
387664cceb0093b755739e56572b836a99104ee8a75David Howells				     1),
388d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			cred, type, description, match);
3898589b4e00e352f983259140f25a262d973be6bc5David Howells		rcu_read_unlock();
3903e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
391664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
3923e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
3933e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
394664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
3953e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
3963e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
3973e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
3983e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
399664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4003e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4013e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
402664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4033e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
405b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	}
406b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* or search the user-session keyring */
407c69e8d9c01db2adc503464993c358901c9af9de4David Howells	else if (cred->user->session_keyring) {
408b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = keyring_search_aux(
409c69e8d9c01db2adc503464993c358901c9af9de4David Howells			make_key_ref(cred->user->session_keyring, 1),
410d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			cred, type, description, match);
411664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(key_ref))
4123e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			goto found;
4133e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells
414664cceb0093b755739e56572b836a99104ee8a75David Howells		switch (PTR_ERR(key_ref)) {
4153e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -EAGAIN: /* no key */
4163e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			if (ret)
4173e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
4183e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		case -ENOKEY: /* negative key */
419664cceb0093b755739e56572b836a99104ee8a75David Howells			ret = key_ref;
4203e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4213e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		default:
422664cceb0093b755739e56572b836a99104ee8a75David Howells			err = key_ref;
4233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells			break;
4243e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4258589b4e00e352f983259140f25a262d973be6bc5David Howells	}
426b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
427b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	/* if this process has an instantiation authorisation key, then we also
428b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * search the keyrings of the process mentioned there
429b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 * - we don't permit access to request_key auth keys via this method
430b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	 */
431c69e8d9c01db2adc503464993c358901c9af9de4David Howells	if (cred->request_key_auth &&
432d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	    cred == current_cred() &&
43304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells	    type != &key_type_request_key_auth
434b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	    ) {
43504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		/* defend against the auth key being revoked */
436c69e8d9c01db2adc503464993c358901c9af9de4David Howells		down_read(&cred->request_key_auth->sem);
437b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
438c69e8d9c01db2adc503464993c358901c9af9de4David Howells		if (key_validate(cred->request_key_auth) == 0) {
439c69e8d9c01db2adc503464993c358901c9af9de4David Howells			rka = cred->request_key_auth->payload.data;
440b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
44104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			key_ref = search_process_keyrings(type, description,
442d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells							  match, rka->cred);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
444c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
44504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
44604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			if (!IS_ERR(key_ref))
44704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				goto found;
44804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells
44904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			switch (PTR_ERR(key_ref)) {
45004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			case -EAGAIN: /* no key */
45104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				if (ret)
45204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells					break;
45304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			case -ENOKEY: /* negative key */
45404c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				ret = key_ref;
4553e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells				break;
45604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			default:
45704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				err = key_ref;
45804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells				break;
45904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells			}
46004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells		} else {
461c69e8d9c01db2adc503464993c358901c9af9de4David Howells			up_read(&cred->request_key_auth->sem);
4623e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		}
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no key - decide on the error we're going to go for */
466664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ret ? ret : err;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4683e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound:
469664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end search_process_keyrings() */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
475664cceb0093b755739e56572b836a99104ee8a75David Howells * see if the key we're looking at is the target key
476664cceb0093b755739e56572b836a99104ee8a75David Howells */
477664cceb0093b755739e56572b836a99104ee8a75David Howellsstatic int lookup_user_key_possessed(const struct key *key, const void *target)
478664cceb0093b755739e56572b836a99104ee8a75David Howells{
479664cceb0093b755739e56572b836a99104ee8a75David Howells	return key == target;
480664cceb0093b755739e56572b836a99104ee8a75David Howells
481664cceb0093b755739e56572b836a99104ee8a75David Howells} /* end lookup_user_key_possessed() */
482664cceb0093b755739e56572b836a99104ee8a75David Howells
483664cceb0093b755739e56572b836a99104ee8a75David Howells/*****************************************************************************/
484664cceb0093b755739e56572b836a99104ee8a75David Howells/*
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - don't create special keyrings unless so requested
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - partially constructed keys aren't found unless requested
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4895593122eec26b061cc0b6fbff32118f1aadf4a27David Howellskey_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
4908bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			  key_perm_t perm)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4928bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	struct request_key_auth *rka;
493d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *cred;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *key;
495b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells	key_ref_t key_ref, skey_ref;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellstry_again:
499bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	cred = get_current_cred();
500664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(-ENOKEY);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (id) {
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_THREAD_KEYRING:
504b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->thread_keyring) {
5055593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5088bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_thread_keyring();
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5104d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
513bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
516b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->thread_keyring;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
518664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_PROCESS_KEYRING:
522bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		if (!cred->tgcred->process_keyring) {
5235593122eec26b061cc0b6fbff32118f1aadf4a27David Howells			if (!(lflags & KEY_LOOKUP_CREATE))
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5268bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_process_keyring();
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0) {
5284d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter				key_ref = ERR_PTR(ret);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
531bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
534bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		key = cred->tgcred->process_keyring;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
536664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_SESSION_KEYRING:
540bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		if (!cred->tgcred->session_keyring) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* always install a session keyring upon access if one
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * doesn't exist yet */
5438bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
54469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
54569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
546b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells			ret = install_session_keyring(
547b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells				cred->user->session_keyring);
548d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret < 0)
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto error;
551bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells			goto reget_creds;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5543e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_lock();
555bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells		key = rcu_dereference(cred->tgcred->session_keyring);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
5573e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells		rcu_read_unlock();
558664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_KEYRING:
562b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->user->uid_keyring) {
5638bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
56469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
56569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
56669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
56769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
568b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->user->uid_keyring;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&key->usage);
570664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 1);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KEY_SPEC_USER_SESSION_KEYRING:
574b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->user->session_keyring) {
5758bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			ret = install_user_keyrings();
57669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells			if (ret < 0)
57769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells				goto error;
57869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells		}
57969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells
580b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->user->session_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_GROUP_KEYRING:
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* group keyrings are not yet supported */
5874d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter		key_ref = ERR_PTR(-EINVAL);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
590b5f545c880a2a47947ba2118b2509644ab7a2969David Howells	case KEY_SPEC_REQKEY_AUTH_KEY:
591b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		key = cred->request_key_auth;
592b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		if (!key)
593b5f545c880a2a47947ba2118b2509644ab7a2969David Howells			goto error;
594b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
595b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		atomic_inc(&key->usage);
596b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		key_ref = make_key_ref(key, 1);
597b5f545c880a2a47947ba2118b2509644ab7a2969David Howells		break;
598b5f545c880a2a47947ba2118b2509644ab7a2969David Howells
5998bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells	case KEY_SPEC_REQUESTOR_KEYRING:
600b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (!cred->request_key_auth)
6018bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6028bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
603b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		down_read(&cred->request_key_auth->sem);
604b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
6058bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key_ref = ERR_PTR(-EKEYREVOKED);
6068bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = NULL;
6078bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		} else {
608b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells			rka = cred->request_key_auth->payload.data;
6098bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			key = rka->dest_keyring;
6108bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			atomic_inc(&key->usage);
6118bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		}
612b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells		up_read(&cred->request_key_auth->sem);
6138bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		if (!key)
6148bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells			goto error;
6158bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		key_ref = make_key_ref(key, 1);
6168bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells		break;
6178bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
619664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = ERR_PTR(-EINVAL);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (id < 1)
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key = key_lookup(id);
624664cceb0093b755739e56572b836a99104ee8a75David Howells		if (IS_ERR(key)) {
625e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells			key_ref = ERR_CAST(key);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
627664cceb0093b755739e56572b836a99104ee8a75David Howells		}
628664cceb0093b755739e56572b836a99104ee8a75David Howells
629664cceb0093b755739e56572b836a99104ee8a75David Howells		key_ref = make_key_ref(key, 0);
630664cceb0093b755739e56572b836a99104ee8a75David Howells
631664cceb0093b755739e56572b836a99104ee8a75David Howells		/* check to see if we possess the key */
632664cceb0093b755739e56572b836a99104ee8a75David Howells		skey_ref = search_process_keyrings(key->type, key,
633664cceb0093b755739e56572b836a99104ee8a75David Howells						   lookup_user_key_possessed,
634d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells						   cred);
635664cceb0093b755739e56572b836a99104ee8a75David Howells
636664cceb0093b755739e56572b836a99104ee8a75David Howells		if (!IS_ERR(skey_ref)) {
637664cceb0093b755739e56572b836a99104ee8a75David Howells			key_put(key);
638664cceb0093b755739e56572b836a99104ee8a75David Howells			key_ref = skey_ref;
639664cceb0093b755739e56572b836a99104ee8a75David Howells		}
640664cceb0093b755739e56572b836a99104ee8a75David Howells
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6445593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	/* unlink does not use the nominated key in any way, so can skip all
6455593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	 * the permission checks as it is only concerned with the keyring */
6465593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
6475593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		ret = 0;
6485593122eec26b061cc0b6fbff32118f1aadf4a27David Howells		goto error;
6495593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	}
6505593122eec26b061cc0b6fbff32118f1aadf4a27David Howells
6515593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
65276181c134f87479fa13bf2548ddf2999055d34d4David Howells		ret = wait_for_key_construction(key, true);
65376181c134f87479fa13bf2548ddf2999055d34d4David Howells		switch (ret) {
65476181c134f87479fa13bf2548ddf2999055d34d4David Howells		case -ERESTARTSYS:
65576181c134f87479fa13bf2548ddf2999055d34d4David Howells			goto invalid_key;
65676181c134f87479fa13bf2548ddf2999055d34d4David Howells		default:
65776181c134f87479fa13bf2548ddf2999055d34d4David Howells			if (perm)
65876181c134f87479fa13bf2548ddf2999055d34d4David Howells				goto invalid_key;
65976181c134f87479fa13bf2548ddf2999055d34d4David Howells		case 0:
66076181c134f87479fa13bf2548ddf2999055d34d4David Howells			break;
66176181c134f87479fa13bf2548ddf2999055d34d4David Howells		}
66276181c134f87479fa13bf2548ddf2999055d34d4David Howells	} else if (perm) {
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = key_validate(key);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto invalid_key;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EIO;
6695593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
6705593122eec26b061cc0b6fbff32118f1aadf4a27David Howells	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6733e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells	/* check the permissions */
674d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = key_task_permission(key_ref, cred, perm);
67529db9190634067c5a328ee5fcc2890251b836b4bDavid Howells	if (ret < 0)
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto invalid_key;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
678664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
679bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	put_cred(cred);
680664cceb0093b755739e56572b836a99104ee8a75David Howells	return key_ref;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
682664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key:
683664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref_put(key_ref);
684664cceb0093b755739e56572b836a99104ee8a75David Howells	key_ref = ERR_PTR(ret);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto error;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
687bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	/* if we attempted to install a keyring, then it may have caused new
688bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	 * creds to be installed */
689bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellsreget_creds:
690bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	put_cred(cred);
691bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells	goto try_again;
692bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end lookup_user_key() */
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create a new one of that name if not
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - named session keyring joining is done with a semaphore held
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
704d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	const struct cred *old;
705d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	struct cred *new;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct key *keyring;
707d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	long ret, serial;
708d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
709d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	/* only permit this if there's a single thread in the thread group -
710d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	 * this avoids us having to adjust the creds on all threads and risking
711d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	 * ENOMEM */
7125bb459bb45d1ad3c177485dcf0af01580aa31125Oleg Nesterov	if (!current_is_single_threaded())
713d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -EMLINK;
714d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
715d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	new = prepare_creds();
716d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	if (!new)
717d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		return -ENOMEM;
718d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	old = current_cred();
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if no name is provided, install an anonymous keyring */
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!name) {
722d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = install_session_keyring_to_cred(new, NULL);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
726d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		serial = new->tgcred->session_keyring->serial;
727d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		ret = commit_creds(new);
728d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		if (ret == 0)
729d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells			ret = serial;
730d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		goto okay;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allow the user to join or create a named keyring */
734bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_lock(&key_session_mutex);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look for an existing keyring of this name */
73769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells	keyring = find_keyring_by_name(name, false);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PTR_ERR(keyring) == -ENOKEY) {
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* not found - try and create a new one */
740d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells		keyring = keyring_alloc(name, old->uid, old->gid, old,
7417e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells					KEY_ALLOC_IN_QUOTA, NULL);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(keyring)) {
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = PTR_ERR(keyring);
744bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells			goto error2;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
746d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	} else if (IS_ERR(keyring)) {
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(keyring);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we've got a keyring - now to install it */
752d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	ret = install_session_keyring_to_cred(new, keyring);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error2;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
756d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	commit_creds(new);
757d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	mutex_unlock(&key_session_mutex);
758d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = keyring->serial;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	key_put(keyring);
761d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsokay:
762d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	return ret;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
764664cceb0093b755739e56572b836a99104ee8a75David Howellserror2:
765bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar	mutex_unlock(&key_session_mutex);
766664cceb0093b755739e56572b836a99104ee8a75David Howellserror:
767d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells	abort_creds(new);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
769d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells}
770ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
771ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells/*
772ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells * Replace a process's session keyring when that process resumes userspace on
773ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells * behalf of one of its children
774ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells */
775ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howellsvoid key_replace_session_keyring(void)
776ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells{
777ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	const struct cred *old;
778ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	struct cred *new;
779ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
780ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	if (!current->replacement_session_keyring)
781ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells		return;
782ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
783ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	write_lock_irq(&tasklist_lock);
784ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new = current->replacement_session_keyring;
785ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	current->replacement_session_keyring = NULL;
786ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	write_unlock_irq(&tasklist_lock);
787ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
788ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	if (!new)
789ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells		return;
790ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
791ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	old = current_cred();
792ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  uid	= old->  uid;
793ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> euid	= old-> euid;
794ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> suid	= old-> suid;
795ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsuid	= old->fsuid;
796ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->  gid	= old->  gid;
797ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> egid	= old-> egid;
798ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new-> sgid	= old-> sgid;
799ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->fsgid	= old->fsgid;
800ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->user	= get_uid(old->user);
801ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->group_info	= get_group_info(old->group_info);
802ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
803ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->securebits	= old->securebits;
804ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_inheritable	= old->cap_inheritable;
805ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_permitted	= old->cap_permitted;
806ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_effective	= old->cap_effective;
807ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->cap_bset		= old->cap_bset;
808ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
809ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->jit_keyring	= old->jit_keyring;
810ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->thread_keyring	= key_get(old->thread_keyring);
811ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->tgcred->tgid	= old->tgcred->tgid;
812ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
813ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
814ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	security_transfer_creds(new, old);
815ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells
816ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells	commit_creds(new);
817ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells}
818