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