From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757701AbdELOBM (ORCPT ); Fri, 12 May 2017 10:01:12 -0400 Received: from foss.arm.com ([217.140.101.70]:60088 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757638AbdELOBD (ORCPT ); Fri, 12 May 2017 10:01:03 -0400 Date: Fri, 12 May 2017 15:00:23 +0100 From: Mark Rutland To: linux-kernel@vger.kernel.org, David Howells , Elena Reshetova Cc: keyrings@vger.kernel.org, Kees Cook , Hans Liljestrand , David Windsor , James Morris , Peter Zijlstra , Ingo Molnar Subject: next-20170510 refcount_inc() on zero / use-after-free in key_lookup() Message-ID: <20170512140023.GA18818@leverpostej> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, While fuzzing next-20170510 on arm64 with Syzkaller, I hit a refcount_inc() on a zero count in __key_get(), called from key_lookup(). The tree was dirty as I was testing with some new hardened string functions, but AFAICT these are not to blame. >>From a quick look at key_lookup(), the following looks very suspicious: found: /* pretend it doesn't exist if it is awaiting deletion */ if (refcount_read(&key->usage) == 0) goto not_found; /* this races with key_put(), but that doesn't matter since key_put() * doesn't actually change the key */ __key_get(key); ... as if we can race with key_put(), we can see a zero refcount here, and the race *does* matter. Full splat (and Syzkaller reproducer) below. See [1] for how to build Syzkaller and run the reproducer. I had to stick a udelay(10) between the refcount_read() and __key_get() in order to reproduce this reliably on my machine, due to the small window in key_lookup(). YMMV. Thanks, Mark. [1] https://github.com/google/syzkaller/wiki/How-to-execute-syzkaller-programs ------------[ cut here ]------------ WARNING: CPU: 0 PID: 3438 at lib/refcount.c:150 refcount_inc+0x78/0xa0 lib/refcount.c:150 Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 3438 Comm: syz-executor0 Not tainted 4.11.0-next-20170510-00001-g67f1150-dirty #6 Hardware name: linux,dummy-virt (DT) Call trace: [] dump_backtrace+0x0/0x538 arch/arm64/kernel/traps.c:73 [] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:228 [] __dump_stack lib/dump_stack.c:16 [inline] [] dump_stack+0x120/0x188 lib/dump_stack.c:52 [] panic+0x288/0x554 kernel/panic.c:180 [] __warn+0x25c/0x2b8 kernel/panic.c:541 [] report_bug+0x234/0x2e0 lib/bug.c:183 [] bug_handler.part.1+0x40/0x110 arch/arm64/kernel/traps.c:725 [] bug_handler+0x4c/0x88 arch/arm64/kernel/traps.c:722 [] call_break_hook arch/arm64/kernel/debug-monitors.c:303 [inline] [] brk_handler+0x1b8/0x360 arch/arm64/kernel/debug-monitors.c:318 [] do_debug_exception+0xfc/0x360 arch/arm64/mm/fault.c:683 Exception stack(0xffff80005eab7a40 to 0xffff80005eab7b70) 7a40: 0000000000000000 0001000000000000 ffff80005eab7c90 ffff200008c77808 7a60: 0000000080000145 000000000000003d ffff20000b878000 ffff20000b878e60 7a80: ffff20000b878da0 ffff8000655bb180 ffff80005eab7ba0 000000002000d000 7aa0: 0000000041b58ab3 ffff20000a90b450 ffff2000080819d8 ffff20000a2e70c0 7ac0: ffff800061f95e80 ffff20000b878e00 ffff20000b878000 ffff20000b878e60 7ae0: ffff80005eab7c90 ffff80005eab7c90 ffff80005eab7c50 00000000ffffffc8 7b00: 0000000041b58ab3 ffff20000a91dc28 ffff20000828c908 1fffe40001be8b32 7b20: 1ffff0000cab772d 1ffff0000cab772d ffff20000d705f80 ffff8000655bb948 7b40: ffff8000655bb948 1ffff0000cab7728 1ffff0000bd56f72 ffff8000655bb940 7b60: 000000000000002b ffff10000bd56f60 [] el1_dbg+0x18/0x74 [] __key_get include/linux/key.h:253 [inline] [] key_lookup+0x158/0x1c8 security/keys/key.c:670 [] lookup_user_key+0x128/0xdf8 security/keys/process_keys.c:680 [] keyctl_update_key+0xf4/0x1b0 security/keys/keyctl.c:340 [] SYSC_keyctl security/keys/keyctl.c:1647 [inline] [] SyS_keyctl+0x2ac/0x2e8 security/keys/keyctl.c:1635 [] el0_svc_naked+0x24/0x28 SMP: stopping secondary CPUs Kernel Offset: disabled Memory Limit: none Rebooting in 86400 seconds.. Syzkaller reproducer: # {Threaded:true Collide:true Repeat:true Procs:1 Sandbox:setuid Repro:false} mmap(&(0x7f0000000000/0xb000)=nil, (0xb000), 0x3, 0x32, 0xffffffffffffffff, 0x0) r0 = add_key(&(0x7f0000003000-0x8)="6b657972696e6700", &(0x7f0000005000-0x5)={0x73, 0x79, 0x7a, 0x0, 0x0}, &(0x7f0000006000)="", 0x0, 0xffffffffffffffff) r1 = request_key(&(0x7f0000006000-0x5)="6465616400", &(0x7f0000007000-0x5)={0x73, 0x79, 0x7a, 0x2, 0x0}, &(0x7f0000006000)="7472757374656465746831706f7369785f61636c5f6163636573736b657972696e675b47504c6264657600", 0xfffffffffffffffb) keyctl$unlink(0x9, r0, r1) socketpair(0x19, 0xa, 0x7, &(0x7f000000b000)={0xffffffffffffffff, 0xffffffffffffffff}) connect(0xffffffffffffffff, &(0x7f0000005000-0xc)=@nl={0x10, 0x0, 0x7, 0x1}, 0xc) mmap(&(0x7f000000c000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) keyctl$read(0xb, r0, &(0x7f000000c000)="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0x3c) gettid() mmap(&(0x7f000000d000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) getuid() mmap(&(0x7f0000005000/0x4000)=nil, (0x4000), 0x3, 0x110, 0xffffffffffffffff, 0x0) getresuid(&(0x7f000000d000)=0x0, &(0x7f000000d000)=0x0, &(0x7f000000e000-0x4)=0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f000000e000/0x1000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0) KEYCTl$update(0x2, r0, &(0x7f000000c000)="012c27e9d9b724cd535660d5c1a8618218e464709bb9f1f10488601c5b26ac08f9ea4223cb59259a83d344a32abe11dae8aa62a385044890f9eaf5", 0x3b)