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 | |
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>
-rw-r--r-- | include/linux/cred.h | 16 | ||||
-rw-r--r-- | include/linux/key.h | 8 | ||||
-rw-r--r-- | include/linux/sched.h | 6 | ||||
-rw-r--r-- | kernel/cred.c | 63 | ||||
-rw-r--r-- | kernel/fork.c | 7 | ||||
-rw-r--r-- | security/keys/process_keys.c | 100 | ||||
-rw-r--r-- | security/keys/request_key.c | 34 |
7 files changed, 135 insertions, 99 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h index 166ce4ddba64..62b9e532422d 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
@@ -72,6 +72,21 @@ extern int in_group_p(gid_t); | |||
72 | extern int in_egroup_p(gid_t); | 72 | extern int in_egroup_p(gid_t); |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * The common credentials for a thread group | ||
76 | * - shared by CLONE_THREAD | ||
77 | */ | ||
78 | #ifdef CONFIG_KEYS | ||
79 | struct thread_group_cred { | ||
80 | atomic_t usage; | ||
81 | pid_t tgid; /* thread group process ID */ | ||
82 | spinlock_t lock; | ||
83 | struct key *session_keyring; /* keyring inherited over fork */ | ||
84 | struct key *process_keyring; /* keyring private to this process */ | ||
85 | struct rcu_head rcu; /* RCU deletion hook */ | ||
86 | }; | ||
87 | #endif | ||
88 | |||
89 | /* | ||
75 | * The security context of a task | 90 | * The security context of a task |
76 | * | 91 | * |
77 | * The parts of the context break down into two categories: | 92 | * The parts of the context break down into two categories: |
@@ -114,6 +129,7 @@ struct cred { | |||
114 | * keys to */ | 129 | * keys to */ |
115 | struct key *thread_keyring; /* keyring private to this thread */ | 130 | struct key *thread_keyring; /* keyring private to this thread */ |
116 | struct key *request_key_auth; /* assumed request_key authority */ | 131 | struct key *request_key_auth; /* assumed request_key authority */ |
132 | struct thread_group_cred *tgcred; /* thread-group shared credentials */ | ||
117 | #endif | 133 | #endif |
118 | #ifdef CONFIG_SECURITY | 134 | #ifdef CONFIG_SECURITY |
119 | void *security; /* subjective LSM security */ | 135 | void *security; /* subjective LSM security */ |
diff --git a/include/linux/key.h b/include/linux/key.h index df709e1af3cd..0836cc838b0c 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -278,9 +278,7 @@ extern ctl_table key_sysctls[]; | |||
278 | */ | 278 | */ |
279 | extern void switch_uid_keyring(struct user_struct *new_user); | 279 | extern void switch_uid_keyring(struct user_struct *new_user); |
280 | extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); | 280 | extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); |
281 | extern int copy_thread_group_keys(struct task_struct *tsk); | ||
282 | extern void exit_keys(struct task_struct *tsk); | 281 | extern void exit_keys(struct task_struct *tsk); |
283 | extern void exit_thread_group_keys(struct signal_struct *tg); | ||
284 | extern int suid_keys(struct task_struct *tsk); | 282 | extern int suid_keys(struct task_struct *tsk); |
285 | extern int exec_keys(struct task_struct *tsk); | 283 | extern int exec_keys(struct task_struct *tsk); |
286 | extern void key_fsuid_changed(struct task_struct *tsk); | 284 | extern void key_fsuid_changed(struct task_struct *tsk); |
@@ -289,8 +287,8 @@ extern void key_init(void); | |||
289 | 287 | ||
290 | #define __install_session_keyring(keyring) \ | 288 | #define __install_session_keyring(keyring) \ |
291 | ({ \ | 289 | ({ \ |
292 | struct key *old_session = current->signal->session_keyring; \ | 290 | struct key *old_session = current->cred->tgcred->session_keyring; \ |
293 | current->signal->session_keyring = keyring; \ | 291 | current->cred->tgcred->session_keyring = keyring; \ |
294 | old_session; \ | 292 | old_session; \ |
295 | }) | 293 | }) |
296 | 294 | ||
@@ -308,9 +306,7 @@ extern void key_init(void); | |||
308 | #define switch_uid_keyring(u) do { } while(0) | 306 | #define switch_uid_keyring(u) do { } while(0) |
309 | #define __install_session_keyring(k) ({ NULL; }) | 307 | #define __install_session_keyring(k) ({ NULL; }) |
310 | #define copy_keys(f,t) 0 | 308 | #define copy_keys(f,t) 0 |
311 | #define copy_thread_group_keys(t) 0 | ||
312 | #define exit_keys(t) do { } while(0) | 309 | #define exit_keys(t) do { } while(0) |
313 | #define exit_thread_group_keys(tg) do { } while(0) | ||
314 | #define suid_keys(t) do { } while(0) | 310 | #define suid_keys(t) do { } while(0) |
315 | #define exec_keys(t) do { } while(0) | 311 | #define exec_keys(t) do { } while(0) |
316 | #define key_fsuid_changed(t) do { } while(0) | 312 | #define key_fsuid_changed(t) do { } while(0) |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 740cf946c8cc..2913252989b3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -571,12 +571,6 @@ struct signal_struct { | |||
571 | */ | 571 | */ |
572 | struct rlimit rlim[RLIM_NLIMITS]; | 572 | struct rlimit rlim[RLIM_NLIMITS]; |
573 | 573 | ||
574 | /* keep the process-shared keyrings here so that they do the right | ||
575 | * thing in threads created with CLONE_THREAD */ | ||
576 | #ifdef CONFIG_KEYS | ||
577 | struct key *session_keyring; /* keyring inherited over fork */ | ||
578 | struct key *process_keyring; /* keyring private to this process */ | ||
579 | #endif | ||
580 | #ifdef CONFIG_BSD_PROCESS_ACCT | 574 | #ifdef CONFIG_BSD_PROCESS_ACCT |
581 | struct pacct_struct pacct; /* per-process accounting information */ | 575 | struct pacct_struct pacct; /* per-process accounting information */ |
582 | #endif | 576 | #endif |
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 | } |
diff --git a/kernel/fork.c b/kernel/fork.c index c932e283ddfc..ded1972672a3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -802,12 +802,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
802 | if (!sig) | 802 | if (!sig) |
803 | return -ENOMEM; | 803 | return -ENOMEM; |
804 | 804 | ||
805 | ret = copy_thread_group_keys(tsk); | ||
806 | if (ret < 0) { | ||
807 | kmem_cache_free(signal_cachep, sig); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | atomic_set(&sig->count, 1); | 805 | atomic_set(&sig->count, 1); |
812 | atomic_set(&sig->live, 1); | 806 | atomic_set(&sig->live, 1); |
813 | init_waitqueue_head(&sig->wait_chldexit); | 807 | init_waitqueue_head(&sig->wait_chldexit); |
@@ -852,7 +846,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
852 | void __cleanup_signal(struct signal_struct *sig) | 846 | void __cleanup_signal(struct signal_struct *sig) |
853 | { | 847 | { |
854 | thread_group_cputime_free(sig); | 848 | thread_group_cputime_free(sig); |
855 | exit_thread_group_keys(sig); | ||
856 | tty_kref_put(sig->tty); | 849 | tty_kref_put(sig->tty); |
857 | kmem_cache_free(signal_cachep, sig); | 850 | kmem_cache_free(signal_cachep, sig); |
858 | } | 851 | } |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 212601ebaa46..70ee93406f30 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -189,7 +189,7 @@ int install_process_keyring(void) | |||
189 | 189 | ||
190 | might_sleep(); | 190 | might_sleep(); |
191 | 191 | ||
192 | if (!tsk->signal->process_keyring) { | 192 | if (!tsk->cred->tgcred->process_keyring) { |
193 | sprintf(buf, "_pid.%u", tsk->tgid); | 193 | sprintf(buf, "_pid.%u", tsk->tgid); |
194 | 194 | ||
195 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | 195 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, |
@@ -200,12 +200,12 @@ int install_process_keyring(void) | |||
200 | } | 200 | } |
201 | 201 | ||
202 | /* attach keyring */ | 202 | /* attach keyring */ |
203 | spin_lock_irq(&tsk->sighand->siglock); | 203 | spin_lock_irq(&tsk->cred->tgcred->lock); |
204 | if (!tsk->signal->process_keyring) { | 204 | if (!tsk->cred->tgcred->process_keyring) { |
205 | tsk->signal->process_keyring = keyring; | 205 | tsk->cred->tgcred->process_keyring = keyring; |
206 | keyring = NULL; | 206 | keyring = NULL; |
207 | } | 207 | } |
208 | spin_unlock_irq(&tsk->sighand->siglock); | 208 | spin_unlock_irq(&tsk->cred->tgcred->lock); |
209 | 209 | ||
210 | key_put(keyring); | 210 | key_put(keyring); |
211 | } | 211 | } |
@@ -235,11 +235,11 @@ static int install_session_keyring(struct key *keyring) | |||
235 | sprintf(buf, "_ses.%u", tsk->tgid); | 235 | sprintf(buf, "_ses.%u", tsk->tgid); |
236 | 236 | ||
237 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 237 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
238 | if (tsk->signal->session_keyring) | 238 | if (tsk->cred->tgcred->session_keyring) |
239 | flags = KEY_ALLOC_IN_QUOTA; | 239 | flags = KEY_ALLOC_IN_QUOTA; |
240 | 240 | ||
241 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | 241 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, |
242 | flags, NULL); | 242 | tsk, flags, NULL); |
243 | if (IS_ERR(keyring)) | 243 | if (IS_ERR(keyring)) |
244 | return PTR_ERR(keyring); | 244 | return PTR_ERR(keyring); |
245 | } | 245 | } |
@@ -248,10 +248,10 @@ static int install_session_keyring(struct key *keyring) | |||
248 | } | 248 | } |
249 | 249 | ||
250 | /* install the keyring */ | 250 | /* install the keyring */ |
251 | spin_lock_irq(&tsk->sighand->siglock); | 251 | spin_lock_irq(&tsk->cred->tgcred->lock); |
252 | old = tsk->signal->session_keyring; | 252 | old = tsk->cred->tgcred->session_keyring; |
253 | rcu_assign_pointer(tsk->signal->session_keyring, keyring); | 253 | rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring); |
254 | spin_unlock_irq(&tsk->sighand->siglock); | 254 | spin_unlock_irq(&tsk->cred->tgcred->lock); |
255 | 255 | ||
256 | /* we're using RCU on the pointer, but there's no point synchronising | 256 | /* we're using RCU on the pointer, but there's no point synchronising |
257 | * on it if it didn't previously point to anything */ | 257 | * on it if it didn't previously point to anything */ |
@@ -266,28 +266,6 @@ static int install_session_keyring(struct key *keyring) | |||
266 | 266 | ||
267 | /*****************************************************************************/ | 267 | /*****************************************************************************/ |
268 | /* | 268 | /* |
269 | * copy the keys in a thread group for fork without CLONE_THREAD | ||
270 | */ | ||
271 | int copy_thread_group_keys(struct task_struct *tsk) | ||
272 | { | ||
273 | key_check(current->thread_group->session_keyring); | ||
274 | key_check(current->thread_group->process_keyring); | ||
275 | |||
276 | /* no process keyring yet */ | ||
277 | tsk->signal->process_keyring = NULL; | ||
278 | |||
279 | /* same session keyring */ | ||
280 | rcu_read_lock(); | ||
281 | tsk->signal->session_keyring = | ||
282 | key_get(rcu_dereference(current->signal->session_keyring)); | ||
283 | rcu_read_unlock(); | ||
284 | |||
285 | return 0; | ||
286 | |||
287 | } /* end copy_thread_group_keys() */ | ||
288 | |||
289 | /*****************************************************************************/ | ||
290 | /* | ||
291 | * copy the keys for fork | 269 | * copy the keys for fork |
292 | */ | 270 | */ |
293 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | 271 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) |
@@ -307,17 +285,6 @@ int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | |||
307 | 285 | ||
308 | /*****************************************************************************/ | 286 | /*****************************************************************************/ |
309 | /* | 287 | /* |
310 | * dispose of thread group keys upon thread group destruction | ||
311 | */ | ||
312 | void exit_thread_group_keys(struct signal_struct *tg) | ||
313 | { | ||
314 | key_put(tg->session_keyring); | ||
315 | key_put(tg->process_keyring); | ||
316 | |||
317 | } /* end exit_thread_group_keys() */ | ||
318 | |||
319 | /*****************************************************************************/ | ||
320 | /* | ||
321 | * dispose of per-thread keys upon thread exit | 288 | * dispose of per-thread keys upon thread exit |
322 | */ | 289 | */ |
323 | void exit_keys(struct task_struct *tsk) | 290 | void exit_keys(struct task_struct *tsk) |
@@ -344,10 +311,10 @@ int exec_keys(struct task_struct *tsk) | |||
344 | key_put(old); | 311 | key_put(old); |
345 | 312 | ||
346 | /* discard the process keyring from a newly exec'd task */ | 313 | /* discard the process keyring from a newly exec'd task */ |
347 | spin_lock_irq(&tsk->sighand->siglock); | 314 | spin_lock_irq(&tsk->cred->tgcred->lock); |
348 | old = tsk->signal->process_keyring; | 315 | old = tsk->cred->tgcred->process_keyring; |
349 | tsk->signal->process_keyring = NULL; | 316 | tsk->cred->tgcred->process_keyring = NULL; |
350 | spin_unlock_irq(&tsk->sighand->siglock); | 317 | spin_unlock_irq(&tsk->cred->tgcred->lock); |
351 | 318 | ||
352 | key_put(old); | 319 | key_put(old); |
353 | 320 | ||
@@ -452,9 +419,9 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
452 | } | 419 | } |
453 | 420 | ||
454 | /* search the process keyring second */ | 421 | /* search the process keyring second */ |
455 | if (context->signal->process_keyring) { | 422 | if (cred->tgcred->process_keyring) { |
456 | key_ref = keyring_search_aux( | 423 | key_ref = keyring_search_aux( |
457 | make_key_ref(context->signal->process_keyring, 1), | 424 | make_key_ref(cred->tgcred->process_keyring, 1), |
458 | context, type, description, match); | 425 | context, type, description, match); |
459 | if (!IS_ERR(key_ref)) | 426 | if (!IS_ERR(key_ref)) |
460 | goto found; | 427 | goto found; |
@@ -473,11 +440,11 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
473 | } | 440 | } |
474 | 441 | ||
475 | /* search the session keyring */ | 442 | /* search the session keyring */ |
476 | if (context->signal->session_keyring) { | 443 | if (cred->tgcred->session_keyring) { |
477 | rcu_read_lock(); | 444 | rcu_read_lock(); |
478 | key_ref = keyring_search_aux( | 445 | key_ref = keyring_search_aux( |
479 | make_key_ref(rcu_dereference( | 446 | make_key_ref(rcu_dereference( |
480 | context->signal->session_keyring), | 447 | cred->tgcred->session_keyring), |
481 | 1), | 448 | 1), |
482 | context, type, description, match); | 449 | context, type, description, match); |
483 | rcu_read_unlock(); | 450 | rcu_read_unlock(); |
@@ -586,11 +553,13 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
586 | { | 553 | { |
587 | struct request_key_auth *rka; | 554 | struct request_key_auth *rka; |
588 | struct task_struct *t = current; | 555 | struct task_struct *t = current; |
589 | struct cred *cred = current_cred(); | 556 | struct cred *cred; |
590 | struct key *key; | 557 | struct key *key; |
591 | key_ref_t key_ref, skey_ref; | 558 | key_ref_t key_ref, skey_ref; |
592 | int ret; | 559 | int ret; |
593 | 560 | ||
561 | try_again: | ||
562 | cred = get_current_cred(); | ||
594 | key_ref = ERR_PTR(-ENOKEY); | 563 | key_ref = ERR_PTR(-ENOKEY); |
595 | 564 | ||
596 | switch (id) { | 565 | switch (id) { |
@@ -604,6 +573,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
604 | key = ERR_PTR(ret); | 573 | key = ERR_PTR(ret); |
605 | goto error; | 574 | goto error; |
606 | } | 575 | } |
576 | goto reget_creds; | ||
607 | } | 577 | } |
608 | 578 | ||
609 | key = cred->thread_keyring; | 579 | key = cred->thread_keyring; |
@@ -612,7 +582,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
612 | break; | 582 | break; |
613 | 583 | ||
614 | case KEY_SPEC_PROCESS_KEYRING: | 584 | case KEY_SPEC_PROCESS_KEYRING: |
615 | if (!t->signal->process_keyring) { | 585 | if (!cred->tgcred->process_keyring) { |
616 | if (!create) | 586 | if (!create) |
617 | goto error; | 587 | goto error; |
618 | 588 | ||
@@ -621,15 +591,16 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
621 | key = ERR_PTR(ret); | 591 | key = ERR_PTR(ret); |
622 | goto error; | 592 | goto error; |
623 | } | 593 | } |
594 | goto reget_creds; | ||
624 | } | 595 | } |
625 | 596 | ||
626 | key = t->signal->process_keyring; | 597 | key = cred->tgcred->process_keyring; |
627 | atomic_inc(&key->usage); | 598 | atomic_inc(&key->usage); |
628 | key_ref = make_key_ref(key, 1); | 599 | key_ref = make_key_ref(key, 1); |
629 | break; | 600 | break; |
630 | 601 | ||
631 | case KEY_SPEC_SESSION_KEYRING: | 602 | case KEY_SPEC_SESSION_KEYRING: |
632 | if (!t->signal->session_keyring) { | 603 | if (!cred->tgcred->session_keyring) { |
633 | /* always install a session keyring upon access if one | 604 | /* always install a session keyring upon access if one |
634 | * doesn't exist yet */ | 605 | * doesn't exist yet */ |
635 | ret = install_user_keyrings(); | 606 | ret = install_user_keyrings(); |
@@ -639,10 +610,11 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
639 | cred->user->session_keyring); | 610 | cred->user->session_keyring); |
640 | if (ret < 0) | 611 | if (ret < 0) |
641 | goto error; | 612 | goto error; |
613 | goto reget_creds; | ||
642 | } | 614 | } |
643 | 615 | ||
644 | rcu_read_lock(); | 616 | rcu_read_lock(); |
645 | key = rcu_dereference(t->signal->session_keyring); | 617 | key = rcu_dereference(cred->tgcred->session_keyring); |
646 | atomic_inc(&key->usage); | 618 | atomic_inc(&key->usage); |
647 | rcu_read_unlock(); | 619 | rcu_read_unlock(); |
648 | key_ref = make_key_ref(key, 1); | 620 | key_ref = make_key_ref(key, 1); |
@@ -758,6 +730,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
758 | goto invalid_key; | 730 | goto invalid_key; |
759 | 731 | ||
760 | error: | 732 | error: |
733 | put_cred(cred); | ||
761 | return key_ref; | 734 | return key_ref; |
762 | 735 | ||
763 | invalid_key: | 736 | invalid_key: |
@@ -765,6 +738,12 @@ invalid_key: | |||
765 | key_ref = ERR_PTR(ret); | 738 | key_ref = ERR_PTR(ret); |
766 | goto error; | 739 | goto error; |
767 | 740 | ||
741 | /* if we attempted to install a keyring, then it may have caused new | ||
742 | * creds to be installed */ | ||
743 | reget_creds: | ||
744 | put_cred(cred); | ||
745 | goto try_again; | ||
746 | |||
768 | } /* end lookup_user_key() */ | 747 | } /* end lookup_user_key() */ |
769 | 748 | ||
770 | /*****************************************************************************/ | 749 | /*****************************************************************************/ |
@@ -777,6 +756,7 @@ invalid_key: | |||
777 | long join_session_keyring(const char *name) | 756 | long join_session_keyring(const char *name) |
778 | { | 757 | { |
779 | struct task_struct *tsk = current; | 758 | struct task_struct *tsk = current; |
759 | struct cred *cred = current->cred; | ||
780 | struct key *keyring; | 760 | struct key *keyring; |
781 | long ret; | 761 | long ret; |
782 | 762 | ||
@@ -787,7 +767,7 @@ long join_session_keyring(const char *name) | |||
787 | goto error; | 767 | goto error; |
788 | 768 | ||
789 | rcu_read_lock(); | 769 | rcu_read_lock(); |
790 | ret = rcu_dereference(tsk->signal->session_keyring)->serial; | 770 | ret = rcu_dereference(cred->tgcred->session_keyring)->serial; |
791 | rcu_read_unlock(); | 771 | rcu_read_unlock(); |
792 | goto error; | 772 | goto error; |
793 | } | 773 | } |
@@ -799,7 +779,7 @@ long join_session_keyring(const char *name) | |||
799 | keyring = find_keyring_by_name(name, false); | 779 | keyring = find_keyring_by_name(name, false); |
800 | if (PTR_ERR(keyring) == -ENOKEY) { | 780 | if (PTR_ERR(keyring) == -ENOKEY) { |
801 | /* not found - try and create a new one */ | 781 | /* not found - try and create a new one */ |
802 | keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk, | 782 | keyring = keyring_alloc(name, cred->uid, cred->gid, tsk, |
803 | KEY_ALLOC_IN_QUOTA, NULL); | 783 | KEY_ALLOC_IN_QUOTA, NULL); |
804 | if (IS_ERR(keyring)) { | 784 | if (IS_ERR(keyring)) { |
805 | ret = PTR_ERR(keyring); | 785 | ret = PTR_ERR(keyring); |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0488b0af5bd6..3d12558362df 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -66,7 +66,6 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
66 | const char *op, | 66 | const char *op, |
67 | void *aux) | 67 | void *aux) |
68 | { | 68 | { |
69 | struct task_struct *tsk = current; | ||
70 | const struct cred *cred = current_cred(); | 69 | const struct cred *cred = current_cred(); |
71 | key_serial_t prkey, sskey; | 70 | key_serial_t prkey, sskey; |
72 | struct key *key = cons->key, *authkey = cons->authkey, *keyring; | 71 | struct key *key = cons->key, *authkey = cons->authkey, *keyring; |
@@ -109,18 +108,13 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
109 | cred->thread_keyring->serial : 0); | 108 | cred->thread_keyring->serial : 0); |
110 | 109 | ||
111 | prkey = 0; | 110 | prkey = 0; |
112 | if (tsk->signal->process_keyring) | 111 | if (cred->tgcred->process_keyring) |
113 | prkey = tsk->signal->process_keyring->serial; | 112 | prkey = cred->tgcred->process_keyring->serial; |
114 | 113 | ||
115 | sprintf(keyring_str[1], "%d", prkey); | 114 | if (cred->tgcred->session_keyring) |
116 | 115 | sskey = rcu_dereference(cred->tgcred->session_keyring)->serial; | |
117 | if (tsk->signal->session_keyring) { | 116 | else |
118 | rcu_read_lock(); | ||
119 | sskey = rcu_dereference(tsk->signal->session_keyring)->serial; | ||
120 | rcu_read_unlock(); | ||
121 | } else { | ||
122 | sskey = cred->user->session_keyring->serial; | 117 | sskey = cred->user->session_keyring->serial; |
123 | } | ||
124 | 118 | ||
125 | sprintf(keyring_str[2], "%d", sskey); | 119 | sprintf(keyring_str[2], "%d", sskey); |
126 | 120 | ||
@@ -222,7 +216,7 @@ static int construct_key(struct key *key, const void *callout_info, | |||
222 | static void construct_get_dest_keyring(struct key **_dest_keyring) | 216 | static void construct_get_dest_keyring(struct key **_dest_keyring) |
223 | { | 217 | { |
224 | struct request_key_auth *rka; | 218 | struct request_key_auth *rka; |
225 | struct task_struct *tsk = current; | 219 | const struct cred *cred = current_cred(); |
226 | struct key *dest_keyring = *_dest_keyring, *authkey; | 220 | struct key *dest_keyring = *_dest_keyring, *authkey; |
227 | 221 | ||
228 | kenter("%p", dest_keyring); | 222 | kenter("%p", dest_keyring); |
@@ -234,11 +228,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
234 | } else { | 228 | } else { |
235 | /* use a default keyring; falling through the cases until we | 229 | /* use a default keyring; falling through the cases until we |
236 | * find one that we actually have */ | 230 | * find one that we actually have */ |
237 | switch (tsk->cred->jit_keyring) { | 231 | switch (cred->jit_keyring) { |
238 | case KEY_REQKEY_DEFL_DEFAULT: | 232 | case KEY_REQKEY_DEFL_DEFAULT: |
239 | case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: | 233 | case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: |
240 | if (tsk->cred->request_key_auth) { | 234 | if (cred->request_key_auth) { |
241 | authkey = tsk->cred->request_key_auth; | 235 | authkey = cred->request_key_auth; |
242 | down_read(&authkey->sem); | 236 | down_read(&authkey->sem); |
243 | rka = authkey->payload.data; | 237 | rka = authkey->payload.data; |
244 | if (!test_bit(KEY_FLAG_REVOKED, | 238 | if (!test_bit(KEY_FLAG_REVOKED, |
@@ -251,19 +245,19 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
251 | } | 245 | } |
252 | 246 | ||
253 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | 247 | case KEY_REQKEY_DEFL_THREAD_KEYRING: |
254 | dest_keyring = key_get(tsk->cred->thread_keyring); | 248 | dest_keyring = key_get(cred->thread_keyring); |
255 | if (dest_keyring) | 249 | if (dest_keyring) |
256 | break; | 250 | break; |
257 | 251 | ||
258 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 252 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
259 | dest_keyring = key_get(tsk->signal->process_keyring); | 253 | dest_keyring = key_get(cred->tgcred->process_keyring); |
260 | if (dest_keyring) | 254 | if (dest_keyring) |
261 | break; | 255 | break; |
262 | 256 | ||
263 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 257 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
264 | rcu_read_lock(); | 258 | rcu_read_lock(); |
265 | dest_keyring = key_get( | 259 | dest_keyring = key_get( |
266 | rcu_dereference(tsk->signal->session_keyring)); | 260 | rcu_dereference(cred->tgcred->session_keyring)); |
267 | rcu_read_unlock(); | 261 | rcu_read_unlock(); |
268 | 262 | ||
269 | if (dest_keyring) | 263 | if (dest_keyring) |
@@ -271,11 +265,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
271 | 265 | ||
272 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | 266 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
273 | dest_keyring = | 267 | dest_keyring = |
274 | key_get(tsk->cred->user->session_keyring); | 268 | key_get(cred->user->session_keyring); |
275 | break; | 269 | break; |
276 | 270 | ||
277 | case KEY_REQKEY_DEFL_USER_KEYRING: | 271 | case KEY_REQKEY_DEFL_USER_KEYRING: |
278 | dest_keyring = key_get(tsk->cred->user->uid_keyring); | 272 | dest_keyring = key_get(cred->user->uid_keyring); |
279 | break; | 273 | break; |
280 | 274 | ||
281 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | 275 | case KEY_REQKEY_DEFL_GROUP_KEYRING: |