aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cred.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:20 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:20 -0500
commitbb952bb98a7e479262c7eb25d5592545a3af147d (patch)
tree9a2158c07a22a5fbddcec412944d2e7534eecc8f /kernel/cred.c
parent275bb41e9d058fbb327e7642f077e1beaeac162e (diff)
CRED: Separate per-task-group keyrings from signal_struct
Separate per-task-group keyrings from signal_struct and dangle their anchor from the cred struct rather than the signal_struct. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: James Morris <jmorris@namei.org> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel/cred.c')
-rw-r--r--kernel/cred.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/kernel/cred.c b/kernel/cred.c
index 833244a7cb05..ac73e3617684 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -17,6 +17,17 @@
17#include <linux/security.h> 17#include <linux/security.h>
18 18
19/* 19/*
20 * The common credentials for the initial task's thread group
21 */
22#ifdef CONFIG_KEYS
23static struct thread_group_cred init_tgcred = {
24 .usage = ATOMIC_INIT(2),
25 .tgid = 0,
26 .lock = SPIN_LOCK_UNLOCKED,
27};
28#endif
29
30/*
20 * The initial credentials for the initial task 31 * The initial credentials for the initial task
21 */ 32 */
22struct cred init_cred = { 33struct cred init_cred = {
@@ -28,9 +39,42 @@ struct cred init_cred = {
28 .cap_bset = CAP_INIT_BSET, 39 .cap_bset = CAP_INIT_BSET,
29 .user = INIT_USER, 40 .user = INIT_USER,
30 .group_info = &init_groups, 41 .group_info = &init_groups,
42#ifdef CONFIG_KEYS
43 .tgcred = &init_tgcred,
44#endif
31}; 45};
32 46
33/* 47/*
48 * Dispose of the shared task group credentials
49 */
50#ifdef CONFIG_KEYS
51static void release_tgcred_rcu(struct rcu_head *rcu)
52{
53 struct thread_group_cred *tgcred =
54 container_of(rcu, struct thread_group_cred, rcu);
55
56 BUG_ON(atomic_read(&tgcred->usage) != 0);
57
58 key_put(tgcred->session_keyring);
59 key_put(tgcred->process_keyring);
60 kfree(tgcred);
61}
62#endif
63
64/*
65 * Release a set of thread group credentials.
66 */
67static void release_tgcred(struct cred *cred)
68{
69#ifdef CONFIG_KEYS
70 struct thread_group_cred *tgcred = cred->tgcred;
71
72 if (atomic_dec_and_test(&tgcred->usage))
73 call_rcu(&tgcred->rcu, release_tgcred_rcu);
74#endif
75}
76
77/*
34 * The RCU callback to actually dispose of a set of credentials 78 * The RCU callback to actually dispose of a set of credentials
35 */ 79 */
36static void put_cred_rcu(struct rcu_head *rcu) 80static void put_cred_rcu(struct rcu_head *rcu)
@@ -41,6 +85,7 @@ static void put_cred_rcu(struct rcu_head *rcu)
41 85
42 key_put(cred->thread_keyring); 86 key_put(cred->thread_keyring);
43 key_put(cred->request_key_auth); 87 key_put(cred->request_key_auth);
88 release_tgcred(cred);
44 put_group_info(cred->group_info); 89 put_group_info(cred->group_info);
45 free_uid(cred->user); 90 free_uid(cred->user);
46 security_cred_free(cred); 91 security_cred_free(cred);
@@ -71,12 +116,30 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
71 if (!pcred) 116 if (!pcred)
72 return -ENOMEM; 117 return -ENOMEM;
73 118
119#ifdef CONFIG_KEYS
120 if (clone_flags & CLONE_THREAD) {
121 atomic_inc(&pcred->tgcred->usage);
122 } else {
123 pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL);
124 if (!pcred->tgcred) {
125 kfree(pcred);
126 return -ENOMEM;
127 }
128 atomic_set(&pcred->tgcred->usage, 1);
129 spin_lock_init(&pcred->tgcred->lock);
130 pcred->tgcred->process_keyring = NULL;
131 pcred->tgcred->session_keyring =
132 key_get(p->cred->tgcred->session_keyring);
133 }
134#endif
135
74#ifdef CONFIG_SECURITY 136#ifdef CONFIG_SECURITY
75 pcred->security = NULL; 137 pcred->security = NULL;
76#endif 138#endif
77 139
78 ret = security_cred_alloc(pcred); 140 ret = security_cred_alloc(pcred);
79 if (ret < 0) { 141 if (ret < 0) {
142 release_tgcred(pcred);
80 kfree(pcred); 143 kfree(pcred);
81 return ret; 144 return ret;
82 } 145 }