From 74908a0009eb36054190ab80deb9671014efed96 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Sep 2009 17:47:12 -0700 Subject: [PATCH 1/5] include/linux/cred.h: fix build mips allmodconfig: include/linux/cred.h: In function `creds_are_invalid': include/linux/cred.h:187: error: `PAGE_SIZE' undeclared (first use in this function) include/linux/cred.h:187: error: (Each undeclared identifier is reported only once include/linux/cred.h:187: error: for each function it appears in.) Fixes commit b6dff3ec5e116e3af6f537d4caedcad6b9e5082a Author: David Howells AuthorDate: Fri Nov 14 10:39:16 2008 +1100 Commit: James Morris CommitDate: Fri Nov 14 10:39:16 2008 +1100 CRED: Separate task security context from task_struct I think. It's way too large to be inlined anyway. Dunno if this needs an EXPORT_SYMBOL() yet. Cc: David Howells Cc: James Morris Cc: Serge Hallyn Signed-off-by: Andrew Morton Acked-by: David Howells Signed-off-by: James Morris --- include/linux/cred.h | 18 +----------------- kernel/cred.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/include/linux/cred.h b/include/linux/cred.h index fb371601a3b4..4e3387a89cb9 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -176,23 +176,7 @@ extern void __invalid_creds(const struct cred *, const char *, unsigned); extern void __validate_process_creds(struct task_struct *, const char *, unsigned); -static inline bool creds_are_invalid(const struct cred *cred) -{ - if (cred->magic != CRED_MAGIC) - return true; - if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) - return true; -#ifdef CONFIG_SECURITY_SELINUX - if (selinux_is_enabled()) { - if ((unsigned long) cred->security < PAGE_SIZE) - return true; - if ((*(u32 *)cred->security & 0xffffff00) == - (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) - return true; - } -#endif - return false; -} +extern bool creds_are_invalid(const struct cred *cred); static inline void __validate_creds(const struct cred *cred, const char *file, unsigned line) diff --git a/kernel/cred.c b/kernel/cred.c index d7f7a01082eb..70bda79fae24 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -782,6 +782,24 @@ EXPORT_SYMBOL(set_create_files_as); #ifdef CONFIG_DEBUG_CREDENTIALS +bool creds_are_invalid(const struct cred *cred) +{ + if (cred->magic != CRED_MAGIC) + return true; + if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) + return true; +#ifdef CONFIG_SECURITY_SELINUX + if (selinux_is_enabled()) { + if ((unsigned long) cred->security < PAGE_SIZE) + return true; + if ((*(u32 *)cred->security & 0xffffff00) == + (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) + return true; + } +#endif + return false; +} + /* * dump invalid credentials */ From 764db03fee50f7a3de91de80ef4a943f0d720801 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 18 Sep 2009 11:06:47 -0700 Subject: [PATCH 2/5] creds_are_invalid() needs to be exported for use by modules: ERROR: "creds_are_invalid" [fs/cachefiles/cachefiles.ko] undefined! Signed-off-by: Randy Dunlap Cc: David Howells Cc: James Morris Cc: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: James Morris --- kernel/cred.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/cred.c b/kernel/cred.c index 70bda79fae24..dd76cfe5f5b0 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -799,6 +799,7 @@ bool creds_are_invalid(const struct cred *cred) #endif return false; } +EXPORT_SYMBOL(creds_are_invalid); /* * dump invalid credentials From 0afd9056f1b43c9fcbfdf933b263d72023d382fe Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 18 Sep 2009 12:54:24 -0700 Subject: [PATCH 3/5] tpm-fixup-pcrs-sysfs-file-update Signed-off-by: Jason Gunthorpe Cc: Debora Velarde Cc: Rajiv Andrade Cc: Marcel Selhorst Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index b0603b2e5684..1f32b520ca26 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -742,7 +742,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); * the module usage count. */ #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) -#define EXTEND_PCR_SIZE 34 +#define EXTEND_PCR_RESULT_SIZE 34 static struct tpm_input_header pcrextend_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(34), @@ -760,10 +760,9 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) return -ENODEV; cmd.header.in = pcrextend_header; - BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE); cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, cmd.header.in.length, + rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, "attempting extend a PCR value"); module_put(chip->dev->driver->owner); From 606531c316d30e9639473a6da09ee917125ab467 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 16 Sep 2009 15:54:14 +0100 Subject: [PATCH 4/5] KEYS: Have the garbage collector set its timer for live expired keys The key garbage collector sets a timer to start a new collection cycle at the point the earliest key to expire should be considered garbage. However, it currently only does this if the key it is considering hasn't yet expired. If the key being considering has expired, but hasn't yet reached the collection time then it is ignored, and won't be collected until some other key provokes a round of collection. Make the garbage collector set the timer for the earliest key that hasn't yet passed its collection time, rather than the earliest key that hasn't yet expired. Signed-off-by: David Howells Signed-off-by: James Morris --- security/keys/gc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/keys/gc.c b/security/keys/gc.c index 485fc6233c38..4770be375ffe 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -169,9 +169,9 @@ static void key_garbage_collector(struct work_struct *work) /* trawl through the keys looking for keyrings */ for (;;) { - if (key->expiry > now && key->expiry < new_timer) { + if (key->expiry > limit && key->expiry < new_timer) { kdebug("will expire %x in %ld", - key_serial(key), key->expiry - now); + key_serial(key), key->expiry - limit); new_timer = key->expiry; } From 5224ee086321fec78970e2f2805892d2b34e8957 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Sun, 20 Sep 2009 21:21:10 -0400 Subject: [PATCH 5/5] SELinux: do not destroy the avc_cache_nodep The security_ops reset done when SELinux is disabled at run time is done after the avc cache is freed and after the kmem_cache for the avc is also freed. This means that between the time the selinux disable code destroys the avc_node_cachep another process could make a security request and could try to allocate from the cache. We are just going to leave the cachep around, like we always have. SELinux: Disabled at runtime. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] kmem_cache_alloc+0x9a/0x185 PGD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC last sysfs file: CPU 1 Modules linked in: Pid: 12, comm: khelper Not tainted 2.6.31-tip-05525-g0eeacc6-dirty #14819 System Product Name RIP: 0010:[] [] kmem_cache_alloc+0x9a/0x185 RSP: 0018:ffff88003f9258b0 EFLAGS: 00010086 RAX: 0000000000000001 RBX: 0000000000000000 RCX: 0000000078c0129e RDX: 0000000000000000 RSI: ffffffff8130b626 RDI: ffffffff81122528 RBP: ffff88003f925900 R08: 0000000078c0129e R09: 0000000000000001 R10: 0000000000000000 R11: 0000000078c0129e R12: 0000000000000246 R13: 0000000000008020 R14: ffff88003f8586d8 R15: 0000000000000001 FS: 0000000000000000(0000) GS:ffff880002b00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000000 CR3: 0000000001001000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: ffffffff827bd420 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process khelper (pid: 12, threadinfo ffff88003f924000, task ffff88003f928000) Stack: 0000000000000246 0000802000000246 ffffffff8130b626 0000000000000001 <0> 0000000078c0129e 0000000000000000 ffff88003f925a70 0000000000000002 <0> 0000000000000001 0000000000000001 ffff88003f925960 ffffffff8130b626 Call Trace: [] ? avc_alloc_node+0x36/0x273 [] avc_alloc_node+0x36/0x273 [] ? avc_latest_notif_update+0x7d/0x9e [] avc_insert+0x51/0x18d [] avc_has_perm_noaudit+0x9d/0x128 [] avc_has_perm+0x45/0x88 [] current_has_perm+0x52/0x6d [] selinux_task_create+0x2f/0x45 [] security_task_create+0x29/0x3f [] copy_process+0x82/0xdf0 [] ? register_lock_class+0x2f/0x36c [] ? mark_lock+0x2e/0x1e1 [] do_fork+0x16e/0x382 [] ? register_lock_class+0x2f/0x36c [] ? probe_workqueue_execution+0x57/0xf9 [] ? mark_lock+0x2e/0x1e1 [] ? probe_workqueue_execution+0x57/0xf9 [] kernel_thread+0x82/0xe0 [] ? ____call_usermodehelper+0x0/0x139 [] ? child_rip+0x0/0x20 [] ? __call_usermodehelper+0x65/0x9a [] run_workqueue+0x171/0x27e [] ? run_workqueue+0x11d/0x27e [] ? __call_usermodehelper+0x0/0x9a [] worker_thread+0xe8/0x10f [] ? autoremove_wake_function+0x0/0x63 [] ? worker_thread+0x0/0x10f [] kthread+0x91/0x99 [] child_rip+0xa/0x20 [] ? restore_args+0x0/0x30 [] ? kthread+0x0/0x99 [] ? child_rip+0x0/0x20 Code: 0f 85 99 00 00 00 9c 58 66 66 90 66 90 49 89 c4 fa 66 66 90 66 66 90 e8 83 34 fb ff e8 d7 e9 26 00 48 98 49 8b 94 c6 10 01 00 00 <48> 8b 1a 44 8b 7a 18 48 85 db 74 0f 8b 42 14 48 8b 04 c3 ff 42 RIP [] kmem_cache_alloc+0x9a/0x185 RSP CR2: 0000000000000000 ---[ end trace 42f41a982344e606 ]--- Reported-by: Ingo Molnar Signed-off-by: Eric Paris Signed-off-by: James Morris --- security/selinux/avc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 1ed0f076aadc..b4b5da1c0a42 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -868,8 +868,19 @@ u32 avc_policy_seqno(void) void avc_disable(void) { - avc_flush(); - synchronize_rcu(); - if (avc_node_cachep) - kmem_cache_destroy(avc_node_cachep); + /* + * If you are looking at this because you have realized that we are + * not destroying the avc_node_cachep it might be easy to fix, but + * I don't know the memory barrier semantics well enough to know. It's + * possible that some other task dereferenced security_ops when + * it still pointed to selinux operations. If that is the case it's + * possible that it is about to use the avc and is about to need the + * avc_node_cachep. I know I could wrap the security.c security_ops call + * in an rcu_lock, but seriously, it's not worth it. Instead I just flush + * the cache and get that memory back. + */ + if (avc_node_cachep) { + avc_flush(); + /* kmem_cache_destroy(avc_node_cachep); */ + } }