process_keys.c 18.6 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 18
 * 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/slab.h>
#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/err.h>
I
Ingo Molnar 已提交
19
#include <linux/mutex.h>
L
Linus Torvalds 已提交
20 21 22 23
#include <asm/uaccess.h>
#include "internal.h"

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

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

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

/*****************************************************************************/
/*
41
 * install user and user session keyrings for a particular UID
L
Linus Torvalds 已提交
42
 */
43
int install_user_keyrings(void)
L
Linus Torvalds 已提交
44
{
45
	struct user_struct *user = current->cred->user;
L
Linus Torvalds 已提交
46 47 48 49
	struct key *uid_keyring, *session_keyring;
	char buf[20];
	int ret;

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

52 53 54
	if (user->uid_keyring) {
		kleave(" = 0 [exist]");
		return 0;
L
Linus Torvalds 已提交
55 56
	}

57 58
	mutex_lock(&key_user_keyring_mutex);
	ret = 0;
L
Linus Torvalds 已提交
59

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

105 106 107
	mutex_unlock(&key_user_keyring_mutex);
	kleave(" = 0");
	return 0;
L
Linus Torvalds 已提交
108

109 110 111 112
error_release_both:
	key_put(session_keyring);
error_release:
	key_put(uid_keyring);
113
error:
114 115
	mutex_unlock(&key_user_keyring_mutex);
	kleave(" = %d", ret);
L
Linus Torvalds 已提交
116
	return ret;
117
}
L
Linus Torvalds 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

/*****************************************************************************/
/*
 * deal with the UID changing
 */
void switch_uid_keyring(struct user_struct *new_user)
{
#if 0 /* do nothing for now */
	struct key *old;

	/* switch to the new user's session keyring if we were running under
	 * root's default session keyring */
	if (new_user->uid != 0 &&
	    current->session_keyring == &root_session_keyring
	    ) {
		atomic_inc(&new_user->session_keyring->usage);

		task_lock(current);
		old = current->session_keyring;
		current->session_keyring = new_user->session_keyring;
		task_unlock(current);

		key_put(old);
	}
#endif

} /* end switch_uid_keyring() */

/*****************************************************************************/
/*
 * install a fresh thread keyring, discarding the old one
 */
150
int install_thread_keyring(void)
L
Linus Torvalds 已提交
151
{
152
	struct task_struct *tsk = current;
L
Linus Torvalds 已提交
153 154 155 156 157 158
	struct key *keyring, *old;
	char buf[20];
	int ret;

	sprintf(buf, "_tid.%u", tsk->pid);

159
	keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
160
				KEY_ALLOC_QUOTA_OVERRUN, NULL);
L
Linus Torvalds 已提交
161 162 163 164 165 166
	if (IS_ERR(keyring)) {
		ret = PTR_ERR(keyring);
		goto error;
	}

	task_lock(tsk);
167 168
	old = tsk->cred->thread_keyring;
	tsk->cred->thread_keyring = keyring;
L
Linus Torvalds 已提交
169 170 171 172 173
	task_unlock(tsk);

	ret = 0;

	key_put(old);
174
error:
L
Linus Torvalds 已提交
175 176 177 178 179 180 181 182
	return ret;

} /* end install_thread_keyring() */

/*****************************************************************************/
/*
 * make sure a process keyring is installed
 */
183
int install_process_keyring(void)
L
Linus Torvalds 已提交
184
{
185
	struct task_struct *tsk = current;
L
Linus Torvalds 已提交
186 187 188 189
	struct key *keyring;
	char buf[20];
	int ret;

190 191
	might_sleep();

192
	if (!tsk->cred->tgcred->process_keyring) {
L
Linus Torvalds 已提交
193 194
		sprintf(buf, "_pid.%u", tsk->tgid);

195
		keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
196
					KEY_ALLOC_QUOTA_OVERRUN, NULL);
L
Linus Torvalds 已提交
197 198 199 200 201
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
			goto error;
		}

202
		/* attach keyring */
203 204 205
		spin_lock_irq(&tsk->cred->tgcred->lock);
		if (!tsk->cred->tgcred->process_keyring) {
			tsk->cred->tgcred->process_keyring = keyring;
L
Linus Torvalds 已提交
206 207
			keyring = NULL;
		}
208
		spin_unlock_irq(&tsk->cred->tgcred->lock);
L
Linus Torvalds 已提交
209 210 211 212 213

		key_put(keyring);
	}

	ret = 0;
214
error:
L
Linus Torvalds 已提交
215 216 217 218 219 220 221 222 223
	return ret;

} /* end install_process_keyring() */

/*****************************************************************************/
/*
 * install a session keyring, discarding the old one
 * - if a keyring is not supplied, an empty one is invented
 */
224
static int install_session_keyring(struct key *keyring)
L
Linus Torvalds 已提交
225
{
226
	struct task_struct *tsk = current;
227
	unsigned long flags;
L
Linus Torvalds 已提交
228 229
	struct key *old;
	char buf[20];
230 231

	might_sleep();
L
Linus Torvalds 已提交
232 233 234 235 236

	/* create an empty session keyring */
	if (!keyring) {
		sprintf(buf, "_ses.%u", tsk->tgid);

237
		flags = KEY_ALLOC_QUOTA_OVERRUN;
238
		if (tsk->cred->tgcred->session_keyring)
239 240
			flags = KEY_ALLOC_IN_QUOTA;

241 242
		keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid,
					tsk, flags, NULL);
243 244
		if (IS_ERR(keyring))
			return PTR_ERR(keyring);
L
Linus Torvalds 已提交
245 246 247 248 249 250
	}
	else {
		atomic_inc(&keyring->usage);
	}

	/* install the keyring */
251 252 253 254
	spin_lock_irq(&tsk->cred->tgcred->lock);
	old = tsk->cred->tgcred->session_keyring;
	rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring);
	spin_unlock_irq(&tsk->cred->tgcred->lock);
L
Linus Torvalds 已提交
255

256 257 258 259 260 261
	/* 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 已提交
262

263
	return 0;
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272

} /* end install_session_keyring() */

/*****************************************************************************/
/*
 * copy the keys for fork
 */
int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
{
273 274
	key_check(tsk->cred->thread_keyring);
	key_check(tsk->cred->request_key_auth);
L
Linus Torvalds 已提交
275 276

	/* no thread keyring yet */
277
	tsk->cred->thread_keyring = NULL;
278 279

	/* copy the request_key() authorisation for this thread */
280
	key_get(tsk->cred->request_key_auth);
281

L
Linus Torvalds 已提交
282 283 284 285 286 287
	return 0;

} /* end copy_keys() */

/*****************************************************************************/
/*
288
 * dispose of per-thread keys upon thread exit
L
Linus Torvalds 已提交
289 290 291
 */
void exit_keys(struct task_struct *tsk)
{
292 293
	key_put(tsk->cred->thread_keyring);
	key_put(tsk->cred->request_key_auth);
L
Linus Torvalds 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306

} /* end exit_keys() */

/*****************************************************************************/
/*
 * deal with execve()
 */
int exec_keys(struct task_struct *tsk)
{
	struct key *old;

	/* newly exec'd tasks don't get a thread keyring */
	task_lock(tsk);
307 308
	old = tsk->cred->thread_keyring;
	tsk->cred->thread_keyring = NULL;
L
Linus Torvalds 已提交
309 310 311 312 313
	task_unlock(tsk);

	key_put(old);

	/* discard the process keyring from a newly exec'd task */
314 315 316 317
	spin_lock_irq(&tsk->cred->tgcred->lock);
	old = tsk->cred->tgcred->process_keyring;
	tsk->cred->tgcred->process_keyring = NULL;
	spin_unlock_irq(&tsk->cred->tgcred->lock);
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342

	key_put(old);

	return 0;

} /* end exec_keys() */

/*****************************************************************************/
/*
 * deal with SUID programs
 * - we might want to make this invent a new session keyring
 */
int suid_keys(struct task_struct *tsk)
{
	return 0;

} /* end suid_keys() */

/*****************************************************************************/
/*
 * the filesystem user ID changed
 */
void key_fsuid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
343 344 345 346 347
	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 已提交
348 349 350 351 352 353 354 355 356 357 358
	}

} /* end key_fsuid_changed() */

/*****************************************************************************/
/*
 * the filesystem group ID changed
 */
void key_fsgid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
359 360 361 362 363
	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 已提交
364 365 366 367 368 369 370 371 372 373 374 375
	}

} /* 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
 */
376 377 378 379
key_ref_t search_process_keyrings(struct key_type *type,
				  const void *description,
				  key_match_func_t match,
				  struct task_struct *context)
L
Linus Torvalds 已提交
380
{
381
	struct request_key_auth *rka;
382
	struct cred *cred;
383
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
384

385 386
	might_sleep();

387 388
	cred = get_task_cred(context);

L
Linus Torvalds 已提交
389 390 391 392 393 394 395
	/* 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
	 */
396
	key_ref = NULL;
L
Linus Torvalds 已提交
397 398 399 400
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
401
	if (cred->thread_keyring) {
402
		key_ref = keyring_search_aux(
403
			make_key_ref(cred->thread_keyring, 1),
404 405
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
406 407
			goto found;

408
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
409 410 411 412
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
413
			ret = key_ref;
L
Linus Torvalds 已提交
414 415
			break;
		default:
416
			err = key_ref;
L
Linus Torvalds 已提交
417 418 419 420 421
			break;
		}
	}

	/* search the process keyring second */
422
	if (cred->tgcred->process_keyring) {
423
		key_ref = keyring_search_aux(
424
			make_key_ref(cred->tgcred->process_keyring, 1),
425 426
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
427 428
			goto found;

429
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
430 431 432 433
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
434
			ret = key_ref;
L
Linus Torvalds 已提交
435 436
			break;
		default:
437
			err = key_ref;
L
Linus Torvalds 已提交
438 439 440 441
			break;
		}
	}

442
	/* search the session keyring */
443
	if (cred->tgcred->session_keyring) {
444
		rcu_read_lock();
445 446
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
447
					     cred->tgcred->session_keyring),
448
				     1),
449
			context, type, description, match);
450
		rcu_read_unlock();
451

452
		if (!IS_ERR(key_ref))
453 454
			goto found;

455
		switch (PTR_ERR(key_ref)) {
456 457 458 459
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
460
			ret = key_ref;
461 462
			break;
		default:
463
			err = key_ref;
464 465
			break;
		}
466 467
	}
	/* or search the user-session keyring */
468
	else if (cred->user->session_keyring) {
469
		key_ref = keyring_search_aux(
470
			make_key_ref(cred->user->session_keyring, 1),
471
			context, type, description, match);
472
		if (!IS_ERR(key_ref))
473 474
			goto found;

475
		switch (PTR_ERR(key_ref)) {
476 477 478 479
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
480
			ret = key_ref;
481 482
			break;
		default:
483
			err = key_ref;
484 485
			break;
		}
486
	}
487 488 489 490 491

	/* 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
	 */
492
	if (cred->request_key_auth &&
493
	    context == current &&
494
	    type != &key_type_request_key_auth
495
	    ) {
496
		/* defend against the auth key being revoked */
497
		down_read(&cred->request_key_auth->sem);
498

499 500
		if (key_validate(cred->request_key_auth) == 0) {
			rka = cred->request_key_auth->payload.data;
501

502 503
			key_ref = search_process_keyrings(type, description,
							  match, rka->context);
L
Linus Torvalds 已提交
504

505
			up_read(&cred->request_key_auth->sem);
506 507 508 509 510 511 512 513 514 515

			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;
516
				break;
517 518 519 520 521
			default:
				err = key_ref;
				break;
			}
		} else {
522
			up_read(&cred->request_key_auth->sem);
523
		}
L
Linus Torvalds 已提交
524 525 526
	}

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

529
found:
530
	put_cred(cred);
531
	return key_ref;
L
Linus Torvalds 已提交
532 533 534

} /* end search_process_keyrings() */

535 536 537 538 539 540 541 542 543 544
/*****************************************************************************/
/*
 * 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 已提交
545 546 547 548 549 550
/*****************************************************************************/
/*
 * 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
 */
551 552
key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
			  key_perm_t perm)
L
Linus Torvalds 已提交
553
{
554 555
	struct request_key_auth *rka;
	struct task_struct *t = current;
556
	struct cred *cred;
L
Linus Torvalds 已提交
557
	struct key *key;
558
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
559 560
	int ret;

561 562
try_again:
	cred = get_current_cred();
563
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
564 565 566

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
567
		if (!cred->thread_keyring) {
L
Linus Torvalds 已提交
568 569 570
			if (!create)
				goto error;

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

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

	case KEY_SPEC_PROCESS_KEYRING:
585
		if (!cred->tgcred->process_keyring) {
L
Linus Torvalds 已提交
586 587 588
			if (!create)
				goto error;

589
			ret = install_process_keyring();
L
Linus Torvalds 已提交
590 591 592 593
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
594
			goto reget_creds;
L
Linus Torvalds 已提交
595 596
		}

597
		key = cred->tgcred->process_keyring;
L
Linus Torvalds 已提交
598
		atomic_inc(&key->usage);
599
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
600 601 602
		break;

	case KEY_SPEC_SESSION_KEYRING:
603
		if (!cred->tgcred->session_keyring) {
L
Linus Torvalds 已提交
604 605
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
606
			ret = install_user_keyrings();
607 608
			if (ret < 0)
				goto error;
609 610
			ret = install_session_keyring(
				cred->user->session_keyring);
L
Linus Torvalds 已提交
611 612
			if (ret < 0)
				goto error;
613
			goto reget_creds;
L
Linus Torvalds 已提交
614 615
		}

616
		rcu_read_lock();
617
		key = rcu_dereference(cred->tgcred->session_keyring);
L
Linus Torvalds 已提交
618
		atomic_inc(&key->usage);
619
		rcu_read_unlock();
620
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
621 622 623
		break;

	case KEY_SPEC_USER_KEYRING:
624
		if (!cred->user->uid_keyring) {
625
			ret = install_user_keyrings();
626 627 628 629
			if (ret < 0)
				goto error;
		}

630
		key = cred->user->uid_keyring;
L
Linus Torvalds 已提交
631
		atomic_inc(&key->usage);
632
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
633 634 635
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
636
		if (!cred->user->session_keyring) {
637
			ret = install_user_keyrings();
638 639 640 641
			if (ret < 0)
				goto error;
		}

642
		key = cred->user->session_keyring;
L
Linus Torvalds 已提交
643
		atomic_inc(&key->usage);
644
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
645 646 647 648 649 650 651
		break;

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

652
	case KEY_SPEC_REQKEY_AUTH_KEY:
653
		key = cred->request_key_auth;
654 655 656 657 658 659 660
		if (!key)
			goto error;

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

661
	case KEY_SPEC_REQUESTOR_KEYRING:
662
		if (!cred->request_key_auth)
663 664
			goto error;

665 666
		down_read(&cred->request_key_auth->sem);
		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
667 668 669
			key_ref = ERR_PTR(-EKEYREVOKED);
			key = NULL;
		} else {
670
			rka = cred->request_key_auth->payload.data;
671 672 673
			key = rka->dest_keyring;
			atomic_inc(&key->usage);
		}
674
		up_read(&cred->request_key_auth->sem);
675 676 677 678 679
		if (!key)
			goto error;
		key_ref = make_key_ref(key, 1);
		break;

L
Linus Torvalds 已提交
680
	default:
681
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
682 683 684 685
		if (id < 1)
			goto error;

		key = key_lookup(id);
686
		if (IS_ERR(key)) {
687
			key_ref = ERR_CAST(key);
L
Linus Torvalds 已提交
688
			goto error;
689 690 691 692 693 694 695 696 697 698 699 700 701 702
		}

		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,
						   current);

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

L
Linus Torvalds 已提交
703 704 705
		break;
	}

706 707 708 709 710 711 712 713 714 715 716 717
	if (!partial) {
		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 已提交
718 719 720 721 722 723
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

	ret = -EIO;
724
	if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
L
Linus Torvalds 已提交
725 726
		goto invalid_key;

727
	/* check the permissions */
728
	ret = key_task_permission(key_ref, t, perm);
729
	if (ret < 0)
L
Linus Torvalds 已提交
730 731
		goto invalid_key;

732
error:
733
	put_cred(cred);
734
	return key_ref;
L
Linus Torvalds 已提交
735

736 737 738
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
739 740
	goto error;

741 742 743 744 745 746
	/* 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 已提交
747 748 749 750 751 752 753 754 755 756 757 758
} /* 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)
{
	struct task_struct *tsk = current;
759
	struct cred *cred = current->cred;
L
Linus Torvalds 已提交
760 761 762 763 764
	struct key *keyring;
	long ret;

	/* if no name is provided, install an anonymous keyring */
	if (!name) {
765
		ret = install_session_keyring(NULL);
L
Linus Torvalds 已提交
766 767 768
		if (ret < 0)
			goto error;

769
		rcu_read_lock();
770
		ret = rcu_dereference(cred->tgcred->session_keyring)->serial;
771
		rcu_read_unlock();
L
Linus Torvalds 已提交
772 773 774 775
		goto error;
	}

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

	/* look for an existing keyring of this name */
779
	keyring = find_keyring_by_name(name, false);
L
Linus Torvalds 已提交
780 781
	if (PTR_ERR(keyring) == -ENOKEY) {
		/* not found - try and create a new one */
782
		keyring = keyring_alloc(name, cred->uid, cred->gid, tsk,
783
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
784 785
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
786
			goto error2;
L
Linus Torvalds 已提交
787 788 789 790 791 792 793 794
		}
	}
	else if (IS_ERR(keyring)) {
		ret = PTR_ERR(keyring);
		goto error2;
	}

	/* we've got a keyring - now to install it */
795
	ret = install_session_keyring(keyring);
L
Linus Torvalds 已提交
796 797 798 799 800 801
	if (ret < 0)
		goto error2;

	ret = keyring->serial;
	key_put(keyring);

802
error2:
I
Ingo Molnar 已提交
803
	mutex_unlock(&key_session_mutex);
804
error:
L
Linus Torvalds 已提交
805 806 807
	return ret;

} /* end join_session_keyring() */