diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:20 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:20 -0500 |
commit | bb952bb98a7e479262c7eb25d5592545a3af147d (patch) | |
tree | 9a2158c07a22a5fbddcec412944d2e7534eecc8f /kernel/cred.c | |
parent | 275bb41e9d058fbb327e7642f077e1beaeac162e (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.c | 63 |
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 | ||
23 | static 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 | */ |
22 | struct cred init_cred = { | 33 | struct 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 | ||
51 | static 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 | */ | ||
67 | static 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 | */ |
36 | static void put_cred_rcu(struct rcu_head *rcu) | 80 | static 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 | } |