aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/keyctl.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/keyctl.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/keyctl.c')
-rw-r--r--security/keys/keyctl.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index a0d373f7681..65b38417c21 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1475,7 +1475,8 @@ long keyctl_session_to_parent(void)
1475 goto error_keyring; 1475 goto error_keyring;
1476 newwork = &cred->rcu; 1476 newwork = &cred->rcu;
1477 1477
1478 cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1478 cred->session_keyring = key_ref_to_ptr(keyring_r);
1479 keyring_r = NULL;
1479 init_task_work(newwork, key_change_session_keyring); 1480 init_task_work(newwork, key_change_session_keyring);
1480 1481
1481 me = current; 1482 me = current;
@@ -1500,7 +1501,7 @@ long keyctl_session_to_parent(void)
1500 mycred = current_cred(); 1501 mycred = current_cred();
1501 pcred = __task_cred(parent); 1502 pcred = __task_cred(parent);
1502 if (mycred == pcred || 1503 if (mycred == pcred ||
1503 mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { 1504 mycred->session_keyring == pcred->session_keyring) {
1504 ret = 0; 1505 ret = 0;
1505 goto unlock; 1506 goto unlock;
1506 } 1507 }
@@ -1516,9 +1517,9 @@ long keyctl_session_to_parent(void)
1516 goto unlock; 1517 goto unlock;
1517 1518
1518 /* the keyrings must have the same UID */ 1519 /* the keyrings must have the same UID */
1519 if ((pcred->tgcred->session_keyring && 1520 if ((pcred->session_keyring &&
1520 pcred->tgcred->session_keyring->uid != mycred->euid) || 1521 pcred->session_keyring->uid != mycred->euid) ||
1521 mycred->tgcred->session_keyring->uid != mycred->euid) 1522 mycred->session_keyring->uid != mycred->euid)
1522 goto unlock; 1523 goto unlock;
1523 1524
1524 /* cancel an already pending keyring replacement */ 1525 /* cancel an already pending keyring replacement */