xref: /linux/security/keys/process_keys.c (revision 4bdf0bc3)
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 {
2381da177e4SLinus Torvalds 		atomic_inc(&keyring->usage);
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  */
322*4bdf0bc3SDavid 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 */
338*4bdf0bc3SDavid Howells 	if (ctx->cred->thread_keyring) {
339664cceb0SDavid Howells 		key_ref = keyring_search_aux(
340*4bdf0bc3SDavid 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 */
356*4bdf0bc3SDavid Howells 	if (ctx->cred->process_keyring) {
357664cceb0SDavid Howells 		key_ref = keyring_search_aux(
358*4bdf0bc3SDavid 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 */
376*4bdf0bc3SDavid Howells 	if (ctx->cred->session_keyring) {
3778589b4e0SDavid Howells 		rcu_read_lock();
378664cceb0SDavid Howells 		key_ref = keyring_search_aux(
379*4bdf0bc3SDavid Howells 			make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1),
380*4bdf0bc3SDavid 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 */
399*4bdf0bc3SDavid Howells 	else if (ctx->cred->user->session_keyring) {
400664cceb0SDavid Howells 		key_ref = keyring_search_aux(
401*4bdf0bc3SDavid Howells 			make_key_ref(ctx->cred->user->session_keyring, 1),
402*4bdf0bc3SDavid 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  */
434*4bdf0bc3SDavid 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 
441*4bdf0bc3SDavid 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 	 */
450*4bdf0bc3SDavid Howells 	if (ctx->cred->request_key_auth &&
451*4bdf0bc3SDavid Howells 	    ctx->cred == current_cred() &&
452*4bdf0bc3SDavid Howells 	    ctx->index_key.type != &key_type_request_key_auth
453b5f545c8SDavid Howells 	    ) {
454*4bdf0bc3SDavid Howells 		const struct cred *cred = ctx->cred;
455*4bdf0bc3SDavid Howells 
45604c567d9SDavid Howells 		/* defend against the auth key being revoked */
457c69e8d9cSDavid Howells 		down_read(&cred->request_key_auth->sem);
45804c567d9SDavid Howells 
459*4bdf0bc3SDavid Howells 		if (key_validate(ctx->cred->request_key_auth) == 0) {
460*4bdf0bc3SDavid Howells 			rka = ctx->cred->request_key_auth->payload.data;
4613e30148cSDavid Howells 
462*4bdf0bc3SDavid Howells 			ctx->cred = rka->cred;
463*4bdf0bc3SDavid Howells 			key_ref = search_process_keyrings(ctx);
464*4bdf0bc3SDavid 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  */
492927942aaSDavid Howells int lookup_user_key_possessed(const struct key *key, const void *target)
493664cceb0SDavid Howells {
494664cceb0SDavid Howells 	return key == target;
495a8b17ed0SDavid Howells }
496664cceb0SDavid Howells 
497664cceb0SDavid Howells /*
498973c9f4fSDavid Howells  * Look up a key ID given us by userspace with a given permissions mask to get
499973c9f4fSDavid Howells  * the key it refers to.
500973c9f4fSDavid Howells  *
501973c9f4fSDavid Howells  * Flags can be passed to request that special keyrings be created if referred
502973c9f4fSDavid Howells  * to directly, to permit partially constructed keys to be found and to skip
503973c9f4fSDavid Howells  * validity and permission checks on the found key.
504973c9f4fSDavid Howells  *
505973c9f4fSDavid Howells  * Returns a pointer to the key with an incremented usage count if successful;
506973c9f4fSDavid Howells  * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
507973c9f4fSDavid Howells  * to a key or the best found key was a negative key; -EKEYREVOKED or
508973c9f4fSDavid Howells  * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
509973c9f4fSDavid Howells  * found key doesn't grant the requested permit or the LSM denied access to it;
510973c9f4fSDavid Howells  * or -ENOMEM if a special keyring couldn't be created.
511973c9f4fSDavid Howells  *
512973c9f4fSDavid Howells  * In the case of a successful return, the possession attribute is set on the
513973c9f4fSDavid Howells  * returned key reference.
5141da177e4SLinus Torvalds  */
5155593122eSDavid Howells key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
5168bbf4976SDavid Howells 			  key_perm_t perm)
5171da177e4SLinus Torvalds {
518*4bdf0bc3SDavid Howells 	struct keyring_search_context ctx = {
519*4bdf0bc3SDavid Howells 		.match	= lookup_user_key_possessed,
520*4bdf0bc3SDavid Howells 		.flags	= (KEYRING_SEARCH_NO_STATE_CHECK |
521*4bdf0bc3SDavid Howells 			   KEYRING_SEARCH_LOOKUP_DIRECT),
522*4bdf0bc3SDavid Howells 	};
5238bbf4976SDavid Howells 	struct request_key_auth *rka;
5241da177e4SLinus Torvalds 	struct key *key;
525b6dff3ecSDavid Howells 	key_ref_t key_ref, skey_ref;
5261da177e4SLinus Torvalds 	int ret;
5271da177e4SLinus Torvalds 
528bb952bb9SDavid Howells try_again:
529*4bdf0bc3SDavid Howells 	ctx.cred = get_current_cred();
530664cceb0SDavid Howells 	key_ref = ERR_PTR(-ENOKEY);
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	switch (id) {
5331da177e4SLinus Torvalds 	case KEY_SPEC_THREAD_KEYRING:
534*4bdf0bc3SDavid Howells 		if (!ctx.cred->thread_keyring) {
5355593122eSDavid Howells 			if (!(lflags & KEY_LOOKUP_CREATE))
5361da177e4SLinus Torvalds 				goto error;
5371da177e4SLinus Torvalds 
5388bbf4976SDavid Howells 			ret = install_thread_keyring();
5391da177e4SLinus Torvalds 			if (ret < 0) {
5404d09ec0fSDan Carpenter 				key_ref = ERR_PTR(ret);
5411da177e4SLinus Torvalds 				goto error;
5421da177e4SLinus Torvalds 			}
543bb952bb9SDavid Howells 			goto reget_creds;
5441da177e4SLinus Torvalds 		}
5451da177e4SLinus Torvalds 
546*4bdf0bc3SDavid Howells 		key = ctx.cred->thread_keyring;
5471da177e4SLinus Torvalds 		atomic_inc(&key->usage);
548664cceb0SDavid Howells 		key_ref = make_key_ref(key, 1);
5491da177e4SLinus Torvalds 		break;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 	case KEY_SPEC_PROCESS_KEYRING:
552*4bdf0bc3SDavid Howells 		if (!ctx.cred->process_keyring) {
5535593122eSDavid Howells 			if (!(lflags & KEY_LOOKUP_CREATE))
5541da177e4SLinus Torvalds 				goto error;
5551da177e4SLinus Torvalds 
5568bbf4976SDavid Howells 			ret = install_process_keyring();
5571da177e4SLinus Torvalds 			if (ret < 0) {
5584d09ec0fSDan Carpenter 				key_ref = ERR_PTR(ret);
5591da177e4SLinus Torvalds 				goto error;
5601da177e4SLinus Torvalds 			}
561bb952bb9SDavid Howells 			goto reget_creds;
5621da177e4SLinus Torvalds 		}
5631da177e4SLinus Torvalds 
564*4bdf0bc3SDavid Howells 		key = ctx.cred->process_keyring;
5651da177e4SLinus Torvalds 		atomic_inc(&key->usage);
566664cceb0SDavid Howells 		key_ref = make_key_ref(key, 1);
5671da177e4SLinus Torvalds 		break;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	case KEY_SPEC_SESSION_KEYRING:
570*4bdf0bc3SDavid Howells 		if (!ctx.cred->session_keyring) {
5711da177e4SLinus Torvalds 			/* always install a session keyring upon access if one
5721da177e4SLinus Torvalds 			 * doesn't exist yet */
5738bbf4976SDavid Howells 			ret = install_user_keyrings();
57469664cf1SDavid Howells 			if (ret < 0)
57569664cf1SDavid Howells 				goto error;
5763ecf1b4fSDavid Howells 			if (lflags & KEY_LOOKUP_CREATE)
5773ecf1b4fSDavid Howells 				ret = join_session_keyring(NULL);
5783ecf1b4fSDavid Howells 			else
579b6dff3ecSDavid Howells 				ret = install_session_keyring(
580*4bdf0bc3SDavid Howells 					ctx.cred->user->session_keyring);
581d84f4f99SDavid Howells 
5821da177e4SLinus Torvalds 			if (ret < 0)
5831da177e4SLinus Torvalds 				goto error;
584bb952bb9SDavid Howells 			goto reget_creds;
585*4bdf0bc3SDavid Howells 		} else if (ctx.cred->session_keyring ==
586*4bdf0bc3SDavid Howells 			   ctx.cred->user->session_keyring &&
5873ecf1b4fSDavid Howells 			   lflags & KEY_LOOKUP_CREATE) {
5883ecf1b4fSDavid Howells 			ret = join_session_keyring(NULL);
5893ecf1b4fSDavid Howells 			if (ret < 0)
5903ecf1b4fSDavid Howells 				goto error;
5913ecf1b4fSDavid Howells 			goto reget_creds;
5921da177e4SLinus Torvalds 		}
5931da177e4SLinus Torvalds 
5943e30148cSDavid Howells 		rcu_read_lock();
595*4bdf0bc3SDavid Howells 		key = rcu_dereference(ctx.cred->session_keyring);
5961da177e4SLinus Torvalds 		atomic_inc(&key->usage);
5973e30148cSDavid Howells 		rcu_read_unlock();
598664cceb0SDavid Howells 		key_ref = make_key_ref(key, 1);
5991da177e4SLinus Torvalds 		break;
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 	case KEY_SPEC_USER_KEYRING:
602*4bdf0bc3SDavid Howells 		if (!ctx.cred->user->uid_keyring) {
6038bbf4976SDavid Howells 			ret = install_user_keyrings();
60469664cf1SDavid Howells 			if (ret < 0)
60569664cf1SDavid Howells 				goto error;
60669664cf1SDavid Howells 		}
60769664cf1SDavid Howells 
608*4bdf0bc3SDavid Howells 		key = ctx.cred->user->uid_keyring;
6091da177e4SLinus Torvalds 		atomic_inc(&key->usage);
610664cceb0SDavid Howells 		key_ref = make_key_ref(key, 1);
6111da177e4SLinus Torvalds 		break;
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	case KEY_SPEC_USER_SESSION_KEYRING:
614*4bdf0bc3SDavid Howells 		if (!ctx.cred->user->session_keyring) {
6158bbf4976SDavid Howells 			ret = install_user_keyrings();
61669664cf1SDavid Howells 			if (ret < 0)
61769664cf1SDavid Howells 				goto error;
61869664cf1SDavid Howells 		}
61969664cf1SDavid Howells 
620*4bdf0bc3SDavid Howells 		key = ctx.cred->user->session_keyring;
6211da177e4SLinus Torvalds 		atomic_inc(&key->usage);
622664cceb0SDavid Howells 		key_ref = make_key_ref(key, 1);
6231da177e4SLinus Torvalds 		break;
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	case KEY_SPEC_GROUP_KEYRING:
6261da177e4SLinus Torvalds 		/* group keyrings are not yet supported */
6274d09ec0fSDan Carpenter 		key_ref = ERR_PTR(-EINVAL);
6281da177e4SLinus Torvalds 		goto error;
6291da177e4SLinus Torvalds 
630b5f545c8SDavid Howells 	case KEY_SPEC_REQKEY_AUTH_KEY:
631*4bdf0bc3SDavid Howells 		key = ctx.cred->request_key_auth;
632b5f545c8SDavid Howells 		if (!key)
633b5f545c8SDavid Howells 			goto error;
634b5f545c8SDavid Howells 
635b5f545c8SDavid Howells 		atomic_inc(&key->usage);
636b5f545c8SDavid Howells 		key_ref = make_key_ref(key, 1);
637b5f545c8SDavid Howells 		break;
638b5f545c8SDavid Howells 
6398bbf4976SDavid Howells 	case KEY_SPEC_REQUESTOR_KEYRING:
640*4bdf0bc3SDavid Howells 		if (!ctx.cred->request_key_auth)
6418bbf4976SDavid Howells 			goto error;
6428bbf4976SDavid Howells 
643*4bdf0bc3SDavid Howells 		down_read(&ctx.cred->request_key_auth->sem);
644f67dabbdSDan Carpenter 		if (test_bit(KEY_FLAG_REVOKED,
645*4bdf0bc3SDavid Howells 			     &ctx.cred->request_key_auth->flags)) {
6468bbf4976SDavid Howells 			key_ref = ERR_PTR(-EKEYREVOKED);
6478bbf4976SDavid Howells 			key = NULL;
6488bbf4976SDavid Howells 		} else {
649*4bdf0bc3SDavid Howells 			rka = ctx.cred->request_key_auth->payload.data;
6508bbf4976SDavid Howells 			key = rka->dest_keyring;
6518bbf4976SDavid Howells 			atomic_inc(&key->usage);
6528bbf4976SDavid Howells 		}
653*4bdf0bc3SDavid Howells 		up_read(&ctx.cred->request_key_auth->sem);
6548bbf4976SDavid Howells 		if (!key)
6558bbf4976SDavid Howells 			goto error;
6568bbf4976SDavid Howells 		key_ref = make_key_ref(key, 1);
6578bbf4976SDavid Howells 		break;
6588bbf4976SDavid Howells 
6591da177e4SLinus Torvalds 	default:
660664cceb0SDavid Howells 		key_ref = ERR_PTR(-EINVAL);
6611da177e4SLinus Torvalds 		if (id < 1)
6621da177e4SLinus Torvalds 			goto error;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 		key = key_lookup(id);
665664cceb0SDavid Howells 		if (IS_ERR(key)) {
666e231c2eeSDavid Howells 			key_ref = ERR_CAST(key);
6671da177e4SLinus Torvalds 			goto error;
668664cceb0SDavid Howells 		}
669664cceb0SDavid Howells 
670664cceb0SDavid Howells 		key_ref = make_key_ref(key, 0);
671664cceb0SDavid Howells 
672664cceb0SDavid Howells 		/* check to see if we possess the key */
673*4bdf0bc3SDavid Howells 		ctx.index_key.type		= key->type;
674*4bdf0bc3SDavid Howells 		ctx.index_key.description	= key->description;
675*4bdf0bc3SDavid Howells 		ctx.index_key.desc_len		= strlen(key->description);
676*4bdf0bc3SDavid Howells 		ctx.match_data			= key;
677*4bdf0bc3SDavid Howells 		kdebug("check possessed");
678*4bdf0bc3SDavid Howells 		skey_ref = search_process_keyrings(&ctx);
679*4bdf0bc3SDavid Howells 		kdebug("possessed=%p", skey_ref);
680664cceb0SDavid Howells 
681664cceb0SDavid Howells 		if (!IS_ERR(skey_ref)) {
682664cceb0SDavid Howells 			key_put(key);
683664cceb0SDavid Howells 			key_ref = skey_ref;
684664cceb0SDavid Howells 		}
685664cceb0SDavid Howells 
6861da177e4SLinus Torvalds 		break;
6871da177e4SLinus Torvalds 	}
6881da177e4SLinus Torvalds 
6895593122eSDavid Howells 	/* unlink does not use the nominated key in any way, so can skip all
6905593122eSDavid Howells 	 * the permission checks as it is only concerned with the keyring */
6915593122eSDavid Howells 	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
6925593122eSDavid Howells 		ret = 0;
6935593122eSDavid Howells 		goto error;
6945593122eSDavid Howells 	}
6955593122eSDavid Howells 
6965593122eSDavid Howells 	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
69776181c13SDavid Howells 		ret = wait_for_key_construction(key, true);
69876181c13SDavid Howells 		switch (ret) {
69976181c13SDavid Howells 		case -ERESTARTSYS:
70076181c13SDavid Howells 			goto invalid_key;
70176181c13SDavid Howells 		default:
70276181c13SDavid Howells 			if (perm)
70376181c13SDavid Howells 				goto invalid_key;
70476181c13SDavid Howells 		case 0:
70576181c13SDavid Howells 			break;
70676181c13SDavid Howells 		}
70776181c13SDavid Howells 	} else if (perm) {
7081da177e4SLinus Torvalds 		ret = key_validate(key);
7091da177e4SLinus Torvalds 		if (ret < 0)
7101da177e4SLinus Torvalds 			goto invalid_key;
7111da177e4SLinus Torvalds 	}
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	ret = -EIO;
7145593122eSDavid Howells 	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
7155593122eSDavid Howells 	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
7161da177e4SLinus Torvalds 		goto invalid_key;
7171da177e4SLinus Torvalds 
7183e30148cSDavid Howells 	/* check the permissions */
719*4bdf0bc3SDavid Howells 	ret = key_task_permission(key_ref, ctx.cred, perm);
72029db9190SDavid Howells 	if (ret < 0)
7211da177e4SLinus Torvalds 		goto invalid_key;
7221da177e4SLinus Torvalds 
72331d5a79dSDavid Howells 	key->last_used_at = current_kernel_time().tv_sec;
72431d5a79dSDavid Howells 
7251da177e4SLinus Torvalds error:
726*4bdf0bc3SDavid Howells 	put_cred(ctx.cred);
727664cceb0SDavid Howells 	return key_ref;
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds invalid_key:
730664cceb0SDavid Howells 	key_ref_put(key_ref);
731664cceb0SDavid Howells 	key_ref = ERR_PTR(ret);
7321da177e4SLinus Torvalds 	goto error;
7331da177e4SLinus Torvalds 
734bb952bb9SDavid Howells 	/* if we attempted to install a keyring, then it may have caused new
735bb952bb9SDavid Howells 	 * creds to be installed */
736bb952bb9SDavid Howells reget_creds:
737*4bdf0bc3SDavid Howells 	put_cred(ctx.cred);
738bb952bb9SDavid Howells 	goto try_again;
739a8b17ed0SDavid Howells }
740bb952bb9SDavid Howells 
7411da177e4SLinus Torvalds /*
742973c9f4fSDavid Howells  * Join the named keyring as the session keyring if possible else attempt to
743973c9f4fSDavid Howells  * create a new one of that name and join that.
744973c9f4fSDavid Howells  *
745973c9f4fSDavid Howells  * If the name is NULL, an empty anonymous keyring will be installed as the
746973c9f4fSDavid Howells  * session keyring.
747973c9f4fSDavid Howells  *
748973c9f4fSDavid Howells  * Named session keyrings are joined with a semaphore held to prevent the
749973c9f4fSDavid Howells  * keyrings from going away whilst the attempt is made to going them and also
750973c9f4fSDavid Howells  * to prevent a race in creating compatible session keyrings.
7511da177e4SLinus Torvalds  */
7521da177e4SLinus Torvalds long join_session_keyring(const char *name)
7531da177e4SLinus Torvalds {
754d84f4f99SDavid Howells 	const struct cred *old;
755d84f4f99SDavid Howells 	struct cred *new;
7561da177e4SLinus Torvalds 	struct key *keyring;
757d84f4f99SDavid Howells 	long ret, serial;
758d84f4f99SDavid Howells 
759d84f4f99SDavid Howells 	new = prepare_creds();
760d84f4f99SDavid Howells 	if (!new)
761d84f4f99SDavid Howells 		return -ENOMEM;
762d84f4f99SDavid Howells 	old = current_cred();
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	/* if no name is provided, install an anonymous keyring */
7651da177e4SLinus Torvalds 	if (!name) {
766d84f4f99SDavid Howells 		ret = install_session_keyring_to_cred(new, NULL);
7671da177e4SLinus Torvalds 		if (ret < 0)
7681da177e4SLinus Torvalds 			goto error;
7691da177e4SLinus Torvalds 
7703a50597dSDavid Howells 		serial = new->session_keyring->serial;
771d84f4f99SDavid Howells 		ret = commit_creds(new);
772d84f4f99SDavid Howells 		if (ret == 0)
773d84f4f99SDavid Howells 			ret = serial;
774d84f4f99SDavid Howells 		goto okay;
7751da177e4SLinus Torvalds 	}
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds 	/* allow the user to join or create a named keyring */
778bb003079SIngo Molnar 	mutex_lock(&key_session_mutex);
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 	/* look for an existing keyring of this name */
78169664cf1SDavid Howells 	keyring = find_keyring_by_name(name, false);
7821da177e4SLinus Torvalds 	if (PTR_ERR(keyring) == -ENOKEY) {
7831da177e4SLinus Torvalds 		/* not found - try and create a new one */
78496b5c8feSDavid Howells 		keyring = keyring_alloc(
78596b5c8feSDavid Howells 			name, old->uid, old->gid, old,
78696b5c8feSDavid Howells 			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
7877e047ef5SDavid Howells 			KEY_ALLOC_IN_QUOTA, NULL);
7881da177e4SLinus Torvalds 		if (IS_ERR(keyring)) {
7891da177e4SLinus Torvalds 			ret = PTR_ERR(keyring);
790bcf945d3SDavid Howells 			goto error2;
7911da177e4SLinus Torvalds 		}
792d84f4f99SDavid Howells 	} else if (IS_ERR(keyring)) {
7931da177e4SLinus Torvalds 		ret = PTR_ERR(keyring);
7941da177e4SLinus Torvalds 		goto error2;
7953a50597dSDavid Howells 	} else if (keyring == new->session_keyring) {
7963a50597dSDavid Howells 		ret = 0;
7973a50597dSDavid Howells 		goto error2;
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 	/* we've got a keyring - now to install it */
801d84f4f99SDavid Howells 	ret = install_session_keyring_to_cred(new, keyring);
8021da177e4SLinus Torvalds 	if (ret < 0)
8031da177e4SLinus Torvalds 		goto error2;
8041da177e4SLinus Torvalds 
805d84f4f99SDavid Howells 	commit_creds(new);
806d84f4f99SDavid Howells 	mutex_unlock(&key_session_mutex);
807d84f4f99SDavid Howells 
8081da177e4SLinus Torvalds 	ret = keyring->serial;
8091da177e4SLinus Torvalds 	key_put(keyring);
810d84f4f99SDavid Howells okay:
811d84f4f99SDavid Howells 	return ret;
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds error2:
814bb003079SIngo Molnar 	mutex_unlock(&key_session_mutex);
8151da177e4SLinus Torvalds error:
816d84f4f99SDavid Howells 	abort_creds(new);
8171da177e4SLinus Torvalds 	return ret;
818d84f4f99SDavid Howells }
819ee18d64cSDavid Howells 
820ee18d64cSDavid Howells /*
821973c9f4fSDavid Howells  * Replace a process's session keyring on behalf of one of its children when
822973c9f4fSDavid Howells  * the target  process is about to resume userspace execution.
823ee18d64cSDavid Howells  */
82467d12145SAl Viro void key_change_session_keyring(struct callback_head *twork)
825ee18d64cSDavid Howells {
826413cd3d9SOleg Nesterov 	const struct cred *old = current_cred();
82767d12145SAl Viro 	struct cred *new = container_of(twork, struct cred, rcu);
828ee18d64cSDavid Howells 
829413cd3d9SOleg Nesterov 	if (unlikely(current->flags & PF_EXITING)) {
830413cd3d9SOleg Nesterov 		put_cred(new);
831ee18d64cSDavid Howells 		return;
832413cd3d9SOleg Nesterov 	}
833ee18d64cSDavid Howells 
834ee18d64cSDavid Howells 	new->  uid	= old->  uid;
835ee18d64cSDavid Howells 	new-> euid	= old-> euid;
836ee18d64cSDavid Howells 	new-> suid	= old-> suid;
837ee18d64cSDavid Howells 	new->fsuid	= old->fsuid;
838ee18d64cSDavid Howells 	new->  gid	= old->  gid;
839ee18d64cSDavid Howells 	new-> egid	= old-> egid;
840ee18d64cSDavid Howells 	new-> sgid	= old-> sgid;
841ee18d64cSDavid Howells 	new->fsgid	= old->fsgid;
842ee18d64cSDavid Howells 	new->user	= get_uid(old->user);
843ba0e3427SEric W. Biederman 	new->user_ns	= get_user_ns(old->user_ns);
844ee18d64cSDavid Howells 	new->group_info	= get_group_info(old->group_info);
845ee18d64cSDavid Howells 
846ee18d64cSDavid Howells 	new->securebits	= old->securebits;
847ee18d64cSDavid Howells 	new->cap_inheritable	= old->cap_inheritable;
848ee18d64cSDavid Howells 	new->cap_permitted	= old->cap_permitted;
849ee18d64cSDavid Howells 	new->cap_effective	= old->cap_effective;
850ee18d64cSDavid Howells 	new->cap_bset		= old->cap_bset;
851ee18d64cSDavid Howells 
852ee18d64cSDavid Howells 	new->jit_keyring	= old->jit_keyring;
853ee18d64cSDavid Howells 	new->thread_keyring	= key_get(old->thread_keyring);
8543a50597dSDavid Howells 	new->process_keyring	= key_get(old->process_keyring);
855ee18d64cSDavid Howells 
856ee18d64cSDavid Howells 	security_transfer_creds(new, old);
857ee18d64cSDavid Howells 
858ee18d64cSDavid Howells 	commit_creds(new);
859ee18d64cSDavid Howells }
860