diff options
| author | David Howells <dhowells@redhat.com> | 2008-04-29 04:01:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:17 -0400 |
| commit | 69664cf16af4f31cd54d77948a4baf9c7e0ca7b9 (patch) | |
| tree | 3ff4ecae21c140a2beed25cfa9e55b788f9814ac /security | |
| parent | 6b79ccb5144f9ffb4d4596c23e7570238dd12abc (diff) | |
keys: don't generate user and user session keyrings unless they're accessed
Don't generate the per-UID user and user session keyrings unless they're
explicitly accessed. This solves a problem during a login process whereby
set*uid() is called before the SELinux PAM module, resulting in the per-UID
keyrings having the wrong security labels.
This also cures the problem of multiple per-UID keyrings sometimes appearing
due to PAM modules (including pam_keyinit) setuiding and causing user_structs
to come into and go out of existence whilst the session keyring pins the user
keyring. This is achieved by first searching for extant per-UID keyrings
before inventing new ones.
The serial bound argument is also dropped from find_keyring_by_name() as it's
not currently made use of (setting it to 0 disables the feature).
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: <kwc@citi.umich.edu>
Cc: <arunsr@cse.iitk.ac.in>
Cc: <dwalsh@redhat.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: James Morris <jmorris@namei.org>
Cc: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
| -rw-r--r-- | security/keys/internal.h | 4 | ||||
| -rw-r--r-- | security/keys/key.c | 45 | ||||
| -rw-r--r-- | security/keys/keyring.c | 19 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 142 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 8 |
5 files changed, 92 insertions, 126 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index 6361d3736dbc..2ab38854c47f 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -77,8 +77,6 @@ extern struct mutex key_construction_mutex; | |||
| 77 | extern wait_queue_head_t request_key_conswq; | 77 | extern wait_queue_head_t request_key_conswq; |
| 78 | 78 | ||
| 79 | 79 | ||
| 80 | extern void keyring_publish_name(struct key *keyring); | ||
| 81 | |||
| 82 | extern int __key_link(struct key *keyring, struct key *key); | 80 | extern int __key_link(struct key *keyring, struct key *key); |
| 83 | 81 | ||
| 84 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, | 82 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
| @@ -102,7 +100,7 @@ extern key_ref_t search_process_keyrings(struct key_type *type, | |||
| 102 | key_match_func_t match, | 100 | key_match_func_t match, |
| 103 | struct task_struct *tsk); | 101 | struct task_struct *tsk); |
| 104 | 102 | ||
| 105 | extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); | 103 | extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); |
| 106 | 104 | ||
| 107 | extern int install_thread_keyring(struct task_struct *tsk); | 105 | extern int install_thread_keyring(struct task_struct *tsk); |
| 108 | extern int install_process_keyring(struct task_struct *tsk); | 106 | extern int install_process_keyring(struct task_struct *tsk); |
diff --git a/security/keys/key.c b/security/keys/key.c index d98c61953be6..46f125aa7fa3 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* Basic authentication token and access key management | 1 | /* Basic authentication token and access key management |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -139,36 +139,6 @@ void key_user_put(struct key_user *user) | |||
| 139 | 139 | ||
| 140 | /*****************************************************************************/ | 140 | /*****************************************************************************/ |
| 141 | /* | 141 | /* |
| 142 | * insert a key with a fixed serial number | ||
| 143 | */ | ||
| 144 | static void __init __key_insert_serial(struct key *key) | ||
| 145 | { | ||
| 146 | struct rb_node *parent, **p; | ||
| 147 | struct key *xkey; | ||
| 148 | |||
| 149 | parent = NULL; | ||
| 150 | p = &key_serial_tree.rb_node; | ||
| 151 | |||
| 152 | while (*p) { | ||
| 153 | parent = *p; | ||
| 154 | xkey = rb_entry(parent, struct key, serial_node); | ||
| 155 | |||
| 156 | if (key->serial < xkey->serial) | ||
| 157 | p = &(*p)->rb_left; | ||
| 158 | else if (key->serial > xkey->serial) | ||
| 159 | p = &(*p)->rb_right; | ||
| 160 | else | ||
| 161 | BUG(); | ||
| 162 | } | ||
| 163 | |||
| 164 | /* we've found a suitable hole - arrange for this key to occupy it */ | ||
| 165 | rb_link_node(&key->serial_node, parent, p); | ||
| 166 | rb_insert_color(&key->serial_node, &key_serial_tree); | ||
| 167 | |||
| 168 | } /* end __key_insert_serial() */ | ||
| 169 | |||
| 170 | /*****************************************************************************/ | ||
| 171 | /* | ||
| 172 | * assign a key the next unique serial number | 142 | * assign a key the next unique serial number |
| 173 | * - these are assigned randomly to avoid security issues through covert | 143 | * - these are assigned randomly to avoid security issues through covert |
| 174 | * channel problems | 144 | * channel problems |
| @@ -1020,17 +990,4 @@ void __init key_init(void) | |||
| 1020 | rb_insert_color(&root_key_user.node, | 990 | rb_insert_color(&root_key_user.node, |
| 1021 | &key_user_tree); | 991 | &key_user_tree); |
| 1022 | 992 | ||
| 1023 | /* record root's user standard keyrings */ | ||
| 1024 | key_check(&root_user_keyring); | ||
| 1025 | key_check(&root_session_keyring); | ||
| 1026 | |||
| 1027 | __key_insert_serial(&root_user_keyring); | ||
| 1028 | __key_insert_serial(&root_session_keyring); | ||
| 1029 | |||
| 1030 | keyring_publish_name(&root_user_keyring); | ||
| 1031 | keyring_publish_name(&root_session_keyring); | ||
| 1032 | |||
| 1033 | /* link the two root keyrings together */ | ||
| 1034 | key_link(&root_session_keyring, &root_user_keyring); | ||
| 1035 | |||
| 1036 | } /* end key_init() */ | 993 | } /* end key_init() */ |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 70f0c313c888..a9ab8affc092 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* keyring.c: keyring handling | 1 | /* Keyring handling |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -79,7 +79,7 @@ static DECLARE_RWSEM(keyring_serialise_link_sem); | |||
| 79 | * publish the name of a keyring so that it can be found by name (if it has | 79 | * publish the name of a keyring so that it can be found by name (if it has |
| 80 | * one) | 80 | * one) |
| 81 | */ | 81 | */ |
| 82 | void keyring_publish_name(struct key *keyring) | 82 | static void keyring_publish_name(struct key *keyring) |
| 83 | { | 83 | { |
| 84 | int bucket; | 84 | int bucket; |
| 85 | 85 | ||
| @@ -516,10 +516,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
| 516 | /* | 516 | /* |
| 517 | * find a keyring with the specified name | 517 | * find a keyring with the specified name |
| 518 | * - all named keyrings are searched | 518 | * - all named keyrings are searched |
| 519 | * - only find keyrings with search permission for the process | 519 | * - normally only finds keyrings with search permission for the current process |
| 520 | * - only find keyrings with a serial number greater than the one specified | ||
| 521 | */ | 520 | */ |
| 522 | struct key *find_keyring_by_name(const char *name, key_serial_t bound) | 521 | struct key *find_keyring_by_name(const char *name, bool skip_perm_check) |
| 523 | { | 522 | { |
| 524 | struct key *keyring; | 523 | struct key *keyring; |
| 525 | int bucket; | 524 | int bucket; |
| @@ -545,15 +544,11 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
| 545 | if (strcmp(keyring->description, name) != 0) | 544 | if (strcmp(keyring->description, name) != 0) |
| 546 | continue; | 545 | continue; |
| 547 | 546 | ||
| 548 | if (key_permission(make_key_ref(keyring, 0), | 547 | if (!skip_perm_check && |
| 548 | key_permission(make_key_ref(keyring, 0), | ||
| 549 | KEY_SEARCH) < 0) | 549 | KEY_SEARCH) < 0) |
| 550 | continue; | 550 | continue; |
| 551 | 551 | ||
| 552 | /* found a potential candidate, but we still need to | ||
| 553 | * check the serial number */ | ||
| 554 | if (keyring->serial <= bound) | ||
| 555 | continue; | ||
| 556 | |||
| 557 | /* we've got a match */ | 552 | /* we've got a match */ |
| 558 | atomic_inc(&keyring->usage); | 553 | atomic_inc(&keyring->usage); |
| 559 | read_unlock(&keyring_name_lock); | 554 | read_unlock(&keyring_name_lock); |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index c886a2bb792a..5be6d018759a 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* process_keys.c: management of a process's keyrings | 1 | /* Management of a process's keyrings |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -23,6 +23,9 @@ | |||
| 23 | /* session keyring create vs join semaphore */ | 23 | /* session keyring create vs join semaphore */ |
| 24 | static DEFINE_MUTEX(key_session_mutex); | 24 | static DEFINE_MUTEX(key_session_mutex); |
| 25 | 25 | ||
| 26 | /* user keyring creation semaphore */ | ||
| 27 | static DEFINE_MUTEX(key_user_keyring_mutex); | ||
| 28 | |||
| 26 | /* the root user's tracking struct */ | 29 | /* the root user's tracking struct */ |
| 27 | struct key_user root_key_user = { | 30 | struct key_user root_key_user = { |
| 28 | .usage = ATOMIC_INIT(3), | 31 | .usage = ATOMIC_INIT(3), |
| @@ -33,78 +36,84 @@ struct key_user root_key_user = { | |||
| 33 | .uid = 0, | 36 | .uid = 0, |
| 34 | }; | 37 | }; |
| 35 | 38 | ||
| 36 | /* the root user's UID keyring */ | ||
| 37 | struct key root_user_keyring = { | ||
| 38 | .usage = ATOMIC_INIT(1), | ||
| 39 | .serial = 2, | ||
| 40 | .type = &key_type_keyring, | ||
| 41 | .user = &root_key_user, | ||
| 42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | ||
| 43 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
| 44 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
| 45 | .description = "_uid.0", | ||
| 46 | #ifdef KEY_DEBUGGING | ||
| 47 | .magic = KEY_DEBUG_MAGIC, | ||
| 48 | #endif | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* the root user's default session keyring */ | ||
| 52 | struct key root_session_keyring = { | ||
| 53 | .usage = ATOMIC_INIT(1), | ||
| 54 | .serial = 1, | ||
| 55 | .type = &key_type_keyring, | ||
| 56 | .user = &root_key_user, | ||
| 57 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | ||
| 58 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
| 59 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
| 60 | .description = "_uid_ses.0", | ||
| 61 | #ifdef KEY_DEBUGGING | ||
| 62 | .magic = KEY_DEBUG_MAGIC, | ||
| 63 | #endif | ||
| 64 | }; | ||
| 65 | |||
| 66 | /*****************************************************************************/ | 39 | /*****************************************************************************/ |
| 67 | /* | 40 | /* |
| 68 | * allocate the keyrings to be associated with a UID | 41 | * install user and user session keyrings for a particular UID |
| 69 | */ | 42 | */ |
| 70 | int alloc_uid_keyring(struct user_struct *user, | 43 | static int install_user_keyrings(struct task_struct *tsk) |
| 71 | struct task_struct *ctx) | ||
| 72 | { | 44 | { |
| 45 | struct user_struct *user = tsk->user; | ||
| 73 | struct key *uid_keyring, *session_keyring; | 46 | struct key *uid_keyring, *session_keyring; |
| 74 | char buf[20]; | 47 | char buf[20]; |
| 75 | int ret; | 48 | int ret; |
| 76 | 49 | ||
| 77 | /* concoct a default session keyring */ | 50 | kenter("%p{%u}", user, user->uid); |
| 78 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
| 79 | 51 | ||
| 80 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 52 | if (user->uid_keyring) { |
| 81 | KEY_ALLOC_IN_QUOTA, NULL); | 53 | kleave(" = 0 [exist]"); |
| 82 | if (IS_ERR(session_keyring)) { | 54 | return 0; |
| 83 | ret = PTR_ERR(session_keyring); | ||
| 84 | goto error; | ||
| 85 | } | 55 | } |
| 86 | 56 | ||
| 87 | /* and a UID specific keyring, pointed to by the default session | 57 | mutex_lock(&key_user_keyring_mutex); |
| 88 | * keyring */ | 58 | ret = 0; |
| 89 | sprintf(buf, "_uid.%u", user->uid); | ||
| 90 | 59 | ||
| 91 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 60 | if (!user->uid_keyring) { |
| 92 | KEY_ALLOC_IN_QUOTA, session_keyring); | 61 | /* get the UID-specific keyring |
| 93 | if (IS_ERR(uid_keyring)) { | 62 | * - there may be one in existence already as it may have been |
| 94 | key_put(session_keyring); | 63 | * pinned by a session, but the user_struct pointing to it |
| 95 | ret = PTR_ERR(uid_keyring); | 64 | * may have been destroyed by setuid */ |
| 96 | goto error; | 65 | sprintf(buf, "_uid.%u", user->uid); |
| 66 | |||
| 67 | uid_keyring = find_keyring_by_name(buf, true); | ||
| 68 | if (IS_ERR(uid_keyring)) { | ||
| 69 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | ||
| 70 | tsk, KEY_ALLOC_IN_QUOTA, | ||
| 71 | NULL); | ||
| 72 | if (IS_ERR(uid_keyring)) { | ||
| 73 | ret = PTR_ERR(uid_keyring); | ||
| 74 | goto error; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /* get a default session keyring (which might also exist | ||
| 79 | * already) */ | ||
| 80 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
| 81 | |||
| 82 | session_keyring = find_keyring_by_name(buf, true); | ||
| 83 | if (IS_ERR(session_keyring)) { | ||
| 84 | session_keyring = | ||
| 85 | keyring_alloc(buf, user->uid, (gid_t) -1, | ||
| 86 | tsk, KEY_ALLOC_IN_QUOTA, NULL); | ||
| 87 | if (IS_ERR(session_keyring)) { | ||
| 88 | ret = PTR_ERR(session_keyring); | ||
| 89 | goto error_release; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* we install a link from the user session keyring to | ||
| 93 | * the user keyring */ | ||
| 94 | ret = key_link(session_keyring, uid_keyring); | ||
| 95 | if (ret < 0) | ||
| 96 | goto error_release_both; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* install the keyrings */ | ||
| 100 | user->uid_keyring = uid_keyring; | ||
| 101 | user->session_keyring = session_keyring; | ||
| 97 | } | 102 | } |
| 98 | 103 | ||
| 99 | /* install the keyrings */ | 104 | mutex_unlock(&key_user_keyring_mutex); |
| 100 | user->uid_keyring = uid_keyring; | 105 | kleave(" = 0"); |
| 101 | user->session_keyring = session_keyring; | 106 | return 0; |
| 102 | ret = 0; | ||
| 103 | 107 | ||
| 108 | error_release_both: | ||
| 109 | key_put(session_keyring); | ||
| 110 | error_release: | ||
| 111 | key_put(uid_keyring); | ||
| 104 | error: | 112 | error: |
| 113 | mutex_unlock(&key_user_keyring_mutex); | ||
| 114 | kleave(" = %d", ret); | ||
| 105 | return ret; | 115 | return ret; |
| 106 | 116 | } | |
| 107 | } /* end alloc_uid_keyring() */ | ||
| 108 | 117 | ||
| 109 | /*****************************************************************************/ | 118 | /*****************************************************************************/ |
| 110 | /* | 119 | /* |
| @@ -481,7 +490,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
| 481 | } | 490 | } |
| 482 | } | 491 | } |
| 483 | /* or search the user-session keyring */ | 492 | /* or search the user-session keyring */ |
| 484 | else { | 493 | else if (context->user->session_keyring) { |
| 485 | key_ref = keyring_search_aux( | 494 | key_ref = keyring_search_aux( |
| 486 | make_key_ref(context->user->session_keyring, 1), | 495 | make_key_ref(context->user->session_keyring, 1), |
| 487 | context, type, description, match); | 496 | context, type, description, match); |
| @@ -614,6 +623,9 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
| 614 | if (!context->signal->session_keyring) { | 623 | if (!context->signal->session_keyring) { |
| 615 | /* always install a session keyring upon access if one | 624 | /* always install a session keyring upon access if one |
| 616 | * doesn't exist yet */ | 625 | * doesn't exist yet */ |
| 626 | ret = install_user_keyrings(context); | ||
| 627 | if (ret < 0) | ||
| 628 | goto error; | ||
| 617 | ret = install_session_keyring( | 629 | ret = install_session_keyring( |
| 618 | context, context->user->session_keyring); | 630 | context, context->user->session_keyring); |
| 619 | if (ret < 0) | 631 | if (ret < 0) |
| @@ -628,12 +640,24 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
| 628 | break; | 640 | break; |
| 629 | 641 | ||
| 630 | case KEY_SPEC_USER_KEYRING: | 642 | case KEY_SPEC_USER_KEYRING: |
| 643 | if (!context->user->uid_keyring) { | ||
| 644 | ret = install_user_keyrings(context); | ||
| 645 | if (ret < 0) | ||
| 646 | goto error; | ||
| 647 | } | ||
| 648 | |||
| 631 | key = context->user->uid_keyring; | 649 | key = context->user->uid_keyring; |
| 632 | atomic_inc(&key->usage); | 650 | atomic_inc(&key->usage); |
| 633 | key_ref = make_key_ref(key, 1); | 651 | key_ref = make_key_ref(key, 1); |
| 634 | break; | 652 | break; |
| 635 | 653 | ||
| 636 | case KEY_SPEC_USER_SESSION_KEYRING: | 654 | case KEY_SPEC_USER_SESSION_KEYRING: |
| 655 | if (!context->user->session_keyring) { | ||
| 656 | ret = install_user_keyrings(context); | ||
| 657 | if (ret < 0) | ||
| 658 | goto error; | ||
| 659 | } | ||
| 660 | |||
| 637 | key = context->user->session_keyring; | 661 | key = context->user->session_keyring; |
| 638 | atomic_inc(&key->usage); | 662 | atomic_inc(&key->usage); |
| 639 | key_ref = make_key_ref(key, 1); | 663 | key_ref = make_key_ref(key, 1); |
| @@ -744,7 +768,7 @@ long join_session_keyring(const char *name) | |||
| 744 | mutex_lock(&key_session_mutex); | 768 | mutex_lock(&key_session_mutex); |
| 745 | 769 | ||
| 746 | /* look for an existing keyring of this name */ | 770 | /* look for an existing keyring of this name */ |
| 747 | keyring = find_keyring_by_name(name, 0); | 771 | keyring = find_keyring_by_name(name, false); |
| 748 | if (PTR_ERR(keyring) == -ENOKEY) { | 772 | if (PTR_ERR(keyring) == -ENOKEY) { |
| 749 | /* not found - try and create a new one */ | 773 | /* not found - try and create a new one */ |
| 750 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, | 774 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 838d1e5e63a1..4e4de98941ae 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -5551,14 +5551,6 @@ static __init int selinux_init(void) | |||
| 5551 | else | 5551 | else |
| 5552 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); | 5552 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); |
| 5553 | 5553 | ||
| 5554 | #ifdef CONFIG_KEYS | ||
| 5555 | /* Add security information to initial keyrings */ | ||
| 5556 | selinux_key_alloc(&root_user_keyring, current, | ||
| 5557 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 5558 | selinux_key_alloc(&root_session_keyring, current, | ||
| 5559 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 5560 | #endif | ||
| 5561 | |||
| 5562 | return 0; | 5554 | return 0; |
| 5563 | } | 5555 | } |
| 5564 | 5556 | ||
