process_keys.c 18.5 KB
Newer Older
1
/* Management of a process's keyrings
L
Linus Torvalds 已提交
2
 *
3
 * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/err.h>
I
Ingo Molnar 已提交
18
#include <linux/mutex.h>
19
#include <linux/security.h>
20
#include <linux/user_namespace.h>
L
Linus Torvalds 已提交
21 22 23 24
#include <asm/uaccess.h>
#include "internal.h"

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

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

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

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

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

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

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

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

66 67 68 69 70 71 72 73 74 75
	if (!user->uid_keyring) {
		/* get the UID-specific keyring
		 * - there may be one in existence already as it may have been
		 *   pinned by a session, but the user_struct pointing to it
		 *   may have been destroyed by setuid */
		sprintf(buf, "_uid.%u", user->uid);

		uid_keyring = find_keyring_by_name(buf, true);
		if (IS_ERR(uid_keyring)) {
			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
D
David Howells 已提交
76
						    cred, KEY_ALLOC_IN_QUOTA,
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
						    NULL);
			if (IS_ERR(uid_keyring)) {
				ret = PTR_ERR(uid_keyring);
				goto error;
			}
		}

		/* get a default session keyring (which might also exist
		 * already) */
		sprintf(buf, "_uid_ses.%u", user->uid);

		session_keyring = find_keyring_by_name(buf, true);
		if (IS_ERR(session_keyring)) {
			session_keyring =
				keyring_alloc(buf, user->uid, (gid_t) -1,
D
David Howells 已提交
92
					      cred, KEY_ALLOC_IN_QUOTA, NULL);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
			if (IS_ERR(session_keyring)) {
				ret = PTR_ERR(session_keyring);
				goto error_release;
			}

			/* we install a link from the user session keyring to
			 * the user keyring */
			ret = key_link(session_keyring, uid_keyring);
			if (ret < 0)
				goto error_release_both;
		}

		/* install the keyrings */
		user->uid_keyring = uid_keyring;
		user->session_keyring = session_keyring;
L
Linus Torvalds 已提交
108 109
	}

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

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

/*
D
David Howells 已提交
125
 * install a fresh thread keyring directly to new credentials
L
Linus Torvalds 已提交
126
 */
D
David Howells 已提交
127
int install_thread_keyring_to_cred(struct cred *new)
L
Linus Torvalds 已提交
128
{
D
David Howells 已提交
129
	struct key *keyring;
L
Linus Torvalds 已提交
130

D
David Howells 已提交
131 132 133 134
	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
				KEY_ALLOC_QUOTA_OVERRUN, NULL);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);
L
Linus Torvalds 已提交
135

D
David Howells 已提交
136 137 138
	new->thread_keyring = keyring;
	return 0;
}
L
Linus Torvalds 已提交
139 140 141 142

/*
 * install a fresh thread keyring, discarding the old one
 */
D
David Howells 已提交
143
static int install_thread_keyring(void)
L
Linus Torvalds 已提交
144
{
D
David Howells 已提交
145
	struct cred *new;
L
Linus Torvalds 已提交
146 147
	int ret;

D
David Howells 已提交
148 149 150
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
L
Linus Torvalds 已提交
151

D
David Howells 已提交
152 153 154 155 156 157
	BUG_ON(new->thread_keyring);

	ret = install_thread_keyring_to_cred(new);
	if (ret < 0) {
		abort_creds(new);
		return ret;
L
Linus Torvalds 已提交
158 159
	}

D
David Howells 已提交
160 161
	return commit_creds(new);
}
L
Linus Torvalds 已提交
162

D
David Howells 已提交
163 164 165 166 167 168 169 170 171
/*
 * install a process keyring directly to a credentials struct
 * - returns -EEXIST if there was already a process keyring, 0 if one installed,
 *   and other -ve on any other error
 */
int install_process_keyring_to_cred(struct cred *new)
{
	struct key *keyring;
	int ret;
L
Linus Torvalds 已提交
172

D
David Howells 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	if (new->tgcred->process_keyring)
		return -EEXIST;

	keyring = keyring_alloc("_pid", new->uid, new->gid,
				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);

	spin_lock_irq(&new->tgcred->lock);
	if (!new->tgcred->process_keyring) {
		new->tgcred->process_keyring = keyring;
		keyring = NULL;
		ret = 0;
	} else {
		ret = -EEXIST;
	}
	spin_unlock_irq(&new->tgcred->lock);
	key_put(keyring);
L
Linus Torvalds 已提交
191
	return ret;
D
David Howells 已提交
192
}
L
Linus Torvalds 已提交
193 194 195

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

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

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

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

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

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

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

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

	/* install the keyring */
D
David Howells 已提交
241 242 243 244
	spin_lock_irq(&cred->tgcred->lock);
	old = cred->tgcred->session_keyring;
	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
	spin_unlock_irq(&cred->tgcred->lock);
L
Linus Torvalds 已提交
245

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

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

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

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

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

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

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

} /* end key_fsuid_changed() */

/*****************************************************************************/
/*
 * the filesystem group ID changed
 */
void key_fsgid_changed(struct task_struct *tsk)
{
	/* update the ownership of the thread keyring */
301 302 303 304 305
	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 已提交
306 307 308 309 310 311 312 313 314 315 316 317
	}

} /* 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
 */
318 319 320
key_ref_t search_process_keyrings(struct key_type *type,
				  const void *description,
				  key_match_func_t match,
D
David Howells 已提交
321
				  const struct cred *cred)
L
Linus Torvalds 已提交
322
{
323
	struct request_key_auth *rka;
324
	key_ref_t key_ref, ret, err;
L
Linus Torvalds 已提交
325

326 327
	might_sleep();

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

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

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

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

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

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

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

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

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

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

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

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

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

			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;
455
				break;
456 457 458 459 460
			default:
				err = key_ref;
				break;
			}
		} else {
461
			up_read(&cred->request_key_auth->sem);
462
		}
L
Linus Torvalds 已提交
463 464 465
	}

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

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

} /* end search_process_keyrings() */

473 474 475 476 477 478 479 480 481 482
/*****************************************************************************/
/*
 * 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 已提交
483 484 485 486 487 488
/*****************************************************************************/
/*
 * 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
 */
489
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
490
			  key_perm_t perm)
L
Linus Torvalds 已提交
491
{
492
	struct request_key_auth *rka;
D
David Howells 已提交
493
	const struct cred *cred;
L
Linus Torvalds 已提交
494
	struct key *key;
495
	key_ref_t key_ref, skey_ref;
L
Linus Torvalds 已提交
496 497
	int ret;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	case KEY_SPEC_GROUP_KEYRING:
		/* group keyrings are not yet supported */
587
		key_ref = ERR_PTR(-EINVAL);
L
Linus Torvalds 已提交
588 589
		goto error;

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

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

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

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

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

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

		key_ref = make_key_ref(key, 0);

		/* check to see if we possess the key */
		skey_ref = search_process_keyrings(key->type, key,
						   lookup_user_key_possessed,
D
David Howells 已提交
634
						   cred);
635 636 637 638 639 640

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

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

644 645 646 647 648 649 650 651
	/* unlink does not use the nominated key in any way, so can skip all
	 * the permission checks as it is only concerned with the keyring */
	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
		ret = 0;
		goto error;
	}

	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
652 653 654 655 656 657 658 659 660 661 662
		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 已提交
663 664 665 666 667 668
		ret = key_validate(key);
		if (ret < 0)
			goto invalid_key;
	}

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

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

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

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

687 688 689 690 691 692
	/* 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 已提交
693 694 695 696 697 698 699 700 701 702 703
} /* end lookup_user_key() */

/*****************************************************************************/
/*
 * join the named keyring as the session keyring if possible, or attempt to
 * create a new one of that name if not
 * - if the name is NULL, an empty anonymous keyring is installed instead
 * - named session keyring joining is done with a semaphore held
 */
long join_session_keyring(const char *name)
{
D
David Howells 已提交
704 705
	const struct cred *old;
	struct cred *new;
L
Linus Torvalds 已提交
706
	struct key *keyring;
D
David Howells 已提交
707 708 709 710 711
	long ret, serial;

	/* only permit this if there's a single thread in the thread group -
	 * this avoids us having to adjust the creds on all threads and risking
	 * ENOMEM */
712
	if (!current_is_single_threaded())
D
David Howells 已提交
713 714 715 716 717 718
		return -EMLINK;

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

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

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

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

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

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

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

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

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

/*
 * Replace a process's session keyring when that process resumes userspace on
 * behalf of one of its children
 */
void key_replace_session_keyring(void)
{
	const struct cred *old;
	struct cred *new;

	if (!current->replacement_session_keyring)
		return;

	write_lock_irq(&tasklist_lock);
	new = current->replacement_session_keyring;
	current->replacement_session_keyring = NULL;
	write_unlock_irq(&tasklist_lock);

	if (!new)
		return;

	old = current_cred();
	new->  uid	= old->  uid;
	new-> euid	= old-> euid;
	new-> suid	= old-> suid;
	new->fsuid	= old->fsuid;
	new->  gid	= old->  gid;
	new-> egid	= old-> egid;
	new-> sgid	= old-> sgid;
	new->fsgid	= old->fsgid;
	new->user	= get_uid(old->user);
	new->group_info	= get_group_info(old->group_info);

	new->securebits	= old->securebits;
	new->cap_inheritable	= old->cap_inheritable;
	new->cap_permitted	= old->cap_permitted;
	new->cap_effective	= old->cap_effective;
	new->cap_bset		= old->cap_bset;

	new->jit_keyring	= old->jit_keyring;
	new->thread_keyring	= key_get(old->thread_keyring);
	new->tgcred->tgid	= old->tgcred->tgid;
	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);

	security_transfer_creds(new, old);

	commit_creds(new);
}