process_keys.c 20.3 KB
Newer Older
1
/* Manage a process's keyrings
L
Linus Torvalds 已提交
2
 *
3
 * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/err.h>
I
Ingo Molnar 已提交
18
#include <linux/mutex.h>
19
#include <linux/security.h>
20
#include <linux/user_namespace.h>
L
Linus Torvalds 已提交
21 22 23
#include <asm/uaccess.h>
#include "internal.h"

24
/* Session keyring create vs join semaphore */
I
Ingo Molnar 已提交
25
static DEFINE_MUTEX(key_session_mutex);
L
Linus Torvalds 已提交
26

27
/* User keyring creation semaphore */
28 29
static DEFINE_MUTEX(key_user_keyring_mutex);

30
/* The root user's tracking struct */
L
Linus Torvalds 已提交
31 32
struct key_user root_key_user = {
	.usage		= ATOMIC_INIT(3),
33
	.cons_lock	= __MUTEX_INITIALIZER(root_key_user.cons_lock),
34
	.lock		= __SPIN_LOCK_UNLOCKED(root_key_user.lock),
L
Linus Torvalds 已提交
35 36 37
	.nkeys		= ATOMIC_INIT(2),
	.nikeys		= ATOMIC_INIT(2),
	.uid		= 0,
38
	.user_ns	= &init_user_ns,
L
Linus Torvalds 已提交
39 40 41
};

/*
42
 * Install the user and user session keyrings for the current process's UID.
L
Linus Torvalds 已提交
43
 */
44
int install_user_keyrings(void)
L
Linus Torvalds 已提交
45
{
D
David Howells 已提交
46 47
	struct user_struct *user;
	const struct cred *cred;
L
Linus Torvalds 已提交
48 49 50 51
	struct key *uid_keyring, *session_keyring;
	char buf[20];
	int ret;

D
David Howells 已提交
52 53 54
	cred = current_cred();
	user = cred->user;

55
	kenter("%p{%u}", user, user->uid);
L
Linus Torvalds 已提交
56

57 58 59
	if (user->uid_keyring) {
		kleave(" = 0 [exist]");
		return 0;
L
Linus Torvalds 已提交
60 61
	}

62 63
	mutex_lock(&key_user_keyring_mutex);
	ret = 0;
L
Linus Torvalds 已提交
64

65 66 67 68 69 70 71 72 73 74
	if (!user->uid_keyring) {
		/* get the UID-specific keyring
		 * - there may be one in existence already as it may have been
		 *   pinned by a session, but the user_struct pointing to it
		 *   may have been destroyed by setuid */
		sprintf(buf, "_uid.%u", user->uid);

		uid_keyring = find_keyring_by_name(buf, true);
		if (IS_ERR(uid_keyring)) {
			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
D
David Howells 已提交
75
						    cred, KEY_ALLOC_IN_QUOTA,
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
						    NULL);
			if (IS_ERR(uid_keyring)) {
				ret = PTR_ERR(uid_keyring);
				goto error;
			}
		}

		/* get a default session keyring (which might also exist
		 * already) */
		sprintf(buf, "_uid_ses.%u", user->uid);

		session_keyring = find_keyring_by_name(buf, true);
		if (IS_ERR(session_keyring)) {
			session_keyring =
				keyring_alloc(buf, user->uid, (gid_t) -1,
D
David Howells 已提交
91
					      cred, KEY_ALLOC_IN_QUOTA, NULL);
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
			if (IS_ERR(session_keyring)) {
				ret = PTR_ERR(session_keyring);
				goto error_release;
			}

			/* we install a link from the user session keyring to
			 * the user keyring */
			ret = key_link(session_keyring, uid_keyring);
			if (ret < 0)
				goto error_release_both;
		}

		/* install the keyrings */
		user->uid_keyring = uid_keyring;
		user->session_keyring = session_keyring;
L
Linus Torvalds 已提交
107 108
	}

109 110 111
	mutex_unlock(&key_user_keyring_mutex);
	kleave(" = 0");
	return 0;
L
Linus Torvalds 已提交
112

113 114 115 116
error_release_both:
	key_put(session_keyring);
error_release:
	key_put(uid_keyring);
117
error:
118 119
	mutex_unlock(&key_user_keyring_mutex);
	kleave(" = %d", ret);
L
Linus Torvalds 已提交
120
	return ret;
121
}
L
Linus Torvalds 已提交
122 123

/*
124 125
 * Install a fresh thread keyring directly to new credentials.  This keyring is
 * allowed to overrun the quota.
L
Linus Torvalds 已提交
126
 */
D
David Howells 已提交
127
int install_thread_keyring_to_cred(struct cred *new)
L
Linus Torvalds 已提交
128
{
D
David Howells 已提交
129
	struct key *keyring;
L
Linus Torvalds 已提交
130

D
David Howells 已提交
131 132 133 134
	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
				KEY_ALLOC_QUOTA_OVERRUN, NULL);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);
L
Linus Torvalds 已提交
135

D
David Howells 已提交
136 137 138
	new->thread_keyring = keyring;
	return 0;
}
L
Linus Torvalds 已提交
139 140

/*
141
 * Install a fresh thread keyring, discarding the old one.
L
Linus Torvalds 已提交
142
 */
D
David Howells 已提交
143
static int install_thread_keyring(void)
L
Linus Torvalds 已提交
144
{
D
David Howells 已提交
145
	struct cred *new;
L
Linus Torvalds 已提交
146 147
	int ret;

D
David Howells 已提交
148 149 150
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
151

D
David Howells 已提交
152 153 154 155 156 157
	BUG_ON(new->thread_keyring);

	ret = install_thread_keyring_to_cred(new);
	if (ret < 0) {
		abort_creds(new);
		return ret;
L
Linus Torvalds 已提交
158 159
	}

D
David Howells 已提交
160 161
	return commit_creds(new);
}
L
Linus Torvalds 已提交
162

D
David Howells 已提交
163
/*
164 165 166 167
 * Install a process keyring directly to a credentials struct.
 *
 * Returns -EEXIST if there was already a process keyring, 0 if one installed,
 * and other value on any other error
D
David Howells 已提交
168 169 170 171 172
 */
int install_process_keyring_to_cred(struct cred *new)
{
	struct key *keyring;
	int ret;
L
Linus Torvalds 已提交
173

D
David Howells 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	if (new->tgcred->process_keyring)
		return -EEXIST;

	keyring = keyring_alloc("_pid", new->uid, new->gid,
				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);

	spin_lock_irq(&new->tgcred->lock);
	if (!new->tgcred->process_keyring) {
		new->tgcred->process_keyring = keyring;
		keyring = NULL;
		ret = 0;
	} else {
		ret = -EEXIST;
	}
	spin_unlock_irq(&new->tgcred->lock);
	key_put(keyring);
L
Linus Torvalds 已提交
192
	return ret;
D
David Howells 已提交
193
}
L
Linus Torvalds 已提交
194 195

/*
196 197 198 199 200
 * Make sure a process keyring is installed for the current process.  The
 * existing process keyring is not replaced.
 *
 * Returns 0 if there is a process keyring by the end of this function, some
 * error otherwise.
L
Linus Torvalds 已提交
201
 */
D
David Howells 已提交
202
static int install_process_keyring(void)
L
Linus Torvalds 已提交
203
{
D
David Howells 已提交
204
	struct cred *new;
L
Linus Torvalds 已提交
205 206
	int ret;

D
David Howells 已提交
207 208 209
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
210

D
David Howells 已提交
211 212 213
	ret = install_process_keyring_to_cred(new);
	if (ret < 0) {
		abort_creds(new);
214
		return ret != -EEXIST ? ret : 0;
L
Linus Torvalds 已提交
215 216
	}

D
David Howells 已提交
217 218
	return commit_creds(new);
}
L
Linus Torvalds 已提交
219 220

/*
221
 * Install a session keyring directly to a credentials struct.
L
Linus Torvalds 已提交
222
 */
223
int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
L
Linus Torvalds 已提交
224
{
225
	unsigned long flags;
L
Linus Torvalds 已提交
226
	struct key *old;
227 228

	might_sleep();
L
Linus Torvalds 已提交
229 230 231

	/* create an empty session keyring */
	if (!keyring) {
232
		flags = KEY_ALLOC_QUOTA_OVERRUN;
D
David Howells 已提交
233
		if (cred->tgcred->session_keyring)
234 235
			flags = KEY_ALLOC_IN_QUOTA;

D
David Howells 已提交
236 237
		keyring = keyring_alloc("_ses", cred->uid, cred->gid,
					cred, flags, NULL);
238 239
		if (IS_ERR(keyring))
			return PTR_ERR(keyring);
D
David Howells 已提交
240
	} else {
L
Linus Torvalds 已提交
241 242 243 244
		atomic_inc(&keyring->usage);
	}

	/* install the keyring */
D
David Howells 已提交
245 246 247 248
	spin_lock_irq(&cred->tgcred->lock);
	old = cred->tgcred->session_keyring;
	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
	spin_unlock_irq(&cred->tgcred->lock);
L
Linus Torvalds 已提交
249

250 251 252 253 254 255
	/* we're using RCU on the pointer, but there's no point synchronising
	 * on it if it didn't previously point to anything */
	if (old) {
		synchronize_rcu();
		key_put(old);
	}
L
Linus Torvalds 已提交
256

257
	return 0;
D
David Howells 已提交
258
}
L
Linus Torvalds 已提交
259 260

/*
261 262
 * Install a session keyring, discarding the old one.  If a keyring is not
 * supplied, an empty one is invented.
L
Linus Torvalds 已提交
263
 */
D
David Howells 已提交
264
static int install_session_keyring(struct key *keyring)
L
Linus Torvalds 已提交
265
{
D
David Howells 已提交
266 267
	struct cred *new;
	int ret;
L
Linus Torvalds 已提交
268

D
David Howells 已提交
269 270 271
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
272

D
David Howells 已提交
273 274 275 276 277
	ret = install_session_keyring_to_cred(new, NULL);
	if (ret < 0) {
		abort_creds(new);
		return ret;
	}
L
Linus Torvalds 已提交
278

D
David Howells 已提交
279 280
	return commit_creds(new);
}
L
Linus Torvalds 已提交
281 282

/*
283
 * Handle the fsuid changing.
L
Linus Torvalds 已提交
284 285 286 287
 */
void key_fsuid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
288 289 290 291 292
	BUG_ON(!tsk->cred);
	if (tsk->cred->thread_keyring) {
		down_write(&tsk->cred->thread_keyring->sem);
		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
		up_write(&tsk->cred->thread_keyring->sem);
L
Linus Torvalds 已提交
293
	}
294
}
L
Linus Torvalds 已提交
295 296

/*
297
 * Handle the fsgid changing.
L
Linus Torvalds 已提交
298 299 300 301
 */
void key_fsgid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
302 303 304 305 306
	BUG_ON(!tsk->cred);
	if (tsk->cred->thread_keyring) {
		down_write(&tsk->cred->thread_keyring->sem);
		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
		up_write(&tsk->cred->thread_keyring->sem);
L
Linus Torvalds 已提交
307
	}
308
}
L
Linus Torvalds 已提交
309 310

/*
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
 * Search the process keyrings attached to the supplied cred for the first
 * matching key.
 *
 * The search criteria are the type and the match function.  The description is
 * given to the match function as a parameter, but doesn't otherwise influence
 * the search.  Typically the match function will compare the description
 * parameter to the key's description.
 *
 * This can only search keyrings that grant Search permission to the supplied
 * credentials.  Keyrings linked to searched keyrings will also be searched if
 * they grant Search permission too.  Keys can only be found if they grant
 * Search permission to the credentials.
 *
 * Returns a pointer to the key with the key usage count incremented if
 * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
 * matched negative keys.
 *
 * In the case of a successful return, the possession attribute is set on the
 * returned key reference.
L
Linus Torvalds 已提交
330
 */
331 332 333
key_ref_t search_my_process_keyrings(struct key_type *type,
				     const void *description,
				     key_match_func_t match,
D
David Howells 已提交
334
				     bool no_state_check,
335
				     const struct cred *cred)
L
Linus Torvalds 已提交
336
{
337
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
338 339 340 341 342 343 344 345

	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
	 * searchable, but we failed to find a key or we found a negative key;
	 * otherwise we want to return a sample error (probably -EACCES) if
	 * none of the keyrings were searchable
	 *
	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
	 */
346
	key_ref = NULL;
L
Linus Torvalds 已提交
347 348 349 350
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
351
	if (cred->thread_keyring) {
352
		key_ref = keyring_search_aux(
353
			make_key_ref(cred->thread_keyring, 1),
D
David Howells 已提交
354
			cred, type, description, match, no_state_check);
355
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
356 357
			goto found;

358
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
359 360 361 362
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
363
			ret = key_ref;
L
Linus Torvalds 已提交
364 365
			break;
		default:
366
			err = key_ref;
L
Linus Torvalds 已提交
367 368 369 370 371
			break;
		}
	}

	/* search the process keyring second */
372
	if (cred->tgcred->process_keyring) {
373
		key_ref = keyring_search_aux(
374
			make_key_ref(cred->tgcred->process_keyring, 1),
D
David Howells 已提交
375
			cred, type, description, match, no_state_check);
376
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
377 378
			goto found;

379
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
380 381 382 383
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
384
			ret = key_ref;
L
Linus Torvalds 已提交
385 386
			break;
		default:
387
			err = key_ref;
L
Linus Torvalds 已提交
388 389 390 391
			break;
		}
	}

392
	/* search the session keyring */
393
	if (cred->tgcred->session_keyring) {
394
		rcu_read_lock();
395 396
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
397
					     cred->tgcred->session_keyring),
398
				     1),
D
David Howells 已提交
399
			cred, type, description, match, no_state_check);
400
		rcu_read_unlock();
401

402
		if (!IS_ERR(key_ref))
403 404
			goto found;

405
		switch (PTR_ERR(key_ref)) {
406 407 408 409
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
410
			ret = key_ref;
411 412
			break;
		default:
413
			err = key_ref;
414 415
			break;
		}
416 417
	}
	/* or search the user-session keyring */
418
	else if (cred->user->session_keyring) {
419
		key_ref = keyring_search_aux(
420
			make_key_ref(cred->user->session_keyring, 1),
D
David Howells 已提交
421
			cred, type, description, match, no_state_check);
422
		if (!IS_ERR(key_ref))
423 424
			goto found;

425
		switch (PTR_ERR(key_ref)) {
426 427 428 429
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
430
			ret = key_ref;
431 432
			break;
		default:
433
			err = key_ref;
434 435
			break;
		}
436
	}
437

438 439 440 441 442 443 444 445
	/* no key - decide on the error we're going to go for */
	key_ref = ret ? ret : err;

found:
	return key_ref;
}

/*
446 447 448 449 450 451
 * Search the process keyrings attached to the supplied cred for the first
 * matching key in the manner of search_my_process_keyrings(), but also search
 * the keys attached to the assumed authorisation key using its credentials if
 * one is available.
 *
 * Return same as search_my_process_keyrings().
452 453 454 455 456 457 458 459 460 461 462
 */
key_ref_t search_process_keyrings(struct key_type *type,
				  const void *description,
				  key_match_func_t match,
				  const struct cred *cred)
{
	struct request_key_auth *rka;
	key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;

	might_sleep();

D
David Howells 已提交
463 464
	key_ref = search_my_process_keyrings(type, description, match,
					     false, cred);
465 466 467 468
	if (!IS_ERR(key_ref))
		goto found;
	err = key_ref;

469 470 471 472
	/* if this process has an instantiation authorisation key, then we also
	 * search the keyrings of the process mentioned there
	 * - we don't permit access to request_key auth keys via this method
	 */
473
	if (cred->request_key_auth &&
D
David Howells 已提交
474
	    cred == current_cred() &&
475
	    type != &key_type_request_key_auth
476
	    ) {
477
		/* defend against the auth key being revoked */
478
		down_read(&cred->request_key_auth->sem);
479

480 481
		if (key_validate(cred->request_key_auth) == 0) {
			rka = cred->request_key_auth->payload.data;
482

483
			key_ref = search_process_keyrings(type, description,
D
David Howells 已提交
484
							  match, rka->cred);
L
Linus Torvalds 已提交
485

486
			up_read(&cred->request_key_auth->sem);
487 488 489 490

			if (!IS_ERR(key_ref))
				goto found;

491
			ret = key_ref;
492
		} else {
493
			up_read(&cred->request_key_auth->sem);
494
		}
L
Linus Torvalds 已提交
495 496 497
	}

	/* no key - decide on the error we're going to go for */
498 499 500 501 502 503
	if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
		key_ref = ERR_PTR(-ENOKEY);
	else if (err == ERR_PTR(-EACCES))
		key_ref = ret;
	else
		key_ref = err;
L
Linus Torvalds 已提交
504

505
found:
506
	return key_ref;
507
}
L
Linus Torvalds 已提交
508

509
/*
510
 * See if the key we're looking at is the target key.
511
 */
512
int lookup_user_key_possessed(const struct key *key, const void *target)
513 514
{
	return key == target;
515
}
516

L
Linus Torvalds 已提交
517
/*
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
 * Look up a key ID given us by userspace with a given permissions mask to get
 * the key it refers to.
 *
 * Flags can be passed to request that special keyrings be created if referred
 * to directly, to permit partially constructed keys to be found and to skip
 * validity and permission checks on the found key.
 *
 * Returns a pointer to the key with an incremented usage count if successful;
 * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
 * to a key or the best found key was a negative key; -EKEYREVOKED or
 * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
 * found key doesn't grant the requested permit or the LSM denied access to it;
 * or -ENOMEM if a special keyring couldn't be created.
 *
 * In the case of a successful return, the possession attribute is set on the
 * returned key reference.
L
Linus Torvalds 已提交
534
 */
535
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
536
			  key_perm_t perm)
L
Linus Torvalds 已提交
537
{
538
	struct request_key_auth *rka;
D
David Howells 已提交
539
	const struct cred *cred;
L
Linus Torvalds 已提交
540
	struct key *key;
541
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
542 543
	int ret;

544 545
try_again:
	cred = get_current_cred();
546
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
547 548 549

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
550
		if (!cred->thread_keyring) {
551
			if (!(lflags & KEY_LOOKUP_CREATE))
L
Linus Torvalds 已提交
552 553
				goto error;

554
			ret = install_thread_keyring();
L
Linus Torvalds 已提交
555
			if (ret < 0) {
556
				key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
557 558
				goto error;
			}
559
			goto reget_creds;
L
Linus Torvalds 已提交
560 561
		}

562
		key = cred->thread_keyring;
L
Linus Torvalds 已提交
563
		atomic_inc(&key->usage);
564
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
565 566 567
		break;

	case KEY_SPEC_PROCESS_KEYRING:
568
		if (!cred->tgcred->process_keyring) {
569
			if (!(lflags & KEY_LOOKUP_CREATE))
L
Linus Torvalds 已提交
570 571
				goto error;

572
			ret = install_process_keyring();
L
Linus Torvalds 已提交
573
			if (ret < 0) {
574
				key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
575 576
				goto error;
			}
577
			goto reget_creds;
L
Linus Torvalds 已提交
578 579
		}

580
		key = cred->tgcred->process_keyring;
L
Linus Torvalds 已提交
581
		atomic_inc(&key->usage);
582
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
583 584 585
		break;

	case KEY_SPEC_SESSION_KEYRING:
586
		if (!cred->tgcred->session_keyring) {
L
Linus Torvalds 已提交
587 588
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
589
			ret = install_user_keyrings();
590 591
			if (ret < 0)
				goto error;
592 593
			ret = install_session_keyring(
				cred->user->session_keyring);
D
David Howells 已提交
594

L
Linus Torvalds 已提交
595 596
			if (ret < 0)
				goto error;
597
			goto reget_creds;
L
Linus Torvalds 已提交
598 599
		}

600
		rcu_read_lock();
601
		key = rcu_dereference(cred->tgcred->session_keyring);
L
Linus Torvalds 已提交
602
		atomic_inc(&key->usage);
603
		rcu_read_unlock();
604
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
605 606 607
		break;

	case KEY_SPEC_USER_KEYRING:
608
		if (!cred->user->uid_keyring) {
609
			ret = install_user_keyrings();
610 611 612 613
			if (ret < 0)
				goto error;
		}

614
		key = cred->user->uid_keyring;
L
Linus Torvalds 已提交
615
		atomic_inc(&key->usage);
616
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
617 618 619
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
620
		if (!cred->user->session_keyring) {
621
			ret = install_user_keyrings();
622 623 624 625
			if (ret < 0)
				goto error;
		}

626
		key = cred->user->session_keyring;
L
Linus Torvalds 已提交
627
		atomic_inc(&key->usage);
628
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
629 630 631 632
		break;

	case KEY_SPEC_GROUP_KEYRING:
		/* group keyrings are not yet supported */
633
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
634 635
		goto error;

636
	case KEY_SPEC_REQKEY_AUTH_KEY:
637
		key = cred->request_key_auth;
638 639 640 641 642 643 644
		if (!key)
			goto error;

		atomic_inc(&key->usage);
		key_ref = make_key_ref(key, 1);
		break;

645
	case KEY_SPEC_REQUESTOR_KEYRING:
646
		if (!cred->request_key_auth)
647 648
			goto error;

649 650
		down_read(&cred->request_key_auth->sem);
		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
651 652 653
			key_ref = ERR_PTR(-EKEYREVOKED);
			key = NULL;
		} else {
654
			rka = cred->request_key_auth->payload.data;
655 656 657
			key = rka->dest_keyring;
			atomic_inc(&key->usage);
		}
658
		up_read(&cred->request_key_auth->sem);
659 660 661 662 663
		if (!key)
			goto error;
		key_ref = make_key_ref(key, 1);
		break;

L
Linus Torvalds 已提交
664
	default:
665
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
666 667 668 669
		if (id < 1)
			goto error;

		key = key_lookup(id);
670
		if (IS_ERR(key)) {
671
			key_ref = ERR_CAST(key);
L
Linus Torvalds 已提交
672
			goto error;
673 674 675 676 677 678 679
		}

		key_ref = make_key_ref(key, 0);

		/* check to see if we possess the key */
		skey_ref = search_process_keyrings(key->type, key,
						   lookup_user_key_possessed,
D
David Howells 已提交
680
						   cred);
681 682 683 684 685 686

		if (!IS_ERR(skey_ref)) {
			key_put(key);
			key_ref = skey_ref;
		}

L
Linus Torvalds 已提交
687 688 689
		break;
	}

690 691 692 693 694 695 696 697
	/* unlink does not use the nominated key in any way, so can skip all
	 * the permission checks as it is only concerned with the keyring */
	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
		ret = 0;
		goto error;
	}

	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
698 699 700 701 702 703 704 705 706 707 708
		ret = wait_for_key_construction(key, true);
		switch (ret) {
		case -ERESTARTSYS:
			goto invalid_key;
		default:
			if (perm)
				goto invalid_key;
		case 0:
			break;
		}
	} else if (perm) {
L
Linus Torvalds 已提交
709 710 711 712 713 714
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

	ret = -EIO;
715 716
	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
L
Linus Torvalds 已提交
717 718
		goto invalid_key;

719
	/* check the permissions */
D
David Howells 已提交
720
	ret = key_task_permission(key_ref, cred, perm);
721
	if (ret < 0)
L
Linus Torvalds 已提交
722 723
		goto invalid_key;

724
error:
725
	put_cred(cred);
726
	return key_ref;
L
Linus Torvalds 已提交
727

728 729 730
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
731 732
	goto error;

733 734 735 736 737
	/* if we attempted to install a keyring, then it may have caused new
	 * creds to be installed */
reget_creds:
	put_cred(cred);
	goto try_again;
738
}
739

L
Linus Torvalds 已提交
740
/*
741 742 743 744 745 746 747 748 749
 * Join the named keyring as the session keyring if possible else attempt to
 * create a new one of that name and join that.
 *
 * If the name is NULL, an empty anonymous keyring will be installed as the
 * session keyring.
 *
 * Named session keyrings are joined with a semaphore held to prevent the
 * keyrings from going away whilst the attempt is made to going them and also
 * to prevent a race in creating compatible session keyrings.
L
Linus Torvalds 已提交
750 751 752
 */
long join_session_keyring(const char *name)
{
D
David Howells 已提交
753 754
	const struct cred *old;
	struct cred *new;
L
Linus Torvalds 已提交
755
	struct key *keyring;
D
David Howells 已提交
756 757 758 759 760
	long ret, serial;

	/* only permit this if there's a single thread in the thread group -
	 * this avoids us having to adjust the creds on all threads and risking
	 * ENOMEM */
761
	if (!current_is_single_threaded())
D
David Howells 已提交
762 763 764 765 766 767
		return -EMLINK;

	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();
L
Linus Torvalds 已提交
768 769 770

	/* if no name is provided, install an anonymous keyring */
	if (!name) {
D
David Howells 已提交
771
		ret = install_session_keyring_to_cred(new, NULL);
L
Linus Torvalds 已提交
772 773 774
		if (ret < 0)
			goto error;

D
David Howells 已提交
775 776 777 778 779
		serial = new->tgcred->session_keyring->serial;
		ret = commit_creds(new);
		if (ret == 0)
			ret = serial;
		goto okay;
L
Linus Torvalds 已提交
780 781 782
	}

	/* allow the user to join or create a named keyring */
I
Ingo Molnar 已提交
783
	mutex_lock(&key_session_mutex);
L
Linus Torvalds 已提交
784 785

	/* look for an existing keyring of this name */
786
	keyring = find_keyring_by_name(name, false);
L
Linus Torvalds 已提交
787 788
	if (PTR_ERR(keyring) == -ENOKEY) {
		/* not found - try and create a new one */
D
David Howells 已提交
789
		keyring = keyring_alloc(name, old->uid, old->gid, old,
790
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
791 792
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
793
			goto error2;
L
Linus Torvalds 已提交
794
		}
D
David Howells 已提交
795
	} else if (IS_ERR(keyring)) {
L
Linus Torvalds 已提交
796 797 798 799 800
		ret = PTR_ERR(keyring);
		goto error2;
	}

	/* we've got a keyring - now to install it */
D
David Howells 已提交
801
	ret = install_session_keyring_to_cred(new, keyring);
L
Linus Torvalds 已提交
802 803 804
	if (ret < 0)
		goto error2;

D
David Howells 已提交
805 806 807
	commit_creds(new);
	mutex_unlock(&key_session_mutex);

L
Linus Torvalds 已提交
808 809
	ret = keyring->serial;
	key_put(keyring);
D
David Howells 已提交
810 811
okay:
	return ret;
L
Linus Torvalds 已提交
812

813
error2:
I
Ingo Molnar 已提交
814
	mutex_unlock(&key_session_mutex);
815
error:
D
David Howells 已提交
816
	abort_creds(new);
L
Linus Torvalds 已提交
817
	return ret;
D
David Howells 已提交
818
}
819 820

/*
821 822
 * Replace a process's session keyring on behalf of one of its children when
 * the target  process is about to resume userspace execution.
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
 */
void key_replace_session_keyring(void)
{
	const struct cred *old;
	struct cred *new;

	if (!current->replacement_session_keyring)
		return;

	write_lock_irq(&tasklist_lock);
	new = current->replacement_session_keyring;
	current->replacement_session_keyring = NULL;
	write_unlock_irq(&tasklist_lock);

	if (!new)
		return;

	old = current_cred();
	new->  uid	= old->  uid;
	new-> euid	= old-> euid;
	new-> suid	= old-> suid;
	new->fsuid	= old->fsuid;
	new->  gid	= old->  gid;
	new-> egid	= old-> egid;
	new-> sgid	= old-> sgid;
	new->fsgid	= old->fsgid;
	new->user	= get_uid(old->user);
850
	new->user_ns	= new->user->user_ns;
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
	new->group_info	= get_group_info(old->group_info);

	new->securebits	= old->securebits;
	new->cap_inheritable	= old->cap_inheritable;
	new->cap_permitted	= old->cap_permitted;
	new->cap_effective	= old->cap_effective;
	new->cap_bset		= old->cap_bset;

	new->jit_keyring	= old->jit_keyring;
	new->thread_keyring	= key_get(old->thread_keyring);
	new->tgcred->tgid	= old->tgcred->tgid;
	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);

	security_transfer_creds(new, old);

	commit_creds(new);
}