aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cred.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-09-02 04:13:40 -0400
committerJames Morris <jmorris@namei.org>2009-09-02 07:29:01 -0400
commite0e817392b9acf2c98d3be80c233dddb1b52003d (patch)
treeee680c020039313c9f9c40ab3542bb30a7363381 /kernel/cred.c
parented6d76e4c32de0c2ad5f1d572b948ef49e465176 (diff)
CRED: Add some configurable debugging [try #6]
Add a config option (CONFIG_DEBUG_CREDENTIALS) to turn on some debug checking for credential management. The additional code keeps track of the number of pointers from task_structs to any given cred struct, and checks to see that this number never exceeds the usage count of the cred struct (which includes all references, not just those from task_structs). Furthermore, if SELinux is enabled, the code also checks that the security pointer in the cred struct is never seen to be invalid. This attempts to catch the bug whereby inode_has_perm() faults in an nfsd kernel thread on seeing cred->security be a NULL pointer (it appears that the credential struct has been previously released): http://www.kerneloops.org/oops.php?number=252883 Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel/cred.c')
-rw-r--r--kernel/cred.c250
1 files changed, 244 insertions, 6 deletions
diff --git a/kernel/cred.c b/kernel/cred.c
index 1bb4d7e5d616..24dd2f5104b1 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -18,6 +18,18 @@
18#include <linux/cn_proc.h> 18#include <linux/cn_proc.h>
19#include "cred-internals.h" 19#include "cred-internals.h"
20 20
21#if 0
22#define kdebug(FMT, ...) \
23 printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
24#else
25static inline __attribute__((format(printf, 1, 2)))
26void no_printk(const char *fmt, ...)
27{
28}
29#define kdebug(FMT, ...) \
30 no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
31#endif
32
21static struct kmem_cache *cred_jar; 33static struct kmem_cache *cred_jar;
22 34
23/* 35/*
@@ -36,6 +48,10 @@ static struct thread_group_cred init_tgcred = {
36 */ 48 */
37struct cred init_cred = { 49struct cred init_cred = {
38 .usage = ATOMIC_INIT(4), 50 .usage = ATOMIC_INIT(4),
51#ifdef CONFIG_DEBUG_CREDENTIALS
52 .subscribers = ATOMIC_INIT(2),
53 .magic = CRED_MAGIC,
54#endif
39 .securebits = SECUREBITS_DEFAULT, 55 .securebits = SECUREBITS_DEFAULT,
40 .cap_inheritable = CAP_INIT_INH_SET, 56 .cap_inheritable = CAP_INIT_INH_SET,
41 .cap_permitted = CAP_FULL_SET, 57 .cap_permitted = CAP_FULL_SET,
@@ -48,6 +64,31 @@ struct cred init_cred = {
48#endif 64#endif
49}; 65};
50 66
67static inline void set_cred_subscribers(struct cred *cred, int n)
68{
69#ifdef CONFIG_DEBUG_CREDENTIALS
70 atomic_set(&cred->subscribers, n);
71#endif
72}
73
74static inline int read_cred_subscribers(const struct cred *cred)
75{
76#ifdef CONFIG_DEBUG_CREDENTIALS
77 return atomic_read(&cred->subscribers);
78#else
79 return 0;
80#endif
81}
82
83static inline void alter_cred_subscribers(const struct cred *_cred, int n)
84{
85#ifdef CONFIG_DEBUG_CREDENTIALS
86 struct cred *cred = (struct cred *) _cred;
87
88 atomic_add(n, &cred->subscribers);
89#endif
90}
91
51/* 92/*
52 * Dispose of the shared task group credentials 93 * Dispose of the shared task group credentials
53 */ 94 */
@@ -85,9 +126,22 @@ static void put_cred_rcu(struct rcu_head *rcu)
85{ 126{
86 struct cred *cred = container_of(rcu, struct cred, rcu); 127 struct cred *cred = container_of(rcu, struct cred, rcu);
87 128
129 kdebug("put_cred_rcu(%p)", cred);
130
131#ifdef CONFIG_DEBUG_CREDENTIALS
132 if (cred->magic != CRED_MAGIC_DEAD ||
133 atomic_read(&cred->usage) != 0 ||
134 read_cred_subscribers(cred) != 0)
135 panic("CRED: put_cred_rcu() sees %p with"
136 " mag %x, put %p, usage %d, subscr %d\n",
137 cred, cred->magic, cred->put_addr,
138 atomic_read(&cred->usage),
139 read_cred_subscribers(cred));
140#else
88 if (atomic_read(&cred->usage) != 0) 141 if (atomic_read(&cred->usage) != 0)
89 panic("CRED: put_cred_rcu() sees %p with usage %d\n", 142 panic("CRED: put_cred_rcu() sees %p with usage %d\n",
90 cred, atomic_read(&cred->usage)); 143 cred, atomic_read(&cred->usage));
144#endif
91 145
92 security_cred_free(cred); 146 security_cred_free(cred);
93 key_put(cred->thread_keyring); 147 key_put(cred->thread_keyring);
@@ -106,12 +160,47 @@ static void put_cred_rcu(struct rcu_head *rcu)
106 */ 160 */
107void __put_cred(struct cred *cred) 161void __put_cred(struct cred *cred)
108{ 162{
163 kdebug("__put_cred(%p{%d,%d})", cred,
164 atomic_read(&cred->usage),
165 read_cred_subscribers(cred));
166
109 BUG_ON(atomic_read(&cred->usage) != 0); 167 BUG_ON(atomic_read(&cred->usage) != 0);
168#ifdef CONFIG_DEBUG_CREDENTIALS
169 BUG_ON(read_cred_subscribers(cred) != 0);
170 cred->magic = CRED_MAGIC_DEAD;
171 cred->put_addr = __builtin_return_address(0);
172#endif
173 BUG_ON(cred == current->cred);
174 BUG_ON(cred == current->real_cred);
110 175
111 call_rcu(&cred->rcu, put_cred_rcu); 176 call_rcu(&cred->rcu, put_cred_rcu);
112} 177}
113EXPORT_SYMBOL(__put_cred); 178EXPORT_SYMBOL(__put_cred);
114 179
180/*
181 * Clean up a task's credentials when it exits
182 */
183void exit_creds(struct task_struct *tsk)
184{
185 struct cred *cred;
186
187 kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred,
188 atomic_read(&tsk->cred->usage),
189 read_cred_subscribers(tsk->cred));
190
191 cred = (struct cred *) tsk->real_cred;
192 tsk->real_cred = NULL;
193 validate_creds(cred);
194 alter_cred_subscribers(cred, -1);
195 put_cred(cred);
196
197 cred = (struct cred *) tsk->cred;
198 tsk->cred = NULL;
199 validate_creds(cred);
200 alter_cred_subscribers(cred, -1);
201 put_cred(cred);
202}
203
115/** 204/**
116 * prepare_creds - Prepare a new set of credentials for modification 205 * prepare_creds - Prepare a new set of credentials for modification
117 * 206 *
@@ -132,16 +221,19 @@ struct cred *prepare_creds(void)
132 const struct cred *old; 221 const struct cred *old;
133 struct cred *new; 222 struct cred *new;
134 223
135 BUG_ON(atomic_read(&task->real_cred->usage) < 1); 224 validate_process_creds();
136 225
137 new = kmem_cache_alloc(cred_jar, GFP_KERNEL); 226 new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
138 if (!new) 227 if (!new)
139 return NULL; 228 return NULL;
140 229
230 kdebug("prepare_creds() alloc %p", new);
231
141 old = task->cred; 232 old = task->cred;
142 memcpy(new, old, sizeof(struct cred)); 233 memcpy(new, old, sizeof(struct cred));
143 234
144 atomic_set(&new->usage, 1); 235 atomic_set(&new->usage, 1);
236 set_cred_subscribers(new, 0);
145 get_group_info(new->group_info); 237 get_group_info(new->group_info);
146 get_uid(new->user); 238 get_uid(new->user);
147 239
@@ -157,6 +249,7 @@ struct cred *prepare_creds(void)
157 249
158 if (security_prepare_creds(new, old, GFP_KERNEL) < 0) 250 if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
159 goto error; 251 goto error;
252 validate_creds(new);
160 return new; 253 return new;
161 254
162error: 255error:
@@ -229,9 +322,12 @@ struct cred *prepare_usermodehelper_creds(void)
229 if (!new) 322 if (!new)
230 return NULL; 323 return NULL;
231 324
325 kdebug("prepare_usermodehelper_creds() alloc %p", new);
326
232 memcpy(new, &init_cred, sizeof(struct cred)); 327 memcpy(new, &init_cred, sizeof(struct cred));
233 328
234 atomic_set(&new->usage, 1); 329 atomic_set(&new->usage, 1);
330 set_cred_subscribers(new, 0);
235 get_group_info(new->group_info); 331 get_group_info(new->group_info);
236 get_uid(new->user); 332 get_uid(new->user);
237 333
@@ -250,6 +346,7 @@ struct cred *prepare_usermodehelper_creds(void)
250#endif 346#endif
251 if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0) 347 if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
252 goto error; 348 goto error;
349 validate_creds(new);
253 350
254 BUG_ON(atomic_read(&new->usage) != 1); 351 BUG_ON(atomic_read(&new->usage) != 1);
255 return new; 352 return new;
@@ -286,6 +383,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
286 ) { 383 ) {
287 p->real_cred = get_cred(p->cred); 384 p->real_cred = get_cred(p->cred);
288 get_cred(p->cred); 385 get_cred(p->cred);
386 alter_cred_subscribers(p->cred, 2);
387 kdebug("share_creds(%p{%d,%d})",
388 p->cred, atomic_read(&p->cred->usage),
389 read_cred_subscribers(p->cred));
289 atomic_inc(&p->cred->user->processes); 390 atomic_inc(&p->cred->user->processes);
290 return 0; 391 return 0;
291 } 392 }
@@ -331,6 +432,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
331 432
332 atomic_inc(&new->user->processes); 433 atomic_inc(&new->user->processes);
333 p->cred = p->real_cred = get_cred(new); 434 p->cred = p->real_cred = get_cred(new);
435 alter_cred_subscribers(new, 2);
436 validate_creds(new);
334 return 0; 437 return 0;
335 438
336error_put: 439error_put:
@@ -355,13 +458,20 @@ error_put:
355int commit_creds(struct cred *new) 458int commit_creds(struct cred *new)
356{ 459{
357 struct task_struct *task = current; 460 struct task_struct *task = current;
358 const struct cred *old; 461 const struct cred *old = task->real_cred;
359 462
360 BUG_ON(task->cred != task->real_cred); 463 kdebug("commit_creds(%p{%d,%d})", new,
361 BUG_ON(atomic_read(&task->real_cred->usage) < 2); 464 atomic_read(&new->usage),
465 read_cred_subscribers(new));
466
467 BUG_ON(task->cred != old);
468#ifdef CONFIG_DEBUG_CREDENTIALS
469 BUG_ON(read_cred_subscribers(old) < 2);
470 validate_creds(old);
471 validate_creds(new);
472#endif
362 BUG_ON(atomic_read(&new->usage) < 1); 473 BUG_ON(atomic_read(&new->usage) < 1);
363 474
364 old = task->real_cred;
365 security_commit_creds(new, old); 475 security_commit_creds(new, old);
366 476
367 get_cred(new); /* we will require a ref for the subj creds too */ 477 get_cred(new); /* we will require a ref for the subj creds too */
@@ -390,12 +500,14 @@ int commit_creds(struct cred *new)
390 * cheaply with the new uid cache, so if it matters 500 * cheaply with the new uid cache, so if it matters
391 * we should be checking for it. -DaveM 501 * we should be checking for it. -DaveM
392 */ 502 */
503 alter_cred_subscribers(new, 2);
393 if (new->user != old->user) 504 if (new->user != old->user)
394 atomic_inc(&new->user->processes); 505 atomic_inc(&new->user->processes);
395 rcu_assign_pointer(task->real_cred, new); 506 rcu_assign_pointer(task->real_cred, new);
396 rcu_assign_pointer(task->cred, new); 507 rcu_assign_pointer(task->cred, new);
397 if (new->user != old->user) 508 if (new->user != old->user)
398 atomic_dec(&old->user->processes); 509 atomic_dec(&old->user->processes);
510 alter_cred_subscribers(old, -2);
399 511
400 sched_switch_user(task); 512 sched_switch_user(task);
401 513
@@ -428,6 +540,13 @@ EXPORT_SYMBOL(commit_creds);
428 */ 540 */
429void abort_creds(struct cred *new) 541void abort_creds(struct cred *new)
430{ 542{
543 kdebug("abort_creds(%p{%d,%d})", new,
544 atomic_read(&new->usage),
545 read_cred_subscribers(new));
546
547#ifdef CONFIG_DEBUG_CREDENTIALS
548 BUG_ON(read_cred_subscribers(new) != 0);
549#endif
431 BUG_ON(atomic_read(&new->usage) < 1); 550 BUG_ON(atomic_read(&new->usage) < 1);
432 put_cred(new); 551 put_cred(new);
433} 552}
@@ -444,7 +563,20 @@ const struct cred *override_creds(const struct cred *new)
444{ 563{
445 const struct cred *old = current->cred; 564 const struct cred *old = current->cred;
446 565
447 rcu_assign_pointer(current->cred, get_cred(new)); 566 kdebug("override_creds(%p{%d,%d})", new,
567 atomic_read(&new->usage),
568 read_cred_subscribers(new));
569
570 validate_creds(old);
571 validate_creds(new);
572 get_cred(new);
573 alter_cred_subscribers(new, 1);
574 rcu_assign_pointer(current->cred, new);
575 alter_cred_subscribers(old, -1);
576
577 kdebug("override_creds() = %p{%d,%d}", old,
578 atomic_read(&old->usage),
579 read_cred_subscribers(old));
448 return old; 580 return old;
449} 581}
450EXPORT_SYMBOL(override_creds); 582EXPORT_SYMBOL(override_creds);
@@ -460,7 +592,15 @@ void revert_creds(const struct cred *old)
460{ 592{
461 const struct cred *override = current->cred; 593 const struct cred *override = current->cred;
462 594
595 kdebug("revert_creds(%p{%d,%d})", old,
596 atomic_read(&old->usage),
597 read_cred_subscribers(old));
598
599 validate_creds(old);
600 validate_creds(override);
601 alter_cred_subscribers(old, 1);
463 rcu_assign_pointer(current->cred, old); 602 rcu_assign_pointer(current->cred, old);
603 alter_cred_subscribers(override, -1);
464 put_cred(override); 604 put_cred(override);
465} 605}
466EXPORT_SYMBOL(revert_creds); 606EXPORT_SYMBOL(revert_creds);
@@ -502,11 +642,15 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
502 if (!new) 642 if (!new)
503 return NULL; 643 return NULL;
504 644
645 kdebug("prepare_kernel_cred() alloc %p", new);
646
505 if (daemon) 647 if (daemon)
506 old = get_task_cred(daemon); 648 old = get_task_cred(daemon);
507 else 649 else
508 old = get_cred(&init_cred); 650 old = get_cred(&init_cred);
509 651
652 validate_creds(old);
653
510 *new = *old; 654 *new = *old;
511 get_uid(new->user); 655 get_uid(new->user);
512 get_group_info(new->group_info); 656 get_group_info(new->group_info);
@@ -526,7 +670,9 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
526 goto error; 670 goto error;
527 671
528 atomic_set(&new->usage, 1); 672 atomic_set(&new->usage, 1);
673 set_cred_subscribers(new, 0);
529 put_cred(old); 674 put_cred(old);
675 validate_creds(new);
530 return new; 676 return new;
531 677
532error: 678error:
@@ -589,3 +735,95 @@ int set_create_files_as(struct cred *new, struct inode *inode)
589 return security_kernel_create_files_as(new, inode); 735 return security_kernel_create_files_as(new, inode);
590} 736}
591EXPORT_SYMBOL(set_create_files_as); 737EXPORT_SYMBOL(set_create_files_as);
738
739#ifdef CONFIG_DEBUG_CREDENTIALS
740
741/*
742 * dump invalid credentials
743 */
744static void dump_invalid_creds(const struct cred *cred, const char *label,
745 const struct task_struct *tsk)
746{
747 printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n",
748 label, cred,
749 cred == &init_cred ? "[init]" : "",
750 cred == tsk->real_cred ? "[real]" : "",
751 cred == tsk->cred ? "[eff]" : "");
752 printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n",
753 cred->magic, cred->put_addr);
754 printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n",
755 atomic_read(&cred->usage),
756 read_cred_subscribers(cred));
757 printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n",
758 cred->uid, cred->euid, cred->suid, cred->fsuid);
759 printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n",
760 cred->gid, cred->egid, cred->sgid, cred->fsgid);
761#ifdef CONFIG_SECURITY
762 printk(KERN_ERR "CRED: ->security is %p\n", cred->security);
763 if ((unsigned long) cred->security >= PAGE_SIZE &&
764 (((unsigned long) cred->security & 0xffffff00) !=
765 (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)))
766 printk(KERN_ERR "CRED: ->security {%x, %x}\n",
767 ((u32*)cred->security)[0],
768 ((u32*)cred->security)[1]);
769#endif
770}
771
772/*
773 * report use of invalid credentials
774 */
775void __invalid_creds(const struct cred *cred, const char *file, unsigned line)
776{
777 printk(KERN_ERR "CRED: Invalid credentials\n");
778 printk(KERN_ERR "CRED: At %s:%u\n", file, line);
779 dump_invalid_creds(cred, "Specified", current);
780 BUG();
781}
782EXPORT_SYMBOL(__invalid_creds);
783
784/*
785 * check the credentials on a process
786 */
787void __validate_process_creds(struct task_struct *tsk,
788 const char *file, unsigned line)
789{
790 if (tsk->cred == tsk->real_cred) {
791 if (unlikely(read_cred_subscribers(tsk->cred) < 2 ||
792 creds_are_invalid(tsk->cred)))
793 goto invalid_creds;
794 } else {
795 if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 ||
796 read_cred_subscribers(tsk->cred) < 1 ||
797 creds_are_invalid(tsk->real_cred) ||
798 creds_are_invalid(tsk->cred)))
799 goto invalid_creds;
800 }
801 return;
802
803invalid_creds:
804 printk(KERN_ERR "CRED: Invalid process credentials\n");
805 printk(KERN_ERR "CRED: At %s:%u\n", file, line);
806
807 dump_invalid_creds(tsk->real_cred, "Real", tsk);
808 if (tsk->cred != tsk->real_cred)
809 dump_invalid_creds(tsk->cred, "Effective", tsk);
810 else
811 printk(KERN_ERR "CRED: Effective creds == Real creds\n");
812 BUG();
813}
814EXPORT_SYMBOL(__validate_process_creds);
815
816/*
817 * check creds for do_exit()
818 */
819void validate_creds_for_do_exit(struct task_struct *tsk)
820{
821 kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})",
822 tsk->real_cred, tsk->cred,
823 atomic_read(&tsk->cred->usage),
824 read_cred_subscribers(tsk->cred));
825
826 __validate_process_creds(tsk, __FILE__, __LINE__);
827}
828
829#endif /* CONFIG_DEBUG_CREDENTIALS */