Re: fs: use-after-free in path_lookupat
From: Dmitry Vyukov
Date: Sun Mar 05 2017 - 06:46:13 EST
On Sun, Mar 5, 2017 at 12:24 PM, Dmitry Vyukov <dvyukov@xxxxxxxxxx> wrote:
>>>> On Sat, Mar 04, 2017 at 03:59:36PM +0100, Dmitry Vyukov wrote:
>>>>
>>>>> I am getting the following use-after-free reports while running
>>>>> syzkaller fuzzer on 86292b33d4b79ee03e2f43ea0381ef85f077c760 (but also
>>>>> happened on 6dc39c50e4aeb769c8ae06edf2b1a732f3490913 and
>>>>> c82be9d2244aacea9851c86f4fb74694c99cd874).
>>>>
>>>> IOW, it's not fs/namei.c patches from this window...
>>>>
>>>>> unlazy_walk+0xf2/0x4b0 fs/namei.c:692
>>>>
>>>> Could you post disassembly (e.g. from objdump -d) of your unlazy_walk()?
>>>> For the kernel the trace is from...
>>>>
>>>>> r4 = memfd_create(&(0x7f0000013000)="2f6465762f6877726e6700", 0x0)
>>>>> name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300",
>>>>> &(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0,
>>>>> 0x1000)
>>>>>
>>>>> What's strange is that dirfd passed to name_to_handle_at is memfd
>>>>> handle (sic). And path lookup somehow does not fail early on this.
>>>>> Does it make any sense?
>>>>
>>>> It doesn't, but is that the triggering call of name_to_handle_at(), or do you
>>>> have it called elsewhere?
I am pretty sure it is that one.
I don't think I ever used name_to_handle_at syscall in my life and I
definitely didn't make it lookup a memfd :)
>>>> FWIW, no LOOKUP_ROOT in filename_lookup() flags + NULL root + dfd not
>>>> equal to AT_FDCWD + non-empty name should've ended up in
>>>> if (!d_can_lookup(dentry)) {
>>>> fdput(f);
>>>> return ERR_PTR(-ENOTDIR);
>>>> }
>>>> in path_init() and it shouldn't have progressed any further. And in case
>>>> of name_to_handle_at() we have user_path_at(dfd, name, lookup_flags, &path),
>>>> i.e. user_path_at_empty(dfd, name, lookup_flags, &path, NULL), i.e.
>>>> filename_lookup(dfd, getname_flags(name, lookup_flags, NULL), lookup_flags,
>>>> &path, NULL). IOW, filename_lookup() is called with root equal to NULL,
>>>> dfd and name coming straight from userland and lookup_flags containing
>>>> nothing beyond LOOKUP_EMPTY and LOOKUP_FOLLOW...
> Yes, but still it somehow happens...
I've added this diff:
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2213,6 +2213,7 @@ static const char *path_init(struct nameidata
*nd, unsigned flags)
dentry = f.file->f_path.dentry;
+pr_err("%d: path_init: s=%s flags=%d\n", current->pid, s, dentry->d_flags);
if (*s) {
if (!d_can_lookup(dentry)) {
fdput(f);
Most of the time flags are 4194304, but occasionally they are 5243016:
[ 172.559822] 21279: path_init: s= flags=4194304
[ 172.572357] 21275: path_init: s= flags=4194304
[ 172.605964] 21297: path_init: s= flags=4194304
[ 172.609712] 21301: path_init: s= flags=4194304
[ 172.620832] 21287: path_init: s= flags=4194304
[ 172.651228] 21288: path_init: s= flags=4194304
[ 172.660516] 21306: path_init: s= flags=4194304
[ 172.689294] 21308: path_init: s= flags=4194304
[ 172.689743] 21281: path_init: s= flags=4194304
[ 172.705908] 21313: path_init: s= flags=4194304
[ 172.755287] 21297: path_init: s= flags=5243016
[ 172.762358] 21306: path_init: s= flags=4194304
[ 172.763248] 21306: path_init: s= flags=4194304
[ 172.766700] 21317: path_init: s= flags=4194304
[ 172.775612] 21313: path_init: s= flags=4194304
[ 172.797624] 21308: path_init: s= flags=4194304
[ 172.798709] 21328: path_init: s= flags=4194304
[ 172.800170] 21322: path_init: s= flags=4194304
...
[ 179.202077] 22190: path_init: s= flags=4194304
[ 179.209753] 22189: path_init: s= flags=4194304
[ 179.211614] 22187: path_init: s= flags=4194304
[ 179.223048] 22165: path_init: s= flags=4194304
[ 179.271114] 22195: path_init: s= flags=4194304
[ 179.290350] 22182: path_init: s= flags=4194304
[ 179.301246] 22189: path_init: s= flags=4194304
[ 179.325996] 22202: path_init: s= flags=4194304
[ 179.327900] 22203: path_init: s= flags=4194304
[ 179.349044] 22195: path_init: s= flags=4194304
[ 179.363826] 22211: path_init: s= flags=4194304
[ 179.364938] 22207: path_init: s= flags=4194304
[ 179.364985] 22206: path_init: s= flags=4194304
[ 179.415240] 22214: path_init: s= flags=4194304
[ 179.464470] 22219: path_init: s= flags=4194304
[ 179.484437] 22225: path_init: s= flags=4194304
[ 179.489139] 22207: path_init: s= flags=4194304
[ 179.495212] 22206: path_init: s= flags=4194304
[ 179.521143] 22216: path_init: s= flags=4194304
[ 179.526780] 22228: path_init: s= flags=4194304
[ 179.540650] 22227: path_init: s= flags=4194304
[ 179.545824] 22225: path_init: s= flags=4194304
[ 179.574581] 22214: path_init: s= flags=4194304
[ 179.577168] 22236: path_init: s= flags=4194304
[ 179.618489] 22240: path_init: s= flags=4194304
[ 179.644057] 22243: path_init: s= flags=4194304
[ 179.647793] 22228: path_init: s= flags=4194304
[ 179.680428] 22248: path_init: s= flags=4194304
[ 179.716533] 22240: path_init: s= flags=4194304
[ 179.720363] 22227: path_init: s= flags=4194304
[ 179.721421] 22236: path_init: s= flags=4194304
[ 179.722195] 22249: path_init: s= flags=4194304
[ 179.729854] 22252: path_init: s= flags=4194304
[ 179.772353] 22248: path_init: s= flags=5243016
[ 179.778042] 22243: path_init: s= flags=4194304
[ 179.779056] ==================================================================
[ 179.779707] BUG: KASAN: use-after-free in
perf_trace_lock_acquire+0x9cf/0xa00 at addr ffff88005c34c930
[ 179.780010] Read of size 8 by task syz-executor/22243
[ 179.780010] CPU: 2 PID: 22243 Comm: syz-executor Not tainted 4.10.0+ #294
[ 179.781396] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS Bochs 01/01/2011
[ 179.782914] Call Trace:
[ 179.782914] dump_stack+0x2fb/0x3fd
[ 179.782914] ? arch_local_irq_restore+0x53/0x53
[ 179.782914] ? vprintk_emit+0x566/0x770
[ 179.782914] ? console_unlock+0xf50/0xf50
[ 179.782914] ? console_unlock+0xf50/0xf50
[ 179.782914] ? lock_set_class+0xc00/0xc00
[ 179.782914] ? __lock_is_held+0xb6/0x140
[ 179.782914] ? check_noncircular+0x20/0x20
[ 179.782914] ? lock_set_class+0xc00/0xc00
[ 179.782914] ? __handle_mm_fault+0x1c84/0x2cd0
[ 179.782914] ? vprintk_default+0x28/0x30
[ 179.789989] ? vprintk_func+0x47/0x90
[ 179.789989] ? printk+0xc8/0xf9
[ 179.789989] ? load_image_and_restore+0x134/0x134
[ 179.789989] kasan_object_err+0x1c/0x90
[ 179.789989] kasan_report.part.2+0x1b0/0x460
[ 179.789989] ? kasan_check_write+0x14/0x20
[ 179.789989] ? do_raw_spin_lock+0xbd/0x1f0
[ 179.789989] ? perf_trace_lock_acquire+0x9cf/0xa00
[ 179.789989] __asan_report_load8_noabort+0x29/0x30
[ 179.789989] perf_trace_lock_acquire+0x9cf/0xa00
[ 179.789989] ? RECLAIM_FS_verbose+0x10/0x10
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? __do_page_fault+0x51b/0xb60
[ 179.789989] ? lock_acquire+0x630/0x630
[ 179.789989] ? memset+0x31/0x40
[ 179.789989] lock_acquire+0x473/0x630
[ 179.789989] ? lockref_get_not_dead+0x19/0x80
[ 179.789989] ? lock_set_class+0xc00/0xc00
[ 179.789989] ? trace_hardirqs_on_caller+0x545/0x6f0
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? trace_hardirqs_on_caller+0x545/0x6f0
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? retint_kernel+0x10/0x10
[ 179.789989] ? trace_hardirqs_on_caller+0x545/0x6f0
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? trace_hardirqs_on_caller+0x545/0x6f0
[ 179.789989] ? mark_held_locks+0x100/0x100
[ 179.789989] ? trace_hardirqs_on_thunk+0x1a/0x1c
[ 179.789989] ? retint_kernel+0x10/0x10
[ 179.789989] _raw_spin_lock+0x33/0x50
[ 179.789989] ? lockref_get_not_dead+0x19/0x80
[ 179.789989] lockref_get_not_dead+0x19/0x80
[ 179.789989] legitimize_path.isra.36+0x7d/0x1a0
[ 179.789989] unlazy_walk+0xf2/0x4b0
[ 179.789989] complete_walk+0xb2/0x1f0
[ 179.789989] path_lookupat+0x1c1/0x400
[ 179.789989] filename_lookup+0x282/0x540
[ 179.789989] ? filename_parentat+0x5b0/0x5b0
[ 179.806362] ? kmem_cache_alloc+0x3f5/0x6e0
[ 179.806648] ? getname_flags+0x256/0x580
[ 179.806648] user_path_at_empty+0x40/0x50
[ 179.806648] SyS_name_to_handle_at+0xff/0x720
[ 179.806648] ? vfs_dentry_acceptable+0x10/0x10
[ 179.806648] ? retint_kernel+0x10/0x10
[ 179.806648] entry_SYSCALL_64_fastpath+0x1f/0xc2
[ 179.806648] RIP: 0033:0x4458d9
[ 179.806648] RSP: 002b:00007faa1547cb58 EFLAGS: 00000286 ORIG_RAX:
000000000000012f
[ 179.806648] RAX: ffffffffffffffda RBX: 0000000000000050 RCX: 00000000004458d9
[ 179.806648] RDX: 0000000020002ff3 RSI: 0000000020002ffa RDI: 0000000000000050
[ 179.806648] RBP: 00000000006e11b0 R08: 0000000000001000 R09: 0000000000000000
[ 179.806648] R10: 0000000020002000 R11: 0000000000000286 R12: 0000000000708000
[ 179.806648] R13: 0000000000000000 R14: 00007faa1547d9c0 R15: 00007faa1547d700
[ 179.806648] Object at ffff88005c34c880, in cache dentry size: 288
[ 179.814491] 22252: path_init: s= flags=4194304
[ 179.806648] Allocated:
[ 179.806648] PID = 22260
[ 179.806648] save_stack_trace+0x16/0x20
[ 179.806648] save_stack+0x43/0xd0
[ 179.816189] kasan_kmalloc+0xaa/0xd0
[ 179.816189] kasan_slab_alloc+0x12/0x20
[ 179.816189] kmem_cache_alloc+0x102/0x6e0
[ 179.816189] __d_alloc+0xb3/0xbb0
[ 179.816189] d_alloc_pseudo+0x1d/0x30
[ 179.816189] __shmem_file_setup+0x20c/0x5a0
[ 179.816189] SyS_memfd_create+0x172/0x2c0
[ 179.816189] entry_SYSCALL_64_fastpath+0x1f/0xc2
[ 179.816189] Freed:
[ 179.816189] PID = 22265
[ 179.816189] save_stack_trace+0x16/0x20
[ 179.816189] save_stack+0x43/0xd0
[ 179.816189] kasan_slab_free+0x6f/0xb0
[ 179.816189] kmem_cache_free+0x71/0x240
[ 179.816189] dentry_free+0xd5/0x160
[ 179.816189] __dentry_kill+0x471/0x6d0
[ 179.816189] dput.part.25+0x5ce/0x7c0
[ 179.816189] dput+0x1f/0x30
[ 179.816189] __fput+0x538/0x800
[ 179.816189] ____fput+0x15/0x20
[ 179.816189] task_work_run+0x197/0x260
[ 179.816189] exit_to_usermode_loop+0x23b/0x2a0
[ 179.816189] syscall_return_slowpath+0x4d3/0x570
[ 179.816189] entry_SYSCALL_64_fastpath+0xc0/0xc2
[ 179.816189] Disposed:
[ 179.816189] PID = 21945
[ 179.816189] save_stack_trace+0x16/0x20
[ 179.816189] save_stack+0x43/0xd0
[ 179.816189] kasan_set_rcu_track+0xcf/0xf0
[ 179.816189] __call_rcu.constprop.77+0x1d6/0x15a0
[ 179.816189] call_rcu_sched+0x12/0x20
[ 179.816189] dentry_free+0xb7/0x160
[ 179.816189] __dentry_kill+0x471/0x6d0
[ 179.816189] dput.part.25+0x4fe/0x7c0
[ 179.816189] dput+0x1f/0x30
[ 179.816189] __debugfs_remove.part.10+0xb8/0xf0
[ 179.816189] debugfs_remove+0xea/0x1f0
[ 179.816189] bdi_unregister+0x2f9/0x550
[ 179.816189] bdi_destroy+0x15/0x20
[ 179.816189] v9fs_session_init+0x905/0x1a30
[ 179.816189] v9fs_mount+0x81/0x830
[ 179.816189] mount_fs+0x97/0x2e0
[ 179.816189] vfs_kern_mount.part.23+0xc6/0x490
[ 179.816189] do_mount+0x418/0x2da0
[ 179.816189] SyS_mount+0xab/0x120
[ 179.816189] entry_SYSCALL_64_fastpath+0x1f/0xc2
[ 179.816189] Memory state around the buggy address:
[ 179.816189] ffff88005c34c800: fb fb fb fb fb fb fb fb fc fc fc fc
fc fc fc fc
[ 179.816189] ffff88005c34c880: fb fb fb fb fb fb fb fb fb fb fb fb
fb fb fb fb
[ 179.816189] >ffff88005c34c900: fb fb fb fb fb fb fb fb fb fb fb fb
fb fb fb fb
[ 179.816189] ^
[ 179.816189] ffff88005c34c980: fb fb fb fb fc fc fc fc fc fc fc fc
00 00 00 00
[ 179.816189] ffff88005c34ca00: 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00
[ 179.816189] ==================================================================