process_keys.c 18.4 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
static int install_user_keyrings(struct task_struct *tsk)
L
Linus Torvalds 已提交
44
{
45
	struct user_struct *user = tsk->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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	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,
						    tsk, KEY_ALLOC_IN_QUOTA,
						    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,
					      tsk, KEY_ALLOC_IN_QUOTA, NULL);
			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 已提交
102 103
	}

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

108 109 110 111
error_release_both:
	key_put(session_keyring);
error_release:
	key_put(uid_keyring);
112
error:
113 114
	mutex_unlock(&key_user_keyring_mutex);
	kleave(" = %d", ret);
L
Linus Torvalds 已提交
115
	return ret;
116
}
L
Linus Torvalds 已提交
117 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 150 151 152 153 154 155 156

/*****************************************************************************/
/*
 * 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
 */
int install_thread_keyring(struct task_struct *tsk)
{
	struct key *keyring, *old;
	char buf[20];
	int ret;

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

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

	task_lock(tsk);
	old = tsk->thread_keyring;
	tsk->thread_keyring = keyring;
	task_unlock(tsk);

	ret = 0;

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

} /* end install_thread_keyring() */

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

187 188
	might_sleep();

L
Linus Torvalds 已提交
189 190 191
	if (!tsk->signal->process_keyring) {
		sprintf(buf, "_pid.%u", tsk->tgid);

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

199
		/* attach keyring */
200
		spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
201 202 203 204
		if (!tsk->signal->process_keyring) {
			tsk->signal->process_keyring = keyring;
			keyring = NULL;
		}
205
		spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
206 207 208 209 210

		key_put(keyring);
	}

	ret = 0;
211
error:
L
Linus Torvalds 已提交
212 213 214 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
 */
static int install_session_keyring(struct task_struct *tsk,
				   struct key *keyring)
{
224
	unsigned long flags;
L
Linus Torvalds 已提交
225 226
	struct key *old;
	char buf[20];
227 228

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

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

234 235 236 237 238 239
		flags = KEY_ALLOC_QUOTA_OVERRUN;
		if (tsk->signal->session_keyring)
			flags = KEY_ALLOC_IN_QUOTA;

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

	/* install the keyring */
248 249
	spin_lock_irq(&tsk->sighand->siglock);
	old = tsk->signal->session_keyring;
250
	rcu_assign_pointer(tsk->signal->session_keyring, keyring);
251
	spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
252

253 254 255 256 257 258
	/* 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 已提交
259

260
	return 0;
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276

} /* 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 */
277
	rcu_read_lock();
L
Linus Torvalds 已提交
278
	tsk->signal->session_keyring =
279 280
		key_get(rcu_dereference(current->signal->session_keyring));
	rcu_read_unlock();
L
Linus Torvalds 已提交
281 282 283 284 285 286 287 288 289 290 291 292

	return 0;

} /* end copy_thread_group_keys() */

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

	/* no thread keyring yet */
	tsk->thread_keyring = NULL;
297 298 299 300

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

L
Linus Torvalds 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	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() */

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

} /* 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);
	old = tsk->thread_keyring;
	tsk->thread_keyring = NULL;
	task_unlock(tsk);

	key_put(old);

	/* discard the process keyring from a newly exec'd task */
344
	spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
345 346
	old = tsk->signal->process_keyring;
	tsk->signal->process_keyring = NULL;
347
	spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
348 349 350 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 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

	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 */
	if (tsk->thread_keyring) {
		down_write(&tsk->thread_keyring->sem);
		tsk->thread_keyring->uid = tsk->fsuid;
		up_write(&tsk->thread_keyring->sem);
	}

} /* end key_fsuid_changed() */

/*****************************************************************************/
/*
 * the filesystem group ID changed
 */
void key_fsgid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
	if (tsk->thread_keyring) {
		down_write(&tsk->thread_keyring->sem);
		tsk->thread_keyring->gid = tsk->fsgid;
		up_write(&tsk->thread_keyring->sem);
	}

} /* 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
 */
404 405 406 407
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 已提交
408
{
409
	struct request_key_auth *rka;
410
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
411

412 413
	might_sleep();

L
Linus Torvalds 已提交
414 415 416 417 418 419 420
	/* 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
	 */
421
	key_ref = NULL;
L
Linus Torvalds 已提交
422 423 424 425
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
426
	if (context->thread_keyring) {
427 428 429 430
		key_ref = keyring_search_aux(
			make_key_ref(context->thread_keyring, 1),
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
431 432
			goto found;

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

	/* search the process keyring second */
447
	if (context->signal->process_keyring) {
448 449 450 451
		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 已提交
452 453
			goto found;

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

467 468
	/* search the session keyring */
	if (context->signal->session_keyring) {
469
		rcu_read_lock();
470 471 472 473
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
					     context->signal->session_keyring),
				     1),
474
			context, type, description, match);
475
		rcu_read_unlock();
476

477
		if (!IS_ERR(key_ref))
478 479
			goto found;

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

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

	/* 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
	 */
	if (context->request_key_auth &&
	    context == current &&
519
	    type != &key_type_request_key_auth
520
	    ) {
521 522
		/* defend against the auth key being revoked */
		down_read(&context->request_key_auth->sem);
523

524 525
		if (key_validate(context->request_key_auth) == 0) {
			rka = context->request_key_auth->payload.data;
526

527 528
			key_ref = search_process_keyrings(type, description,
							  match, rka->context);
L
Linus Torvalds 已提交
529

530 531 532 533 534 535 536 537 538 539 540
			up_read(&context->request_key_auth->sem);

			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;
541
				break;
542 543 544 545 546 547
			default:
				err = key_ref;
				break;
			}
		} else {
			up_read(&context->request_key_auth->sem);
548
		}
L
Linus Torvalds 已提交
549 550 551
	}

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

554
found:
555
	return key_ref;
L
Linus Torvalds 已提交
556 557 558

} /* end search_process_keyrings() */

559 560 561 562 563 564 565 566 567 568
/*****************************************************************************/
/*
 * 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 已提交
569 570 571 572 573 574
/*****************************************************************************/
/*
 * 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
 */
575 576
key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
			  int create, int partial, key_perm_t perm)
L
Linus Torvalds 已提交
577
{
578
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
579 580 581
	struct key *key;
	int ret;

582 583 584
	if (!context)
		context = current;

585
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
586 587 588

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
589
		if (!context->thread_keyring) {
L
Linus Torvalds 已提交
590 591 592
			if (!create)
				goto error;

593
			ret = install_thread_keyring(context);
L
Linus Torvalds 已提交
594 595 596 597 598 599
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

600
		key = context->thread_keyring;
L
Linus Torvalds 已提交
601
		atomic_inc(&key->usage);
602
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
603 604 605
		break;

	case KEY_SPEC_PROCESS_KEYRING:
606
		if (!context->signal->process_keyring) {
L
Linus Torvalds 已提交
607 608 609
			if (!create)
				goto error;

610
			ret = install_process_keyring(context);
L
Linus Torvalds 已提交
611 612 613 614 615 616
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

617
		key = context->signal->process_keyring;
L
Linus Torvalds 已提交
618
		atomic_inc(&key->usage);
619
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
620 621 622
		break;

	case KEY_SPEC_SESSION_KEYRING:
623
		if (!context->signal->session_keyring) {
L
Linus Torvalds 已提交
624 625
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
626 627 628
			ret = install_user_keyrings(context);
			if (ret < 0)
				goto error;
L
Linus Torvalds 已提交
629
			ret = install_session_keyring(
630
				context, context->user->session_keyring);
L
Linus Torvalds 已提交
631 632 633 634
			if (ret < 0)
				goto error;
		}

635 636
		rcu_read_lock();
		key = rcu_dereference(context->signal->session_keyring);
L
Linus Torvalds 已提交
637
		atomic_inc(&key->usage);
638
		rcu_read_unlock();
639
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
640 641 642
		break;

	case KEY_SPEC_USER_KEYRING:
643 644 645 646 647 648
		if (!context->user->uid_keyring) {
			ret = install_user_keyrings(context);
			if (ret < 0)
				goto error;
		}

649
		key = context->user->uid_keyring;
L
Linus Torvalds 已提交
650
		atomic_inc(&key->usage);
651
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
652 653 654
		break;

	case KEY_SPEC_USER_SESSION_KEYRING:
655 656 657 658 659 660
		if (!context->user->session_keyring) {
			ret = install_user_keyrings(context);
			if (ret < 0)
				goto error;
		}

661
		key = context->user->session_keyring;
L
Linus Torvalds 已提交
662
		atomic_inc(&key->usage);
663
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
664 665 666 667 668 669 670
		break;

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

671 672 673 674 675 676 677 678 679
	case KEY_SPEC_REQKEY_AUTH_KEY:
		key = context->request_key_auth;
		if (!key)
			goto error;

		atomic_inc(&key->usage);
		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 729
	ret = key_task_permission(key_ref, context, perm);
	if (ret < 0)
L
Linus Torvalds 已提交
730 731
		goto invalid_key;

732 733
error:
	return key_ref;
L
Linus Torvalds 已提交
734

735 736 737
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
	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) {
		ret = install_session_keyring(tsk, NULL);
		if (ret < 0)
			goto error;

761 762 763
		rcu_read_lock();
		ret = rcu_dereference(tsk->signal->session_keyring)->serial;
		rcu_read_unlock();
L
Linus Torvalds 已提交
764 765 766 767
		goto error;
	}

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

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

	/* we've got a keyring - now to install it */
	ret = install_session_keyring(tsk, keyring);
	if (ret < 0)
		goto error2;

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

794
error2:
I
Ingo Molnar 已提交
795
	mutex_unlock(&key_session_mutex);
796
error:
L
Linus Torvalds 已提交
797 798 799
	return ret;

} /* end join_session_keyring() */