process_keys.c 17.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/* process_keys.c: management of a process's keyrings
 *
3
 * Copyright (C) 2004-5 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42

/* the root user's tracking struct */
struct key_user root_key_user = {
	.usage		= ATOMIC_INIT(3),
	.consq		= LIST_HEAD_INIT(root_key_user.consq),
	.lock		= SPIN_LOCK_UNLOCKED,
	.nkeys		= ATOMIC_INIT(2),
	.nikeys		= ATOMIC_INIT(2),
	.uid		= 0,
};

/* the root user's UID keyring */
struct key root_user_keyring = {
	.usage		= ATOMIC_INIT(1),
	.serial		= 2,
	.type		= &key_type_keyring,
	.user		= &root_key_user,
	.sem		= __RWSEM_INITIALIZER(root_user_keyring.sem),
43
	.perm		= (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
44
	.flags		= 1 << KEY_FLAG_INSTANTIATED,
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57
	.description	= "_uid.0",
#ifdef KEY_DEBUGGING
	.magic		= KEY_DEBUG_MAGIC,
#endif
};

/* the root user's default session keyring */
struct key root_session_keyring = {
	.usage		= ATOMIC_INIT(1),
	.serial		= 1,
	.type		= &key_type_keyring,
	.user		= &root_key_user,
	.sem		= __RWSEM_INITIALIZER(root_session_keyring.sem),
58
	.perm		= (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
59
	.flags		= 1 << KEY_FLAG_INSTANTIATED,
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68 69
	.description	= "_uid_ses.0",
#ifdef KEY_DEBUGGING
	.magic		= KEY_DEBUG_MAGIC,
#endif
};

/*****************************************************************************/
/*
 * allocate the keyrings to be associated with a UID
 */
70 71
int alloc_uid_keyring(struct user_struct *user,
		      struct task_struct *ctx)
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79
{
	struct key *uid_keyring, *session_keyring;
	char buf[20];
	int ret;

	/* concoct a default session keyring */
	sprintf(buf, "_uid_ses.%u", user->uid);

80 81
	session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90
	if (IS_ERR(session_keyring)) {
		ret = PTR_ERR(session_keyring);
		goto error;
	}

	/* and a UID specific keyring, pointed to by the default session
	 * keyring */
	sprintf(buf, "_uid.%u", user->uid);

91 92
	uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
				    KEY_ALLOC_IN_QUOTA, session_keyring);
L
Linus Torvalds 已提交
93 94 95 96 97 98 99 100 101 102 103
	if (IS_ERR(uid_keyring)) {
		key_put(session_keyring);
		ret = PTR_ERR(uid_keyring);
		goto error;
	}

	/* install the keyrings */
	user->uid_keyring = uid_keyring;
	user->session_keyring = session_keyring;
	ret = 0;

104
error:
L
Linus Torvalds 已提交
105 106 107 108 109 110 111 112 113 114 115 116 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
	return ret;

} /* end alloc_uid_keyring() */

/*****************************************************************************/
/*
 * 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);

148 149
	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
				KEY_ALLOC_QUOTA_OVERRUN, NULL);
L
Linus Torvalds 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162
	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);
163
error:
L
Linus Torvalds 已提交
164 165 166 167 168 169 170 171
	return ret;

} /* end install_thread_keyring() */

/*****************************************************************************/
/*
 * make sure a process keyring is installed
 */
172
int install_process_keyring(struct task_struct *tsk)
L
Linus Torvalds 已提交
173 174 175 176 177
{
	struct key *keyring;
	char buf[20];
	int ret;

178 179
	might_sleep();

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

183 184
		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
					KEY_ALLOC_QUOTA_OVERRUN, NULL);
L
Linus Torvalds 已提交
185 186 187 188 189
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
			goto error;
		}

190
		/* attach keyring */
191
		spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
192 193 194 195
		if (!tsk->signal->process_keyring) {
			tsk->signal->process_keyring = keyring;
			keyring = NULL;
		}
196
		spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
197 198 199 200 201

		key_put(keyring);
	}

	ret = 0;
202
error:
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210 211 212 213 214
	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)
{
215
	unsigned long flags;
L
Linus Torvalds 已提交
216 217
	struct key *old;
	char buf[20];
218 219

	might_sleep();
L
Linus Torvalds 已提交
220 221 222 223 224

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

225 226 227 228 229 230
		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);
231 232
		if (IS_ERR(keyring))
			return PTR_ERR(keyring);
L
Linus Torvalds 已提交
233 234 235 236 237 238
	}
	else {
		atomic_inc(&keyring->usage);
	}

	/* install the keyring */
239 240
	spin_lock_irq(&tsk->sighand->siglock);
	old = tsk->signal->session_keyring;
241
	rcu_assign_pointer(tsk->signal->session_keyring, keyring);
242
	spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
243

244 245 246 247 248 249
	/* 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 已提交
250

251
	return 0;
L
Linus Torvalds 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

} /* 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 */
268
	rcu_read_lock();
L
Linus Torvalds 已提交
269
	tsk->signal->session_keyring =
270 271
		key_get(rcu_dereference(current->signal->session_keyring));
	rcu_read_unlock();
L
Linus Torvalds 已提交
272 273 274 275 276 277 278 279 280 281 282 283

	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);
284
	key_check(tsk->request_key_auth);
L
Linus Torvalds 已提交
285 286 287

	/* no thread keyring yet */
	tsk->thread_keyring = NULL;
288 289 290 291

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

L
Linus Torvalds 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	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() */

/*****************************************************************************/
/*
309
 * dispose of per-thread keys upon thread exit
L
Linus Torvalds 已提交
310 311 312 313
 */
void exit_keys(struct task_struct *tsk)
{
	key_put(tsk->thread_keyring);
314
	key_put(tsk->request_key_auth);
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334

} /* 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 */
335
	spin_lock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
336 337
	old = tsk->signal->process_keyring;
	tsk->signal->process_keyring = NULL;
338
	spin_unlock_irq(&tsk->sighand->siglock);
L
Linus Torvalds 已提交
339 340 341 342 343 344 345 346 347 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

	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
 */
395 396 397 398
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 已提交
399
{
400
	struct request_key_auth *rka;
401
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
402

403 404
	might_sleep();

L
Linus Torvalds 已提交
405 406 407 408 409 410 411
	/* 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
	 */
412
	key_ref = NULL;
L
Linus Torvalds 已提交
413 414 415 416
	ret = NULL;
	err = ERR_PTR(-EAGAIN);

	/* search the thread keyring first */
417
	if (context->thread_keyring) {
418 419 420 421
		key_ref = keyring_search_aux(
			make_key_ref(context->thread_keyring, 1),
			context, type, description, match);
		if (!IS_ERR(key_ref))
L
Linus Torvalds 已提交
422 423
			goto found;

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

	/* search the process keyring second */
438
	if (context->signal->process_keyring) {
439 440 441 442
		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 已提交
443 444
			goto found;

445
		switch (PTR_ERR(key_ref)) {
L
Linus Torvalds 已提交
446 447 448 449
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
450
			ret = key_ref;
L
Linus Torvalds 已提交
451 452
			break;
		default:
453
			err = key_ref;
L
Linus Torvalds 已提交
454 455 456 457
			break;
		}
	}

458 459
	/* search the session keyring */
	if (context->signal->session_keyring) {
460
		rcu_read_lock();
461 462 463 464
		key_ref = keyring_search_aux(
			make_key_ref(rcu_dereference(
					     context->signal->session_keyring),
				     1),
465
			context, type, description, match);
466
		rcu_read_unlock();
467

468
		if (!IS_ERR(key_ref))
469 470
			goto found;

471
		switch (PTR_ERR(key_ref)) {
472 473 474 475
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
476
			ret = key_ref;
477 478
			break;
		default:
479
			err = key_ref;
480 481
			break;
		}
482 483 484 485 486 487
	}
	/* or search the user-session keyring */
	else {
		key_ref = keyring_search_aux(
			make_key_ref(context->user->session_keyring, 1),
			context, type, description, match);
488
		if (!IS_ERR(key_ref))
489 490
			goto found;

491
		switch (PTR_ERR(key_ref)) {
492 493 494 495
		case -EAGAIN: /* no key */
			if (ret)
				break;
		case -ENOKEY: /* negative key */
496
			ret = key_ref;
497 498
			break;
		default:
499
			err = key_ref;
500 501
			break;
		}
502
	}
503 504 505 506 507 508 509

	/* 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 &&
510
	    type != &key_type_request_key_auth
511
	    ) {
512 513
		/* defend against the auth key being revoked */
		down_read(&context->request_key_auth->sem);
514

515 516
		if (key_validate(context->request_key_auth) == 0) {
			rka = context->request_key_auth->payload.data;
517

518 519
			key_ref = search_process_keyrings(type, description,
							  match, rka->context);
L
Linus Torvalds 已提交
520

521 522 523 524 525 526 527 528 529 530 531
			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;
532
				break;
533 534 535 536 537 538
			default:
				err = key_ref;
				break;
			}
		} else {
			up_read(&context->request_key_auth->sem);
539
		}
L
Linus Torvalds 已提交
540 541 542
	}

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

545
found:
546
	return key_ref;
L
Linus Torvalds 已提交
547 548 549

} /* end search_process_keyrings() */

550 551 552 553 554 555 556 557 558 559
/*****************************************************************************/
/*
 * 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 已提交
560 561 562 563 564 565
/*****************************************************************************/
/*
 * 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
 */
566 567
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 已提交
568
{
569
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
570 571 572
	struct key *key;
	int ret;

573 574 575
	if (!context)
		context = current;

576
	key_ref = ERR_PTR(-ENOKEY);
L
Linus Torvalds 已提交
577 578 579

	switch (id) {
	case KEY_SPEC_THREAD_KEYRING:
580
		if (!context->thread_keyring) {
L
Linus Torvalds 已提交
581 582 583
			if (!create)
				goto error;

584
			ret = install_thread_keyring(context);
L
Linus Torvalds 已提交
585 586 587 588 589 590
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

591
		key = context->thread_keyring;
L
Linus Torvalds 已提交
592
		atomic_inc(&key->usage);
593
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
594 595 596
		break;

	case KEY_SPEC_PROCESS_KEYRING:
597
		if (!context->signal->process_keyring) {
L
Linus Torvalds 已提交
598 599 600
			if (!create)
				goto error;

601
			ret = install_process_keyring(context);
L
Linus Torvalds 已提交
602 603 604 605 606 607
			if (ret < 0) {
				key = ERR_PTR(ret);
				goto error;
			}
		}

608
		key = context->signal->process_keyring;
L
Linus Torvalds 已提交
609
		atomic_inc(&key->usage);
610
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
611 612 613
		break;

	case KEY_SPEC_SESSION_KEYRING:
614
		if (!context->signal->session_keyring) {
L
Linus Torvalds 已提交
615 616 617
			/* always install a session keyring upon access if one
			 * doesn't exist yet */
			ret = install_session_keyring(
618
				context, context->user->session_keyring);
L
Linus Torvalds 已提交
619 620 621 622
			if (ret < 0)
				goto error;
		}

623 624
		rcu_read_lock();
		key = rcu_dereference(context->signal->session_keyring);
L
Linus Torvalds 已提交
625
		atomic_inc(&key->usage);
626
		rcu_read_unlock();
627
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
628 629 630
		break;

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

	case KEY_SPEC_USER_SESSION_KEYRING:
637
		key = context->user->session_keyring;
L
Linus Torvalds 已提交
638
		atomic_inc(&key->usage);
639
		key_ref = make_key_ref(key, 1);
L
Linus Torvalds 已提交
640 641 642 643 644 645 646
		break;

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

647 648 649 650 651 652 653 654 655
	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 已提交
656
	default:
657
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
658 659 660 661
		if (id < 1)
			goto error;

		key = key_lookup(id);
662 663
		if (IS_ERR(key)) {
			key_ref = ERR_PTR(PTR_ERR(key));
L
Linus Torvalds 已提交
664
			goto error;
665 666 667 668 669 670 671 672 673 674 675 676 677 678
		}

		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 已提交
679 680 681
		break;
	}

682
	/* check the status */
L
Linus Torvalds 已提交
683 684 685 686 687 688 689
	if (perm) {
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

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

693
	/* check the permissions */
694 695
	ret = key_task_permission(key_ref, context, perm);
	if (ret < 0)
L
Linus Torvalds 已提交
696 697
		goto invalid_key;

698 699
error:
	return key_ref;
L
Linus Torvalds 已提交
700

701 702 703
invalid_key:
	key_ref_put(key_ref);
	key_ref = ERR_PTR(ret);
L
Linus Torvalds 已提交
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
	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;

727 728 729
		rcu_read_lock();
		ret = rcu_dereference(tsk->signal->session_keyring)->serial;
		rcu_read_unlock();
L
Linus Torvalds 已提交
730 731 732 733
		goto error;
	}

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

	/* look for an existing keyring of this name */
	keyring = find_keyring_by_name(name, 0);
	if (PTR_ERR(keyring) == -ENOKEY) {
		/* not found - try and create a new one */
740 741
		keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
					KEY_ALLOC_IN_QUOTA, NULL);
L
Linus Torvalds 已提交
742 743
		if (IS_ERR(keyring)) {
			ret = PTR_ERR(keyring);
744
			goto error2;
L
Linus Torvalds 已提交
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
		}
	}
	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);

760
error2:
I
Ingo Molnar 已提交
761
	mutex_unlock(&key_session_mutex);
762
error:
L
Linus Torvalds 已提交
763 764 765
	return ret;

} /* end join_session_keyring() */