aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-04-29 04:01:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:17 -0400
commit69664cf16af4f31cd54d77948a4baf9c7e0ca7b9 (patch)
tree3ff4ecae21c140a2beed25cfa9e55b788f9814ac /security/keys
parent6b79ccb5144f9ffb4d4596c23e7570238dd12abc (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/keys')
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/key.c45
-rw-r--r--security/keys/keyring.c19
-rw-r--r--security/keys/process_keys.c142
4 files changed, 92 insertions, 118 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;
77extern wait_queue_head_t request_key_conswq; 77extern wait_queue_head_t request_key_conswq;
78 78
79 79
80extern void keyring_publish_name(struct key *keyring);
81
82extern int __key_link(struct key *keyring, struct key *key); 80extern int __key_link(struct key *keyring, struct key *key);
83 81
84extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, 82extern 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
105extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); 103extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
106 104
107extern int install_thread_keyring(struct task_struct *tsk); 105extern int install_thread_keyring(struct task_struct *tsk);
108extern int install_process_keyring(struct task_struct *tsk); 106extern 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 */
144static 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 */
82void keyring_publish_name(struct key *keyring) 82static 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 */
522struct key *find_keyring_by_name(const char *name, key_serial_t bound) 521struct 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 */
24static DEFINE_MUTEX(key_session_mutex); 24static DEFINE_MUTEX(key_session_mutex);
25 25
26/* user keyring creation semaphore */
27static DEFINE_MUTEX(key_user_keyring_mutex);
28
26/* the root user's tracking struct */ 29/* the root user's tracking struct */
27struct key_user root_key_user = { 30struct 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 */
37struct 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 */
52struct 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 */
70int alloc_uid_keyring(struct user_struct *user, 43static 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
108error_release_both:
109 key_put(session_keyring);
110error_release:
111 key_put(uid_keyring);
104error: 112error:
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,