diff options
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 164 |
1 files changed, 101 insertions, 63 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index c089f78fb94e..d42d2158ce13 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -39,7 +39,7 @@ struct key root_user_keyring = { | |||
39 | .type = &key_type_keyring, | 39 | .type = &key_type_keyring, |
40 | .user = &root_key_user, | 40 | .user = &root_key_user, |
41 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | 41 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), |
42 | .perm = KEY_USR_ALL, | 42 | .perm = KEY_POS_ALL | KEY_USR_ALL, |
43 | .flags = 1 << KEY_FLAG_INSTANTIATED, | 43 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
44 | .description = "_uid.0", | 44 | .description = "_uid.0", |
45 | #ifdef KEY_DEBUGGING | 45 | #ifdef KEY_DEBUGGING |
@@ -54,7 +54,7 @@ struct key root_session_keyring = { | |||
54 | .type = &key_type_keyring, | 54 | .type = &key_type_keyring, |
55 | .user = &root_key_user, | 55 | .user = &root_key_user, |
56 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | 56 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), |
57 | .perm = KEY_USR_ALL, | 57 | .perm = KEY_POS_ALL | KEY_USR_ALL, |
58 | .flags = 1 << KEY_FLAG_INSTANTIATED, | 58 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
59 | .description = "_uid_ses.0", | 59 | .description = "_uid_ses.0", |
60 | #ifdef KEY_DEBUGGING | 60 | #ifdef KEY_DEBUGGING |
@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct *user) | |||
98 | user->session_keyring = session_keyring; | 98 | user->session_keyring = session_keyring; |
99 | ret = 0; | 99 | ret = 0; |
100 | 100 | ||
101 | error: | 101 | error: |
102 | return ret; | 102 | return ret; |
103 | 103 | ||
104 | } /* end alloc_uid_keyring() */ | 104 | } /* end alloc_uid_keyring() */ |
@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_struct *tsk) | |||
156 | ret = 0; | 156 | ret = 0; |
157 | 157 | ||
158 | key_put(old); | 158 | key_put(old); |
159 | error: | 159 | error: |
160 | return ret; | 160 | return ret; |
161 | 161 | ||
162 | } /* end install_thread_keyring() */ | 162 | } /* end install_thread_keyring() */ |
@@ -193,7 +193,7 @@ int install_process_keyring(struct task_struct *tsk) | |||
193 | } | 193 | } |
194 | 194 | ||
195 | ret = 0; | 195 | ret = 0; |
196 | error: | 196 | error: |
197 | return ret; | 197 | return ret; |
198 | 198 | ||
199 | } /* end install_process_keyring() */ | 199 | } /* end install_process_keyring() */ |
@@ -236,7 +236,7 @@ static int install_session_keyring(struct task_struct *tsk, | |||
236 | /* we're using RCU on the pointer */ | 236 | /* we're using RCU on the pointer */ |
237 | synchronize_rcu(); | 237 | synchronize_rcu(); |
238 | key_put(old); | 238 | key_put(old); |
239 | error: | 239 | error: |
240 | return ret; | 240 | return ret; |
241 | 241 | ||
242 | } /* end install_session_keyring() */ | 242 | } /* end install_session_keyring() */ |
@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
376 | * - we return -EAGAIN if we didn't find any matching key | 376 | * - we return -EAGAIN if we didn't find any matching key |
377 | * - we return -ENOKEY if we found only negative matching keys | 377 | * - we return -ENOKEY if we found only negative matching keys |
378 | */ | 378 | */ |
379 | struct key *search_process_keyrings(struct key_type *type, | 379 | key_ref_t search_process_keyrings(struct key_type *type, |
380 | const void *description, | 380 | const void *description, |
381 | key_match_func_t match, | 381 | key_match_func_t match, |
382 | struct task_struct *context) | 382 | struct task_struct *context) |
383 | { | 383 | { |
384 | struct request_key_auth *rka; | 384 | struct request_key_auth *rka; |
385 | struct key *key, *ret, *err, *instkey; | 385 | key_ref_t key_ref, ret, err, instkey_ref; |
386 | 386 | ||
387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
388 | * searchable, but we failed to find a key or we found a negative key; | 388 | * searchable, but we failed to find a key or we found a negative key; |
@@ -391,46 +391,48 @@ struct key *search_process_keyrings(struct key_type *type, | |||
391 | * | 391 | * |
392 | * in terms of priority: success > -ENOKEY > -EAGAIN > other error | 392 | * in terms of priority: success > -ENOKEY > -EAGAIN > other error |
393 | */ | 393 | */ |
394 | key = NULL; | 394 | key_ref = NULL; |
395 | ret = NULL; | 395 | ret = NULL; |
396 | err = ERR_PTR(-EAGAIN); | 396 | err = ERR_PTR(-EAGAIN); |
397 | 397 | ||
398 | /* search the thread keyring first */ | 398 | /* search the thread keyring first */ |
399 | if (context->thread_keyring) { | 399 | if (context->thread_keyring) { |
400 | key = keyring_search_aux(context->thread_keyring, | 400 | key_ref = keyring_search_aux( |
401 | context, type, description, match); | 401 | make_key_ref(context->thread_keyring, 1), |
402 | if (!IS_ERR(key)) | 402 | context, type, description, match); |
403 | if (!IS_ERR(key_ref)) | ||
403 | goto found; | 404 | goto found; |
404 | 405 | ||
405 | switch (PTR_ERR(key)) { | 406 | switch (PTR_ERR(key_ref)) { |
406 | case -EAGAIN: /* no key */ | 407 | case -EAGAIN: /* no key */ |
407 | if (ret) | 408 | if (ret) |
408 | break; | 409 | break; |
409 | case -ENOKEY: /* negative key */ | 410 | case -ENOKEY: /* negative key */ |
410 | ret = key; | 411 | ret = key_ref; |
411 | break; | 412 | break; |
412 | default: | 413 | default: |
413 | err = key; | 414 | err = key_ref; |
414 | break; | 415 | break; |
415 | } | 416 | } |
416 | } | 417 | } |
417 | 418 | ||
418 | /* search the process keyring second */ | 419 | /* search the process keyring second */ |
419 | if (context->signal->process_keyring) { | 420 | if (context->signal->process_keyring) { |
420 | key = keyring_search_aux(context->signal->process_keyring, | 421 | key_ref = keyring_search_aux( |
421 | context, type, description, match); | 422 | make_key_ref(context->signal->process_keyring, 1), |
422 | if (!IS_ERR(key)) | 423 | context, type, description, match); |
424 | if (!IS_ERR(key_ref)) | ||
423 | goto found; | 425 | goto found; |
424 | 426 | ||
425 | switch (PTR_ERR(key)) { | 427 | switch (PTR_ERR(key_ref)) { |
426 | case -EAGAIN: /* no key */ | 428 | case -EAGAIN: /* no key */ |
427 | if (ret) | 429 | if (ret) |
428 | break; | 430 | break; |
429 | case -ENOKEY: /* negative key */ | 431 | case -ENOKEY: /* negative key */ |
430 | ret = key; | 432 | ret = key_ref; |
431 | break; | 433 | break; |
432 | default: | 434 | default: |
433 | err = key; | 435 | err = key_ref; |
434 | break; | 436 | break; |
435 | } | 437 | } |
436 | } | 438 | } |
@@ -438,23 +440,25 @@ struct key *search_process_keyrings(struct key_type *type, | |||
438 | /* search the session keyring */ | 440 | /* search the session keyring */ |
439 | if (context->signal->session_keyring) { | 441 | if (context->signal->session_keyring) { |
440 | rcu_read_lock(); | 442 | rcu_read_lock(); |
441 | key = keyring_search_aux( | 443 | key_ref = keyring_search_aux( |
442 | rcu_dereference(context->signal->session_keyring), | 444 | make_key_ref(rcu_dereference( |
445 | context->signal->session_keyring), | ||
446 | 1), | ||
443 | context, type, description, match); | 447 | context, type, description, match); |
444 | rcu_read_unlock(); | 448 | rcu_read_unlock(); |
445 | 449 | ||
446 | if (!IS_ERR(key)) | 450 | if (!IS_ERR(key_ref)) |
447 | goto found; | 451 | goto found; |
448 | 452 | ||
449 | switch (PTR_ERR(key)) { | 453 | switch (PTR_ERR(key_ref)) { |
450 | case -EAGAIN: /* no key */ | 454 | case -EAGAIN: /* no key */ |
451 | if (ret) | 455 | if (ret) |
452 | break; | 456 | break; |
453 | case -ENOKEY: /* negative key */ | 457 | case -ENOKEY: /* negative key */ |
454 | ret = key; | 458 | ret = key_ref; |
455 | break; | 459 | break; |
456 | default: | 460 | default: |
457 | err = key; | 461 | err = key_ref; |
458 | break; | 462 | break; |
459 | } | 463 | } |
460 | 464 | ||
@@ -465,51 +469,54 @@ struct key *search_process_keyrings(struct key_type *type, | |||
465 | goto no_key; | 469 | goto no_key; |
466 | 470 | ||
467 | rcu_read_lock(); | 471 | rcu_read_lock(); |
468 | instkey = __keyring_search_one( | 472 | instkey_ref = __keyring_search_one( |
469 | rcu_dereference(context->signal->session_keyring), | 473 | make_key_ref(rcu_dereference( |
474 | context->signal->session_keyring), | ||
475 | 1), | ||
470 | &key_type_request_key_auth, NULL, 0); | 476 | &key_type_request_key_auth, NULL, 0); |
471 | rcu_read_unlock(); | 477 | rcu_read_unlock(); |
472 | 478 | ||
473 | if (IS_ERR(instkey)) | 479 | if (IS_ERR(instkey_ref)) |
474 | goto no_key; | 480 | goto no_key; |
475 | 481 | ||
476 | rka = instkey->payload.data; | 482 | rka = key_ref_to_ptr(instkey_ref)->payload.data; |
477 | 483 | ||
478 | key = search_process_keyrings(type, description, match, | 484 | key_ref = search_process_keyrings(type, description, match, |
479 | rka->context); | 485 | rka->context); |
480 | key_put(instkey); | 486 | key_ref_put(instkey_ref); |
481 | 487 | ||
482 | if (!IS_ERR(key)) | 488 | if (!IS_ERR(key_ref)) |
483 | goto found; | 489 | goto found; |
484 | 490 | ||
485 | switch (PTR_ERR(key)) { | 491 | switch (PTR_ERR(key_ref)) { |
486 | case -EAGAIN: /* no key */ | 492 | case -EAGAIN: /* no key */ |
487 | if (ret) | 493 | if (ret) |
488 | break; | 494 | break; |
489 | case -ENOKEY: /* negative key */ | 495 | case -ENOKEY: /* negative key */ |
490 | ret = key; | 496 | ret = key_ref; |
491 | break; | 497 | break; |
492 | default: | 498 | default: |
493 | err = key; | 499 | err = key_ref; |
494 | break; | 500 | break; |
495 | } | 501 | } |
496 | } | 502 | } |
497 | /* or search the user-session keyring */ | 503 | /* or search the user-session keyring */ |
498 | else { | 504 | else { |
499 | key = keyring_search_aux(context->user->session_keyring, | 505 | key_ref = keyring_search_aux( |
500 | context, type, description, match); | 506 | make_key_ref(context->user->session_keyring, 1), |
501 | if (!IS_ERR(key)) | 507 | context, type, description, match); |
508 | if (!IS_ERR(key_ref)) | ||
502 | goto found; | 509 | goto found; |
503 | 510 | ||
504 | switch (PTR_ERR(key)) { | 511 | switch (PTR_ERR(key_ref)) { |
505 | case -EAGAIN: /* no key */ | 512 | case -EAGAIN: /* no key */ |
506 | if (ret) | 513 | if (ret) |
507 | break; | 514 | break; |
508 | case -ENOKEY: /* negative key */ | 515 | case -ENOKEY: /* negative key */ |
509 | ret = key; | 516 | ret = key_ref; |
510 | break; | 517 | break; |
511 | default: | 518 | default: |
512 | err = key; | 519 | err = key_ref; |
513 | break; | 520 | break; |
514 | } | 521 | } |
515 | } | 522 | } |
@@ -517,29 +524,40 @@ struct key *search_process_keyrings(struct key_type *type, | |||
517 | 524 | ||
518 | no_key: | 525 | no_key: |
519 | /* no key - decide on the error we're going to go for */ | 526 | /* no key - decide on the error we're going to go for */ |
520 | key = ret ? ret : err; | 527 | key_ref = ret ? ret : err; |
521 | 528 | ||
522 | found: | 529 | found: |
523 | return key; | 530 | return key_ref; |
524 | 531 | ||
525 | } /* end search_process_keyrings() */ | 532 | } /* end search_process_keyrings() */ |
526 | 533 | ||
527 | /*****************************************************************************/ | 534 | /*****************************************************************************/ |
528 | /* | 535 | /* |
536 | * see if the key we're looking at is the target key | ||
537 | */ | ||
538 | static int lookup_user_key_possessed(const struct key *key, const void *target) | ||
539 | { | ||
540 | return key == target; | ||
541 | |||
542 | } /* end lookup_user_key_possessed() */ | ||
543 | |||
544 | /*****************************************************************************/ | ||
545 | /* | ||
529 | * lookup a key given a key ID from userspace with a given permissions mask | 546 | * lookup a key given a key ID from userspace with a given permissions mask |
530 | * - don't create special keyrings unless so requested | 547 | * - don't create special keyrings unless so requested |
531 | * - partially constructed keys aren't found unless requested | 548 | * - partially constructed keys aren't found unless requested |
532 | */ | 549 | */ |
533 | struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | 550 | key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, |
534 | int create, int partial, key_perm_t perm) | 551 | int create, int partial, key_perm_t perm) |
535 | { | 552 | { |
553 | key_ref_t key_ref, skey_ref; | ||
536 | struct key *key; | 554 | struct key *key; |
537 | int ret; | 555 | int ret; |
538 | 556 | ||
539 | if (!context) | 557 | if (!context) |
540 | context = current; | 558 | context = current; |
541 | 559 | ||
542 | key = ERR_PTR(-ENOKEY); | 560 | key_ref = ERR_PTR(-ENOKEY); |
543 | 561 | ||
544 | switch (id) { | 562 | switch (id) { |
545 | case KEY_SPEC_THREAD_KEYRING: | 563 | case KEY_SPEC_THREAD_KEYRING: |
@@ -556,6 +574,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
556 | 574 | ||
557 | key = context->thread_keyring; | 575 | key = context->thread_keyring; |
558 | atomic_inc(&key->usage); | 576 | atomic_inc(&key->usage); |
577 | key_ref = make_key_ref(key, 1); | ||
559 | break; | 578 | break; |
560 | 579 | ||
561 | case KEY_SPEC_PROCESS_KEYRING: | 580 | case KEY_SPEC_PROCESS_KEYRING: |
@@ -572,6 +591,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
572 | 591 | ||
573 | key = context->signal->process_keyring; | 592 | key = context->signal->process_keyring; |
574 | atomic_inc(&key->usage); | 593 | atomic_inc(&key->usage); |
594 | key_ref = make_key_ref(key, 1); | ||
575 | break; | 595 | break; |
576 | 596 | ||
577 | case KEY_SPEC_SESSION_KEYRING: | 597 | case KEY_SPEC_SESSION_KEYRING: |
@@ -579,7 +599,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
579 | /* always install a session keyring upon access if one | 599 | /* always install a session keyring upon access if one |
580 | * doesn't exist yet */ | 600 | * doesn't exist yet */ |
581 | ret = install_session_keyring( | 601 | ret = install_session_keyring( |
582 | context, context->user->session_keyring); | 602 | context, context->user->session_keyring); |
583 | if (ret < 0) | 603 | if (ret < 0) |
584 | goto error; | 604 | goto error; |
585 | } | 605 | } |
@@ -588,16 +608,19 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
588 | key = rcu_dereference(context->signal->session_keyring); | 608 | key = rcu_dereference(context->signal->session_keyring); |
589 | atomic_inc(&key->usage); | 609 | atomic_inc(&key->usage); |
590 | rcu_read_unlock(); | 610 | rcu_read_unlock(); |
611 | key_ref = make_key_ref(key, 1); | ||
591 | break; | 612 | break; |
592 | 613 | ||
593 | case KEY_SPEC_USER_KEYRING: | 614 | case KEY_SPEC_USER_KEYRING: |
594 | key = context->user->uid_keyring; | 615 | key = context->user->uid_keyring; |
595 | atomic_inc(&key->usage); | 616 | atomic_inc(&key->usage); |
617 | key_ref = make_key_ref(key, 1); | ||
596 | break; | 618 | break; |
597 | 619 | ||
598 | case KEY_SPEC_USER_SESSION_KEYRING: | 620 | case KEY_SPEC_USER_SESSION_KEYRING: |
599 | key = context->user->session_keyring; | 621 | key = context->user->session_keyring; |
600 | atomic_inc(&key->usage); | 622 | atomic_inc(&key->usage); |
623 | key_ref = make_key_ref(key, 1); | ||
601 | break; | 624 | break; |
602 | 625 | ||
603 | case KEY_SPEC_GROUP_KEYRING: | 626 | case KEY_SPEC_GROUP_KEYRING: |
@@ -606,13 +629,28 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
606 | goto error; | 629 | goto error; |
607 | 630 | ||
608 | default: | 631 | default: |
609 | key = ERR_PTR(-EINVAL); | 632 | key_ref = ERR_PTR(-EINVAL); |
610 | if (id < 1) | 633 | if (id < 1) |
611 | goto error; | 634 | goto error; |
612 | 635 | ||
613 | key = key_lookup(id); | 636 | key = key_lookup(id); |
614 | if (IS_ERR(key)) | 637 | if (IS_ERR(key)) { |
638 | key_ref = ERR_PTR(PTR_ERR(key)); | ||
615 | goto error; | 639 | goto error; |
640 | } | ||
641 | |||
642 | key_ref = make_key_ref(key, 0); | ||
643 | |||
644 | /* check to see if we possess the key */ | ||
645 | skey_ref = search_process_keyrings(key->type, key, | ||
646 | lookup_user_key_possessed, | ||
647 | current); | ||
648 | |||
649 | if (!IS_ERR(skey_ref)) { | ||
650 | key_put(key); | ||
651 | key_ref = skey_ref; | ||
652 | } | ||
653 | |||
616 | break; | 654 | break; |
617 | } | 655 | } |
618 | 656 | ||
@@ -630,15 +668,15 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, | |||
630 | /* check the permissions */ | 668 | /* check the permissions */ |
631 | ret = -EACCES; | 669 | ret = -EACCES; |
632 | 670 | ||
633 | if (!key_task_permission(key, context, perm)) | 671 | if (!key_task_permission(key_ref, context, perm)) |
634 | goto invalid_key; | 672 | goto invalid_key; |
635 | 673 | ||
636 | error: | 674 | error: |
637 | return key; | 675 | return key_ref; |
638 | 676 | ||
639 | invalid_key: | 677 | invalid_key: |
640 | key_put(key); | 678 | key_ref_put(key_ref); |
641 | key = ERR_PTR(ret); | 679 | key_ref = ERR_PTR(ret); |
642 | goto error; | 680 | goto error; |
643 | 681 | ||
644 | } /* end lookup_user_key() */ | 682 | } /* end lookup_user_key() */ |
@@ -694,9 +732,9 @@ long join_session_keyring(const char *name) | |||
694 | ret = keyring->serial; | 732 | ret = keyring->serial; |
695 | key_put(keyring); | 733 | key_put(keyring); |
696 | 734 | ||
697 | error2: | 735 | error2: |
698 | up(&key_session_sem); | 736 | up(&key_session_sem); |
699 | error: | 737 | error: |
700 | return ret; | 738 | return ret; |
701 | 739 | ||
702 | } /* end join_session_keyring() */ | 740 | } /* end join_session_keyring() */ |