Commit e0e817392b9acf2c98d3be80c233dddb1b52003d

Authored by David Howells
Committed by James Morris
1 parent ed6d76e4c3

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>

Showing 11 changed files with 346 additions and 12 deletions Side-by-side Diff

... ... @@ -34,6 +34,8 @@
34 34 int flags = nfsexp_flags(rqstp, exp);
35 35 int ret;
36 36  
  37 + validate_process_creds();
  38 +
37 39 /* discard any old override before preparing the new set */
38 40 revert_creds(get_cred(current->real_cred));
39 41 new = prepare_creds();
40 42  
... ... @@ -86,8 +88,10 @@
86 88 else
87 89 new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
88 90 new->cap_permitted);
  91 + validate_process_creds();
89 92 put_cred(override_creds(new));
90 93 put_cred(new);
  94 + validate_process_creds();
91 95 return 0;
92 96  
93 97 oom:
... ... @@ -496,7 +496,9 @@
496 496 /* Lock the export hash tables for reading. */
497 497 exp_readlock();
498 498  
  499 + validate_process_creds();
499 500 svc_process(rqstp);
  501 + validate_process_creds();
500 502  
501 503 /* Unlock export hash tables */
502 504 exp_readunlock();
... ... @@ -684,6 +684,8 @@
684 684 __be32 err;
685 685 int host_err;
686 686  
  687 + validate_process_creds();
  688 +
687 689 /*
688 690 * If we get here, then the client has already done an "open",
689 691 * and (hopefully) checked permission - so allow OWNER_OVERRIDE
... ... @@ -740,6 +742,7 @@
740 742 out_nfserr:
741 743 err = nfserrno(host_err);
742 744 out:
  745 + validate_process_creds();
743 746 return err;
744 747 }
745 748  
... ... @@ -959,6 +959,8 @@
959 959 int error;
960 960 struct file *f;
961 961  
  962 + validate_creds(cred);
  963 +
962 964 /*
963 965 * We must always pass in a valid mount pointer. Historically
964 966 * callers got away with not passing it, but we must enforce this at
include/linux/cred.h
... ... @@ -114,6 +114,13 @@
114 114 */
115 115 struct cred {
116 116 atomic_t usage;
  117 +#ifdef CONFIG_DEBUG_CREDENTIALS
  118 + atomic_t subscribers; /* number of processes subscribed */
  119 + void *put_addr;
  120 + unsigned magic;
  121 +#define CRED_MAGIC 0x43736564
  122 +#define CRED_MAGIC_DEAD 0x44656144
  123 +#endif
117 124 uid_t uid; /* real UID of the task */
118 125 gid_t gid; /* real GID of the task */
119 126 uid_t suid; /* saved UID of the task */
... ... @@ -143,6 +150,7 @@
143 150 };
144 151  
145 152 extern void __put_cred(struct cred *);
  153 +extern void exit_creds(struct task_struct *);
146 154 extern int copy_creds(struct task_struct *, unsigned long);
147 155 extern struct cred *prepare_creds(void);
148 156 extern struct cred *prepare_exec_creds(void);
... ... @@ -158,6 +166,60 @@
158 166 extern int set_create_files_as(struct cred *, struct inode *);
159 167 extern void __init cred_init(void);
160 168  
  169 +/*
  170 + * check for validity of credentials
  171 + */
  172 +#ifdef CONFIG_DEBUG_CREDENTIALS
  173 +extern void __invalid_creds(const struct cred *, const char *, unsigned);
  174 +extern void __validate_process_creds(struct task_struct *,
  175 + const char *, unsigned);
  176 +
  177 +static inline bool creds_are_invalid(const struct cred *cred)
  178 +{
  179 + if (cred->magic != CRED_MAGIC)
  180 + return true;
  181 + if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
  182 + return true;
  183 +#ifdef CONFIG_SECURITY_SELINUX
  184 + if ((unsigned long) cred->security < PAGE_SIZE)
  185 + return true;
  186 + if ((*(u32*)cred->security & 0xffffff00) ==
  187 + (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
  188 + return true;
  189 +#endif
  190 + return false;
  191 +}
  192 +
  193 +static inline void __validate_creds(const struct cred *cred,
  194 + const char *file, unsigned line)
  195 +{
  196 + if (unlikely(creds_are_invalid(cred)))
  197 + __invalid_creds(cred, file, line);
  198 +}
  199 +
  200 +#define validate_creds(cred) \
  201 +do { \
  202 + __validate_creds((cred), __FILE__, __LINE__); \
  203 +} while(0)
  204 +
  205 +#define validate_process_creds() \
  206 +do { \
  207 + __validate_process_creds(current, __FILE__, __LINE__); \
  208 +} while(0)
  209 +
  210 +extern void validate_creds_for_do_exit(struct task_struct *);
  211 +#else
  212 +static inline void validate_creds(const struct cred *cred)
  213 +{
  214 +}
  215 +static inline void validate_creds_for_do_exit(struct task_struct *tsk)
  216 +{
  217 +}
  218 +static inline void validate_process_creds(void)
  219 +{
  220 +}
  221 +#endif
  222 +
161 223 /**
162 224 * get_new_cred - Get a reference on a new set of credentials
163 225 * @cred: The new credentials to reference
... ... @@ -187,6 +249,7 @@
187 249 static inline const struct cred *get_cred(const struct cred *cred)
188 250 {
189 251 struct cred *nonconst_cred = (struct cred *) cred;
  252 + validate_creds(cred);
190 253 return get_new_cred(nonconst_cred);
191 254 }
192 255  
... ... @@ -205,7 +268,7 @@
205 268 {
206 269 struct cred *cred = (struct cred *) _cred;
207 270  
208   - BUG_ON(atomic_read(&(cred)->usage) <= 0);
  271 + validate_creds(cred);
209 272 if (atomic_dec_and_test(&(cred)->usage))
210 273 __put_cred(cred);
211 274 }
... ... @@ -18,6 +18,18 @@
18 18 #include <linux/cn_proc.h>
19 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
  25 +static inline __attribute__((format(printf, 1, 2)))
  26 +void 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 +
21 33 static struct kmem_cache *cred_jar;
22 34  
23 35 /*
... ... @@ -36,6 +48,10 @@
36 48 */
37 49 struct cred init_cred = {
38 50 .usage = ATOMIC_INIT(4),
  51 +#ifdef CONFIG_DEBUG_CREDENTIALS
  52 + .subscribers = ATOMIC_INIT(2),
  53 + .magic = CRED_MAGIC,
  54 +#endif
39 55 .securebits = SECUREBITS_DEFAULT,
40 56 .cap_inheritable = CAP_INIT_INH_SET,
41 57 .cap_permitted = CAP_FULL_SET,
... ... @@ -48,6 +64,31 @@
48 64 #endif
49 65 };
50 66  
  67 +static 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 +
  74 +static 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 +
  83 +static 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 93 * Dispose of the shared task group credentials
53 94 */
54 95  
... ... @@ -85,9 +126,22 @@
85 126 {
86 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 141 if (atomic_read(&cred->usage) != 0)
89 142 panic("CRED: put_cred_rcu() sees %p with usage %d\n",
90 143 cred, atomic_read(&cred->usage));
  144 +#endif
91 145  
92 146 security_cred_free(cred);
93 147 key_put(cred->thread_keyring);
94 148  
95 149  
... ... @@ -106,12 +160,47 @@
106 160 */
107 161 void __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 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 176 call_rcu(&cred->rcu, put_cred_rcu);
112 177 }
113 178 EXPORT_SYMBOL(__put_cred);
114 179  
  180 +/*
  181 + * Clean up a task's credentials when it exits
  182 + */
  183 +void 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 205 * prepare_creds - Prepare a new set of credentials for modification
117 206 *
118 207  
119 208  
... ... @@ -132,16 +221,19 @@
132 221 const struct cred *old;
133 222 struct cred *new;
134 223  
135   - BUG_ON(atomic_read(&task->real_cred->usage) < 1);
  224 + validate_process_creds();
136 225  
137 226 new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
138 227 if (!new)
139 228 return NULL;
140 229  
  230 + kdebug("prepare_creds() alloc %p", new);
  231 +
141 232 old = task->cred;
142 233 memcpy(new, old, sizeof(struct cred));
143 234  
144 235 atomic_set(&new->usage, 1);
  236 + set_cred_subscribers(new, 0);
145 237 get_group_info(new->group_info);
146 238 get_uid(new->user);
147 239  
... ... @@ -157,6 +249,7 @@
157 249  
158 250 if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
159 251 goto error;
  252 + validate_creds(new);
160 253 return new;
161 254  
162 255 error:
163 256  
... ... @@ -229,9 +322,12 @@
229 322 if (!new)
230 323 return NULL;
231 324  
  325 + kdebug("prepare_usermodehelper_creds() alloc %p", new);
  326 +
232 327 memcpy(new, &init_cred, sizeof(struct cred));
233 328  
234 329 atomic_set(&new->usage, 1);
  330 + set_cred_subscribers(new, 0);
235 331 get_group_info(new->group_info);
236 332 get_uid(new->user);
237 333  
... ... @@ -250,6 +346,7 @@
250 346 #endif
251 347 if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
252 348 goto error;
  349 + validate_creds(new);
253 350  
254 351 BUG_ON(atomic_read(&new->usage) != 1);
255 352 return new;
... ... @@ -286,6 +383,10 @@
286 383 ) {
287 384 p->real_cred = get_cred(p->cred);
288 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 390 atomic_inc(&p->cred->user->processes);
290 391 return 0;
291 392 }
... ... @@ -331,6 +432,8 @@
331 432  
332 433 atomic_inc(&new->user->processes);
333 434 p->cred = p->real_cred = get_cred(new);
  435 + alter_cred_subscribers(new, 2);
  436 + validate_creds(new);
334 437 return 0;
335 438  
336 439 error_put:
337 440  
338 441  
... ... @@ -355,13 +458,20 @@
355 458 int commit_creds(struct cred *new)
356 459 {
357 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);
361   - BUG_ON(atomic_read(&task->real_cred->usage) < 2);
  463 + kdebug("commit_creds(%p{%d,%d})", new,
  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 473 BUG_ON(atomic_read(&new->usage) < 1);
363 474  
364   - old = task->real_cred;
365 475 security_commit_creds(new, old);
366 476  
367 477 get_cred(new); /* we will require a ref for the subj creds too */
368 478  
... ... @@ -390,12 +500,14 @@
390 500 * cheaply with the new uid cache, so if it matters
391 501 * we should be checking for it. -DaveM
392 502 */
  503 + alter_cred_subscribers(new, 2);
393 504 if (new->user != old->user)
394 505 atomic_inc(&new->user->processes);
395 506 rcu_assign_pointer(task->real_cred, new);
396 507 rcu_assign_pointer(task->cred, new);
397 508 if (new->user != old->user)
398 509 atomic_dec(&old->user->processes);
  510 + alter_cred_subscribers(old, -2);
399 511  
400 512 sched_switch_user(task);
401 513  
... ... @@ -428,6 +540,13 @@
428 540 */
429 541 void 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 550 BUG_ON(atomic_read(&new->usage) < 1);
432 551 put_cred(new);
433 552 }
... ... @@ -444,7 +563,20 @@
444 563 {
445 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 580 return old;
449 581 }
450 582 EXPORT_SYMBOL(override_creds);
451 583  
... ... @@ -460,7 +592,15 @@
460 592 {
461 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 602 rcu_assign_pointer(current->cred, old);
  603 + alter_cred_subscribers(override, -1);
464 604 put_cred(override);
465 605 }
466 606 EXPORT_SYMBOL(revert_creds);
467 607  
... ... @@ -502,11 +642,15 @@
502 642 if (!new)
503 643 return NULL;
504 644  
  645 + kdebug("prepare_kernel_cred() alloc %p", new);
  646 +
505 647 if (daemon)
506 648 old = get_task_cred(daemon);
507 649 else
508 650 old = get_cred(&init_cred);
509 651  
  652 + validate_creds(old);
  653 +
510 654 *new = *old;
511 655 get_uid(new->user);
512 656 get_group_info(new->group_info);
513 657  
... ... @@ -526,7 +670,9 @@
526 670 goto error;
527 671  
528 672 atomic_set(&new->usage, 1);
  673 + set_cred_subscribers(new, 0);
529 674 put_cred(old);
  675 + validate_creds(new);
530 676 return new;
531 677  
532 678 error:
... ... @@ -589,4 +735,96 @@
589 735 return security_kernel_create_files_as(new, inode);
590 736 }
591 737 EXPORT_SYMBOL(set_create_files_as);
  738 +
  739 +#ifdef CONFIG_DEBUG_CREDENTIALS
  740 +
  741 +/*
  742 + * dump invalid credentials
  743 + */
  744 +static 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 + */
  775 +void __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 +}
  782 +EXPORT_SYMBOL(__invalid_creds);
  783 +
  784 +/*
  785 + * check the credentials on a process
  786 + */
  787 +void __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 +
  803 +invalid_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 +}
  814 +EXPORT_SYMBOL(__validate_process_creds);
  815 +
  816 +/*
  817 + * check creds for do_exit()
  818 + */
  819 +void 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 */
... ... @@ -901,6 +901,8 @@
901 901  
902 902 tracehook_report_exit(&code);
903 903  
  904 + validate_creds_for_do_exit(tsk);
  905 +
904 906 /*
905 907 * We're taking recursive faults here in do_exit. Safest is to just
906 908 * leave this task alone and wait for reboot.
... ... @@ -1008,6 +1010,8 @@
1008 1010  
1009 1011 if (tsk->splice_pipe)
1010 1012 __free_pipe_info(tsk->splice_pipe);
  1013 +
  1014 + validate_creds_for_do_exit(tsk);
1011 1015  
1012 1016 preempt_disable();
1013 1017 /* causes final put_task_struct in finish_task_switch(). */
... ... @@ -152,8 +152,7 @@
152 152 WARN_ON(atomic_read(&tsk->usage));
153 153 WARN_ON(tsk == current);
154 154  
155   - put_cred(tsk->real_cred);
156   - put_cred(tsk->cred);
  155 + exit_creds(tsk);
157 156 delayacct_tsk_free(tsk);
158 157  
159 158 if (!profile_handoff_task(tsk))
... ... @@ -1307,8 +1306,7 @@
1307 1306 module_put(task_thread_info(p)->exec_domain->module);
1308 1307 bad_fork_cleanup_count:
1309 1308 atomic_dec(&p->cred->user->processes);
1310   - put_cred(p->real_cred);
1311   - put_cred(p->cred);
  1309 + exit_creds(p);
1312 1310 bad_fork_free:
1313 1311 free_task(p);
1314 1312 fork_out:
... ... @@ -466,6 +466,7 @@
466 466 int retval = 0;
467 467  
468 468 BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
  469 + validate_creds(sub_info->cred);
469 470  
470 471 helper_lock();
471 472 if (sub_info->path[0] == '\0')
... ... @@ -653,6 +653,21 @@
653 653 This is a relatively cheap check but if you care about maximum
654 654 performance, say N.
655 655  
  656 +config DEBUG_CREDENTIALS
  657 + bool "Debug credential management"
  658 + depends on DEBUG_KERNEL
  659 + help
  660 + Enable this to turn on some debug checking for credential
  661 + management. The additional code keeps track of the number of
  662 + pointers from task_structs to any given cred struct, and checks to
  663 + see that this number never exceeds the usage count of the cred
  664 + struct.
  665 +
  666 + Furthermore, if SELinux is enabled, this also checks that the
  667 + security pointer in the cred struct is never seen to be invalid.
  668 +
  669 + If unsure, say N.
  670 +
656 671 #
657 672 # Select this config option from the architecture Kconfig, if it
658 673 # it is preferred to always offer frame pointers as a config
security/selinux/hooks.c
... ... @@ -1531,6 +1531,8 @@
1531 1531 struct common_audit_data ad;
1532 1532 u32 sid;
1533 1533  
  1534 + validate_creds(cred);
  1535 +
1534 1536 if (unlikely(IS_PRIVATE(inode)))
1535 1537 return 0;
1536 1538  
... ... @@ -3236,7 +3238,9 @@
3236 3238 static void selinux_cred_free(struct cred *cred)
3237 3239 {
3238 3240 struct task_security_struct *tsec = cred->security;
3239   - cred->security = NULL;
  3241 +
  3242 + BUG_ON((unsigned long) cred->security < PAGE_SIZE);
  3243 + cred->security = (void *) 0x7UL;
3240 3244 kfree(tsec);
3241 3245 }
3242 3246