aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/request_key.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-10-02 14:24:29 -0400
committerDavid Howells <dhowells@redhat.com>2012-10-02 14:24:29 -0400
commit3a50597de8635cd05133bd12c95681c82fe7b878 (patch)
treed81c3e46dcef80fbaf84fdf1e8f43676625bab8e /security/keys/request_key.c
parenta84a921978b7d56e0e4b87ffaca6367429b4d8ff (diff)
KEYS: Make the session and process keyrings per-thread
Make the session keyring per-thread rather than per-process, but still inherited from the parent thread to solve a problem with PAM and gdm. The problem is that join_session_keyring() will reject attempts to change the session keyring of a multithreaded program but gdm is now multithreaded before it gets to the point of starting PAM and running pam_keyinit to create the session keyring. See: https://bugs.freedesktop.org/show_bug.cgi?id=49211 The reason that join_session_keyring() will only change the session keyring under a single-threaded environment is that it's hard to alter the other thread's credentials to effect the change in a multi-threaded program. The problems are such as: (1) How to prevent two threads both running join_session_keyring() from racing. (2) Another thread's credentials may not be modified directly by this process. (3) The number of threads is uncertain whilst we're not holding the appropriate spinlock, making preallocation slightly tricky. (4) We could use TIF_NOTIFY_RESUME and key_replace_session_keyring() to get another thread to replace its keyring, but that means preallocating for each thread. A reasonable way around this is to make the session keyring per-thread rather than per-process and just document that if you want a common session keyring, you must get it before you spawn any threads - which is the current situation anyway. Whilst we're at it, we can the process keyring behave in the same way. This means we can clean up some of the ickyness in the creds code. Basically, after this patch, the session, process and thread keyrings are about inheritance rules only and not about sharing changes of keyring. Reported-by: Mantas M. <grawity@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Ray Strode <rstrode@redhat.com>
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r--security/keys/request_key.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 000e75017520..275c4f9e4b8c 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -150,12 +150,12 @@ static int call_sbin_request_key(struct key_construction *cons,
150 cred->thread_keyring ? cred->thread_keyring->serial : 0); 150 cred->thread_keyring ? cred->thread_keyring->serial : 0);
151 151
152 prkey = 0; 152 prkey = 0;
153 if (cred->tgcred->process_keyring) 153 if (cred->process_keyring)
154 prkey = cred->tgcred->process_keyring->serial; 154 prkey = cred->process_keyring->serial;
155 sprintf(keyring_str[1], "%d", prkey); 155 sprintf(keyring_str[1], "%d", prkey);
156 156
157 rcu_read_lock(); 157 rcu_read_lock();
158 session = rcu_dereference(cred->tgcred->session_keyring); 158 session = rcu_dereference(cred->session_keyring);
159 if (!session) 159 if (!session)
160 session = cred->user->session_keyring; 160 session = cred->user->session_keyring;
161 sskey = session->serial; 161 sskey = session->serial;
@@ -297,14 +297,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
297 break; 297 break;
298 298
299 case KEY_REQKEY_DEFL_PROCESS_KEYRING: 299 case KEY_REQKEY_DEFL_PROCESS_KEYRING:
300 dest_keyring = key_get(cred->tgcred->process_keyring); 300 dest_keyring = key_get(cred->process_keyring);
301 if (dest_keyring) 301 if (dest_keyring)
302 break; 302 break;
303 303
304 case KEY_REQKEY_DEFL_SESSION_KEYRING: 304 case KEY_REQKEY_DEFL_SESSION_KEYRING:
305 rcu_read_lock(); 305 rcu_read_lock();
306 dest_keyring = key_get( 306 dest_keyring = key_get(
307 rcu_dereference(cred->tgcred->session_keyring)); 307 rcu_dereference(cred->session_keyring));
308 rcu_read_unlock(); 308 rcu_read_unlock();
309 309
310 if (dest_keyring) 310 if (dest_keyring)