process_keys.c 19.1 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();

L
Linus Torvalds 已提交
192 193 194
	if (!tsk->signal->process_keyring) {
		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
		spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
204 205 206 207
		if (!tsk->signal->process_keyring) {
			tsk->signal->process_keyring = keyring;
			keyring = NULL;
		}
208
		spin_unlock_irq(&tsk->sighand->siglock);
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 238 239 240
		flags = KEY_ALLOC_QUOTA_OVERRUN;
		if (tsk->signal->session_keyring)
			flags = KEY_ALLOC_IN_QUOTA;

241
		keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
242
					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
	spin_lock_irq(&tsk->sighand->siglock);
	old = tsk->signal->session_keyring;
253
	rcu_assign_pointer(tsk->signal->session_keyring, keyring);
254
	spin_unlock_irq(&tsk->sighand->siglock);
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 273 274 275 276 277 278 279

} /* end install_session_keyring() */

/*****************************************************************************/
/*
 * copy the keys in a thread group for fork without CLONE_THREAD
 */
int copy_thread_group_keys(struct task_struct *tsk)
{
	key_check(current->thread_group->session_keyring);
	key_check(current->thread_group->process_keyring);

	/* no process keyring yet */
	tsk->signal->process_keyring = NULL;

	/* same session keyring */
280
	rcu_read_lock();
L
Linus Torvalds 已提交
281
	tsk->signal->session_keyring =
282 283
		key_get(rcu_dereference(current->signal->session_keyring));
	rcu_read_unlock();
L
Linus Torvalds 已提交
284 285 286 287 288 289 290 291 292 293 294

	return 0;

} /* end copy_thread_group_keys() */

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

	/* no thread keyring yet */
299
	tsk->cred->thread_keyring = NULL;
300 301

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

L
Linus Torvalds 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	return 0;

} /* end copy_keys() */

/*****************************************************************************/
/*
 * dispose of thread group keys upon thread group destruction
 */
void exit_thread_group_keys(struct signal_struct *tg)
{
	key_put(tg->session_keyring);
	key_put(tg->process_keyring);

} /* end exit_thread_group_keys() */

/*****************************************************************************/
/*
321
 * dispose of per-thread keys upon thread exit
L
Linus Torvalds 已提交
322 323 324
 */
void exit_keys(struct task_struct *tsk)
{
325 326
	key_put(tsk->cred->thread_keyring);
	key_put(tsk->cred->request_key_auth);
L
Linus Torvalds 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339

} /* 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);
340 341
	old = tsk->cred->thread_keyring;
	tsk->cred->thread_keyring = NULL;
L
Linus Torvalds 已提交
342 343 344 345 346
	task_unlock(tsk);

	key_put(old);

	/* discard the process keyring from a newly exec'd task */
347
	spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
348 349
	old = tsk->signal->process_keyring;
	tsk->signal->process_keyring = NULL;
350
	spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375

	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 */
376 377 378 379 380
	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 已提交
381 382 383 384 385 386 387 388 389 390 391
	}

} /* end key_fsuid_changed() */

/*****************************************************************************/
/*
 * the filesystem group ID changed
 */
void key_fsgid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
392 393 394 395 396
	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 已提交
397 398 399 400 401 402 403 404 405 406 407 408
	}

} /* 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
 */
409 410 411 412
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 已提交
413
{
414
	struct request_key_auth *rka;
415
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
416

417 418
	might_sleep();

L
Linus Torvalds 已提交
419 420 421 422 423 424 425
	/* 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
	 */
426
	key_ref = NULL;
L
Linus Torvalds 已提交
427 428 429 430
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
431
	if (context->cred->thread_keyring) {
432
		key_ref = keyring_search_aux(
433
			make_key_ref(context->cred->thread_keyring, 1),
434 435
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
436 437
			goto found;

438
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
439 440 441 442
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
443
			ret = key_ref;
L
Linus Torvalds 已提交
444 445
			break;
		default:
446
			err = key_ref;
L
Linus Torvalds 已提交
447 448 449 450 451
			break;
		}
	}

	/* search the process keyring second */
452
	if (context->signal->process_keyring) {
453 454 455 456
		key_ref = keyring_search_aux(
			make_key_ref(context->signal->process_keyring, 1),
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
457 458
			goto found;

459
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
460 461 462 463
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
464
			ret = key_ref;
L
Linus Torvalds 已提交
465 466
			break;
		default:
467
			err = key_ref;
L
Linus Torvalds 已提交
468 469 470 471
			break;
		}
	}

472 473
	/* search the session keyring */
	if (context->signal->session_keyring) {
474
		rcu_read_lock();
475 476 477 478
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
					     context->signal->session_keyring),
				     1),
479
			context, type, description, match);
480
		rcu_read_unlock();
481

482
		if (!IS_ERR(key_ref))
483 484
			goto found;

485
		switch (PTR_ERR(key_ref)) {
486 487 488 489
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
490
			ret = key_ref;
491 492
			break;
		default:
493
			err = key_ref;
494 495
			break;
		}
496 497
	}
	/* or search the user-session keyring */
498
	else if (context->cred->user->session_keyring) {
499
		key_ref = keyring_search_aux(
500
			make_key_ref(context->cred->user->session_keyring, 1),
501
			context, type, description, match);
502
		if (!IS_ERR(key_ref))
503 504
			goto found;

505
		switch (PTR_ERR(key_ref)) {
506 507 508 509
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
510
			ret = key_ref;
511 512
			break;
		default:
513
			err = key_ref;
514 515
			break;
		}
516
	}
517 518 519 520 521

	/* 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
	 */
522
	if (context->cred->request_key_auth &&
523
	    context == current &&
524
	    type != &key_type_request_key_auth
525
	    ) {
526
		/* defend against the auth key being revoked */
527
		down_read(&context->cred->request_key_auth->sem);
528

529 530
		if (key_validate(context->cred->request_key_auth) == 0) {
			rka = context->cred->request_key_auth->payload.data;
531

532 533
			key_ref = search_process_keyrings(type, description,
							  match, rka->context);
L
Linus Torvalds 已提交
534

535
			up_read(&context->cred->request_key_auth->sem);
536 537 538 539 540 541 542 543 544 545

			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;
546
				break;
547 548 549 550 551
			default:
				err = key_ref;
				break;
			}
		} else {
552
			up_read(&context->cred->request_key_auth->sem);
553
		}
L
Linus Torvalds 已提交
554 555 556
	}

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

559
found:
560
	return key_ref;
L
Linus Torvalds 已提交
561 562 563

} /* end search_process_keyrings() */

564 565 566 567 568 569 570 571 572 573
/*****************************************************************************/
/*
 * 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 已提交
574 575 576 577 578 579
/*****************************************************************************/
/*
 * 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
 */
580 581
key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
			  key_perm_t perm)
L
Linus Torvalds 已提交
582
{
583 584
	struct request_key_auth *rka;
	struct task_struct *t = current;
585
	struct cred *cred = current_cred();
L
Linus Torvalds 已提交
586
	struct key *key;
587
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
588 589
	int ret;

590
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
591 592 593

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
594
		if (!cred->thread_keyring) {
L
Linus Torvalds 已提交
595 596 597
			if (!create)
				goto error;

598
			ret = install_thread_keyring();
L
Linus Torvalds 已提交
599 600 601 602 603 604
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

605
		key = cred->thread_keyring;
L
Linus Torvalds 已提交
606
		atomic_inc(&key->usage);
607
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
608 609 610
		break;

	case KEY_SPEC_PROCESS_KEYRING:
611
		if (!t->signal->process_keyring) {
L
Linus Torvalds 已提交
612 613 614
			if (!create)
				goto error;

615
			ret = install_process_keyring();
L
Linus Torvalds 已提交
616 617 618 619 620 621
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

622
		key = t->signal->process_keyring;
L
Linus Torvalds 已提交
623
		atomic_inc(&key->usage);
624
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
625 626 627
		break;

	case KEY_SPEC_SESSION_KEYRING:
628
		if (!t->signal->session_keyring) {
L
Linus Torvalds 已提交
629 630
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
631
			ret = install_user_keyrings();
632 633
			if (ret < 0)
				goto error;
634 635
			ret = install_session_keyring(
				cred->user->session_keyring);
L
Linus Torvalds 已提交
636 637 638 639
			if (ret < 0)
				goto error;
		}

640
		rcu_read_lock();
641
		key = rcu_dereference(t->signal->session_keyring);
L
Linus Torvalds 已提交
642
		atomic_inc(&key->usage);
643
		rcu_read_unlock();
644
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
645 646 647
		break;

	case KEY_SPEC_USER_KEYRING:
648
		if (!cred->user->uid_keyring) {
649
			ret = install_user_keyrings();
650 651 652 653
			if (ret < 0)
				goto error;
		}

654
		key = cred->user->uid_keyring;
L
Linus Torvalds 已提交
655
		atomic_inc(&key->usage);
656
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
657 658 659
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
660
		if (!cred->user->session_keyring) {
661
			ret = install_user_keyrings();
662 663 664 665
			if (ret < 0)
				goto error;
		}

666
		key = cred->user->session_keyring;
L
Linus Torvalds 已提交
667
		atomic_inc(&key->usage);
668
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
669 670 671 672 673 674 675
		break;

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

676
	case KEY_SPEC_REQKEY_AUTH_KEY:
677
		key = cred->request_key_auth;
678 679 680 681 682 683 684
		if (!key)
			goto error;

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

685
	case KEY_SPEC_REQUESTOR_KEYRING:
686
		if (!cred->request_key_auth)
687 688
			goto error;

689 690
		down_read(&cred->request_key_auth->sem);
		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
691 692 693
			key_ref = ERR_PTR(-EKEYREVOKED);
			key = NULL;
		} else {
694
			rka = cred->request_key_auth->payload.data;
695 696 697
			key = rka->dest_keyring;
			atomic_inc(&key->usage);
		}
698
		up_read(&cred->request_key_auth->sem);
699 700 701 702 703
		if (!key)
			goto error;
		key_ref = make_key_ref(key, 1);
		break;

L
Linus Torvalds 已提交
704
	default:
705
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
706 707 708 709
		if (id < 1)
			goto error;

		key = key_lookup(id);
710
		if (IS_ERR(key)) {
711
			key_ref = ERR_CAST(key);
L
Linus Torvalds 已提交
712
			goto error;
713 714 715 716 717 718 719 720 721 722 723 724 725 726
		}

		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 已提交
727 728 729
		break;
	}

730 731 732 733 734 735 736 737 738 739 740 741
	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 已提交
742 743 744 745 746 747
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

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

751
	/* check the permissions */
752
	ret = key_task_permission(key_ref, t, perm);
753
	if (ret < 0)
L
Linus Torvalds 已提交
754 755
		goto invalid_key;

756 757
error:
	return key_ref;
L
Linus Torvalds 已提交
758

759 760 761
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
	goto error;

} /* 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;
	struct key *keyring;
	long ret;

	/* if no name is provided, install an anonymous keyring */
	if (!name) {
781
		ret = install_session_keyring(NULL);
L
Linus Torvalds 已提交
782 783 784
		if (ret < 0)
			goto error;

785 786 787
		rcu_read_lock();
		ret = rcu_dereference(tsk->signal->session_keyring)->serial;
		rcu_read_unlock();
L
Linus Torvalds 已提交
788 789 790 791
		goto error;
	}

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

	/* look for an existing keyring of this name */
795
	keyring = find_keyring_by_name(name, false);
L
Linus Torvalds 已提交
796 797
	if (PTR_ERR(keyring) == -ENOKEY) {
		/* not found - try and create a new one */
798
		keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
799
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
800 801
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
802
			goto error2;
L
Linus Torvalds 已提交
803 804 805 806 807 808 809 810
		}
	}
	else if (IS_ERR(keyring)) {
		ret = PTR_ERR(keyring);
		goto error2;
	}

	/* we've got a keyring - now to install it */
811
	ret = install_session_keyring(keyring);
L
Linus Torvalds 已提交
812 813 814 815 816 817
	if (ret < 0)
		goto error2;

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

818
error2:
I
Ingo Molnar 已提交
819
	mutex_unlock(&key_session_mutex);
820
error:
L
Linus Torvalds 已提交
821 822 823
	return ret;

} /* end join_session_keyring() */