process_keys.c 18.5 KB
Newer Older
1
/* Management of 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 24
#include <asm/uaccess.h>
#include "internal.h"

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

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

L
Linus Torvalds 已提交
30 31 32
/* the root user's tracking struct */
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
};

/*****************************************************************************/
/*
43
 * install user and user session keyrings for a particular UID
L
Linus Torvalds 已提交
44
 */
45
int install_user_keyrings(void)
L
Linus Torvalds 已提交
46
{
D
David Howells 已提交
47 48
	struct user_struct *user;
	const struct cred *cred;
L
Linus Torvalds 已提交
49 50 51 52
	struct key *uid_keyring, *session_keyring;
	char buf[20];
	int ret;

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

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

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

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

66 67 68 69 70 71 72 73 74 75
	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 已提交
76
						    cred, KEY_ALLOC_IN_QUOTA,
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
						    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 已提交
92
					      cred, KEY_ALLOC_IN_QUOTA, NULL);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
			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 已提交
108 109
	}

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

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

/*
D
David Howells 已提交
125
 * install a fresh thread keyring directly to new credentials
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 142

/*
 * install a fresh thread keyring, discarding the old one
 */
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 168 169 170 171
/*
 * install a process keyring directly to a credentials struct
 * - returns -EEXIST if there was already a process keyring, 0 if one installed,
 *   and other -ve on any other error
 */
int install_process_keyring_to_cred(struct cred *new)
{
	struct key *keyring;
	int ret;
L
Linus Torvalds 已提交
172

D
David Howells 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	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 已提交
191
	return ret;
D
David Howells 已提交
192
}
L
Linus Torvalds 已提交
193 194 195

/*
 * make sure a process keyring is installed
D
David Howells 已提交
196
 * - we
L
Linus Torvalds 已提交
197
 */
D
David Howells 已提交
198
static int install_process_keyring(void)
L
Linus Torvalds 已提交
199
{
D
David Howells 已提交
200
	struct cred *new;
L
Linus Torvalds 已提交
201 202
	int ret;

D
David Howells 已提交
203 204 205
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
206

D
David Howells 已提交
207 208 209 210
	ret = install_process_keyring_to_cred(new);
	if (ret < 0) {
		abort_creds(new);
		return ret != -EEXIST ?: 0;
L
Linus Torvalds 已提交
211 212
	}

D
David Howells 已提交
213 214
	return commit_creds(new);
}
L
Linus Torvalds 已提交
215 216

/*
D
David Howells 已提交
217
 * install a session keyring directly to a credentials struct
L
Linus Torvalds 已提交
218
 */
D
David Howells 已提交
219 220
static int install_session_keyring_to_cred(struct cred *cred,
					   struct key *keyring)
L
Linus Torvalds 已提交
221
{
222
	unsigned long flags;
L
Linus Torvalds 已提交
223
	struct key *old;
224 225

	might_sleep();
L
Linus Torvalds 已提交
226 227 228

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

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

	/* install the keyring */
D
David Howells 已提交
242 243 244 245
	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 已提交
246

247 248 249 250 251 252
	/* 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 已提交
253

254
	return 0;
D
David Howells 已提交
255
}
L
Linus Torvalds 已提交
256 257

/*
D
David Howells 已提交
258 259
 * install a session keyring, discarding the old one
 * - if a keyring is not supplied, an empty one is invented
L
Linus Torvalds 已提交
260
 */
D
David Howells 已提交
261
static int install_session_keyring(struct key *keyring)
L
Linus Torvalds 已提交
262
{
D
David Howells 已提交
263 264
	struct cred *new;
	int ret;
L
Linus Torvalds 已提交
265

D
David Howells 已提交
266 267 268
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
269

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

D
David Howells 已提交
276 277
	return commit_creds(new);
}
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285

/*****************************************************************************/
/*
 * the filesystem user ID changed
 */
void key_fsuid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
286 287 288 289 290
	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 已提交
291 292 293 294 295 296 297 298 299 300 301
	}

} /* end key_fsuid_changed() */

/*****************************************************************************/
/*
 * the filesystem group ID changed
 */
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 309 310 311 312 313 314 315 316 317 318
	}

} /* end key_fsgid_changed() */

/*****************************************************************************/
/*
 * search the process keyrings for the first matching key
 * - we use the supplied match function to see if the description (or other
 *   feature of interest) matches
 * - we return -EAGAIN if we didn't find any matching key
 * - we return -ENOKEY if we found only negative matching keys
 */
319 320 321
key_ref_t search_process_keyrings(struct key_type *type,
				  const void *description,
				  key_match_func_t match,
D
David Howells 已提交
322
				  const struct cred *cred)
L
Linus Torvalds 已提交
323
{
324
	struct request_key_auth *rka;
325
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
326

327 328
	might_sleep();

L
Linus Torvalds 已提交
329 330 331 332 333 334 335
	/* 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
	 */
336
	key_ref = NULL;
L
Linus Torvalds 已提交
337 338 339 340
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
341
	if (cred->thread_keyring) {
342
		key_ref = keyring_search_aux(
343
			make_key_ref(cred->thread_keyring, 1),
D
David Howells 已提交
344
			cred, type, description, match);
345
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
346 347
			goto found;

348
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
349 350 351 352
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
353
			ret = key_ref;
L
Linus Torvalds 已提交
354 355
			break;
		default:
356
			err = key_ref;
L
Linus Torvalds 已提交
357 358 359 360 361
			break;
		}
	}

	/* search the process keyring second */
362
	if (cred->tgcred->process_keyring) {
363
		key_ref = keyring_search_aux(
364
			make_key_ref(cred->tgcred->process_keyring, 1),
D
David Howells 已提交
365
			cred, type, description, match);
366
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
367 368
			goto found;

369
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
370 371 372 373
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
374
			ret = key_ref;
L
Linus Torvalds 已提交
375 376
			break;
		default:
377
			err = key_ref;
L
Linus Torvalds 已提交
378 379 380 381
			break;
		}
	}

382
	/* search the session keyring */
383
	if (cred->tgcred->session_keyring) {
384
		rcu_read_lock();
385 386
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
387
					     cred->tgcred->session_keyring),
388
				     1),
D
David Howells 已提交
389
			cred, type, description, match);
390
		rcu_read_unlock();
391

392
		if (!IS_ERR(key_ref))
393 394
			goto found;

395
		switch (PTR_ERR(key_ref)) {
396 397 398 399
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
400
			ret = key_ref;
401 402
			break;
		default:
403
			err = key_ref;
404 405
			break;
		}
406 407
	}
	/* or search the user-session keyring */
408
	else if (cred->user->session_keyring) {
409
		key_ref = keyring_search_aux(
410
			make_key_ref(cred->user->session_keyring, 1),
D
David Howells 已提交
411
			cred, type, description, match);
412
		if (!IS_ERR(key_ref))
413 414
			goto found;

415
		switch (PTR_ERR(key_ref)) {
416 417 418 419
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
420
			ret = key_ref;
421 422
			break;
		default:
423
			err = key_ref;
424 425
			break;
		}
426
	}
427 428 429 430 431

	/* 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
	 */
432
	if (cred->request_key_auth &&
D
David Howells 已提交
433
	    cred == current_cred() &&
434
	    type != &key_type_request_key_auth
435
	    ) {
436
		/* defend against the auth key being revoked */
437
		down_read(&cred->request_key_auth->sem);
438

439 440
		if (key_validate(cred->request_key_auth) == 0) {
			rka = cred->request_key_auth->payload.data;
441

442
			key_ref = search_process_keyrings(type, description,
D
David Howells 已提交
443
							  match, rka->cred);
L
Linus Torvalds 已提交
444

445
			up_read(&cred->request_key_auth->sem);
446 447 448 449 450 451 452 453 454 455

			if (!IS_ERR(key_ref))
				goto found;

			switch (PTR_ERR(key_ref)) {
			case -EAGAIN: /* no key */
				if (ret)
					break;
			case -ENOKEY: /* negative key */
				ret = key_ref;
456
				break;
457 458 459 460 461
			default:
				err = key_ref;
				break;
			}
		} else {
462
			up_read(&cred->request_key_auth->sem);
463
		}
L
Linus Torvalds 已提交
464 465 466
	}

	/* no key - decide on the error we're going to go for */
467
	key_ref = ret ? ret : err;
L
Linus Torvalds 已提交
468

469
found:
470
	return key_ref;
L
Linus Torvalds 已提交
471 472 473

} /* end search_process_keyrings() */

474 475 476 477 478 479 480 481 482 483
/*****************************************************************************/
/*
 * see if the key we're looking at is the target key
 */
static int lookup_user_key_possessed(const struct key *key, const void *target)
{
	return key == target;

} /* end lookup_user_key_possessed() */

L
Linus Torvalds 已提交
484 485 486 487 488 489
/*****************************************************************************/
/*
 * lookup a key given a key ID from userspace with a given permissions mask
 * - don't create special keyrings unless so requested
 * - partially constructed keys aren't found unless requested
 */
490
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
491
			  key_perm_t perm)
L
Linus Torvalds 已提交
492
{
493
	struct request_key_auth *rka;
D
David Howells 已提交
494
	const struct cred *cred;
L
Linus Torvalds 已提交
495
	struct key *key;
496
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
497 498
	int ret;

499 500
try_again:
	cred = get_current_cred();
501
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
502 503 504

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
505
		if (!cred->thread_keyring) {
506
			if (!(lflags & KEY_LOOKUP_CREATE))
L
Linus Torvalds 已提交
507 508
				goto error;

509
			ret = install_thread_keyring();
L
Linus Torvalds 已提交
510 511 512 513
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
514
			goto reget_creds;
L
Linus Torvalds 已提交
515 516
		}

517
		key = cred->thread_keyring;
L
Linus Torvalds 已提交
518
		atomic_inc(&key->usage);
519
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
520 521 522
		break;

	case KEY_SPEC_PROCESS_KEYRING:
523
		if (!cred->tgcred->process_keyring) {
524
			if (!(lflags & KEY_LOOKUP_CREATE))
L
Linus Torvalds 已提交
525 526
				goto error;

527
			ret = install_process_keyring();
L
Linus Torvalds 已提交
528 529 530 531
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
532
			goto reget_creds;
L
Linus Torvalds 已提交
533 534
		}

535
		key = cred->tgcred->process_keyring;
L
Linus Torvalds 已提交
536
		atomic_inc(&key->usage);
537
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
538 539 540
		break;

	case KEY_SPEC_SESSION_KEYRING:
541
		if (!cred->tgcred->session_keyring) {
L
Linus Torvalds 已提交
542 543
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
544
			ret = install_user_keyrings();
545 546
			if (ret < 0)
				goto error;
547 548
			ret = install_session_keyring(
				cred->user->session_keyring);
D
David Howells 已提交
549

L
Linus Torvalds 已提交
550 551
			if (ret < 0)
				goto error;
552
			goto reget_creds;
L
Linus Torvalds 已提交
553 554
		}

555
		rcu_read_lock();
556
		key = rcu_dereference(cred->tgcred->session_keyring);
L
Linus Torvalds 已提交
557
		atomic_inc(&key->usage);
558
		rcu_read_unlock();
559
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
560 561 562
		break;

	case KEY_SPEC_USER_KEYRING:
563
		if (!cred->user->uid_keyring) {
564
			ret = install_user_keyrings();
565 566 567 568
			if (ret < 0)
				goto error;
		}

569
		key = cred->user->uid_keyring;
L
Linus Torvalds 已提交
570
		atomic_inc(&key->usage);
571
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
572 573 574
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
575
		if (!cred->user->session_keyring) {
576
			ret = install_user_keyrings();
577 578 579 580
			if (ret < 0)
				goto error;
		}

581
		key = cred->user->session_keyring;
L
Linus Torvalds 已提交
582
		atomic_inc(&key->usage);
583
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
584 585 586 587 588 589 590
		break;

	case KEY_SPEC_GROUP_KEYRING:
		/* group keyrings are not yet supported */
		key = ERR_PTR(-EINVAL);
		goto error;

591
	case KEY_SPEC_REQKEY_AUTH_KEY:
592
		key = cred->request_key_auth;
593 594 595 596 597 598 599
		if (!key)
			goto error;

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

600
	case KEY_SPEC_REQUESTOR_KEYRING:
601
		if (!cred->request_key_auth)
602 603
			goto error;

604 605
		down_read(&cred->request_key_auth->sem);
		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
606 607 608
			key_ref = ERR_PTR(-EKEYREVOKED);
			key = NULL;
		} else {
609
			rka = cred->request_key_auth->payload.data;
610 611 612
			key = rka->dest_keyring;
			atomic_inc(&key->usage);
		}
613
		up_read(&cred->request_key_auth->sem);
614 615 616 617 618
		if (!key)
			goto error;
		key_ref = make_key_ref(key, 1);
		break;

L
Linus Torvalds 已提交
619
	default:
620
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
621 622 623 624
		if (id < 1)
			goto error;

		key = key_lookup(id);
625
		if (IS_ERR(key)) {
626
			key_ref = ERR_CAST(key);
L
Linus Torvalds 已提交
627
			goto error;
628 629 630 631 632 633 634
		}

		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 已提交
635
						   cred);
636 637 638 639 640 641

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

L
Linus Torvalds 已提交
642 643 644
		break;
	}

645 646 647 648 649 650 651 652
	/* 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)) {
653 654 655 656 657 658 659 660 661 662 663
		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 已提交
664 665 666 667 668 669
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

	ret = -EIO;
670 671
	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
L
Linus Torvalds 已提交
672 673
		goto invalid_key;

674
	/* check the permissions */
D
David Howells 已提交
675
	ret = key_task_permission(key_ref, cred, perm);
676
	if (ret < 0)
L
Linus Torvalds 已提交
677 678
		goto invalid_key;

679
error:
680
	put_cred(cred);
681
	return key_ref;
L
Linus Torvalds 已提交
682

683 684 685
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
686 687
	goto error;

688 689 690 691 692 693
	/* 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;

L
Linus Torvalds 已提交
694 695 696 697 698 699 700 701 702 703 704
} /* end lookup_user_key() */

/*****************************************************************************/
/*
 * join the named keyring as the session keyring if possible, or attempt to
 * create a new one of that name if not
 * - if the name is NULL, an empty anonymous keyring is installed instead
 * - named session keyring joining is done with a semaphore held
 */
long join_session_keyring(const char *name)
{
D
David Howells 已提交
705 706
	const struct cred *old;
	struct cred *new;
L
Linus Torvalds 已提交
707
	struct key *keyring;
D
David Howells 已提交
708 709 710 711 712
	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 */
713
	if (!current_is_single_threaded())
D
David Howells 已提交
714 715 716 717 718 719
		return -EMLINK;

	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();
L
Linus Torvalds 已提交
720 721 722

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

D
David Howells 已提交
727 728 729 730 731
		serial = new->tgcred->session_keyring->serial;
		ret = commit_creds(new);
		if (ret == 0)
			ret = serial;
		goto okay;
L
Linus Torvalds 已提交
732 733 734
	}

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

	/* look for an existing keyring of this name */
738
	keyring = find_keyring_by_name(name, false);
L
Linus Torvalds 已提交
739 740
	if (PTR_ERR(keyring) == -ENOKEY) {
		/* not found - try and create a new one */
D
David Howells 已提交
741
		keyring = keyring_alloc(name, old->uid, old->gid, old,
742
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
743 744
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
745
			goto error2;
L
Linus Torvalds 已提交
746
		}
D
David Howells 已提交
747
	} else if (IS_ERR(keyring)) {
L
Linus Torvalds 已提交
748 749 750 751 752
		ret = PTR_ERR(keyring);
		goto error2;
	}

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

D
David Howells 已提交
757 758 759
	commit_creds(new);
	mutex_unlock(&key_session_mutex);

L
Linus Torvalds 已提交
760 761
	ret = keyring->serial;
	key_put(keyring);
D
David Howells 已提交
762 763
okay:
	return ret;
L
Linus Torvalds 已提交
764

765
error2:
I
Ingo Molnar 已提交
766
	mutex_unlock(&key_session_mutex);
767
error:
D
David Howells 已提交
768
	abort_creds(new);
L
Linus Torvalds 已提交
769
	return ret;
D
David Howells 已提交
770
}
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818

/*
 * Replace a process's session keyring when that process resumes userspace on
 * behalf of one of its children
 */
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);
	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);
}