From: Eric Paris Date: Mon, 21 Sep 2009 01:21:10 +0000 (-0400) Subject: SELinux: do not destroy the avc_cache_nodep X-Git-Tag: v2.6.32-rc1~152^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5224ee086321fec78970e2f2805892d2b34e8957;p=profile%2Fcommon%2Fkernel-common.git 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 --- diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 1ed0f076..b4b5da1 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); */ + } }