diff mbox

fs: use-after-free in path_lookupat

Message ID CACT4Y+ZHgE2r9fGsDS_7CHsxa53yrsx0Zp0TBvH4oeqg24w5Yg@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dmitry Vyukov March 5, 2017, 11:37 a.m. UTC
On Sun, Mar 5, 2017 at 12:24 PM, Dmitry Vyukov <dvyukov@google.com> 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:

                                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] ==================================================================

Comments

Al Viro March 5, 2017, 3:57 p.m. UTC | #1
On Sun, Mar 05, 2017 at 12:37:13PM +0100, Dmitry Vyukov wrote:

> 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 :)

So what does it normally return?  On the runs where we do not hit that
use-after-free, that is.

What gets triggered there is nd->path.dentry pointing to already freed
dentry.  We are in RCU mode, so we are not pinning the dentry and it
might have reached dentry_free().  However, anything with DCACHE_RCUACCESS
set would have freeing RCU-delayed, making that impossible.

memfd stuff does *not* have DCACHE_RCUACCESS, which would've made it
plausible, but... there we really should've been stopped cold by
the d_can_lookup() check - that is done while we are still holding
a reference to struct file, which should've prevented freeing and
reuse.  So at the time of that check we have dentry still not reused
by anything, and d_can_lookup() should've failed.

There is a race that could bugger the things up in that area, but it needs
empty name, so this one is something else...
Dmitry Vyukov March 5, 2017, 4:14 p.m. UTC | #2
On Sun, Mar 5, 2017 at 4:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Sun, Mar 05, 2017 at 12:37:13PM +0100, Dmitry Vyukov wrote:
>
>> 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 :)
>
> So what does it normally return?  On the runs where we do not hit that
> use-after-free, that is.
>
> What gets triggered there is nd->path.dentry pointing to already freed
> dentry.  We are in RCU mode, so we are not pinning the dentry and it
> might have reached dentry_free().  However, anything with DCACHE_RCUACCESS
> set would have freeing RCU-delayed, making that impossible.
>
> memfd stuff does *not* have DCACHE_RCUACCESS, which would've made it
> plausible, but... there we really should've been stopped cold by
> the d_can_lookup() check - that is done while we are still holding
> a reference to struct file, which should've prevented freeing and
> reuse.  So at the time of that check we have dentry still not reused
> by anything, and d_can_lookup() should've failed.
>
> There is a race that could bugger the things up in that area, but it needs
> empty name, so this one is something else...

You can see from the log above that s always empty somehow, so the
d_can_lookup check is simply not done. I have not looked at the code,
but it's not racy, so should follow from the arguments passed to
name_to_handle_at.
Al Viro March 5, 2017, 4:33 p.m. UTC | #3
On Sun, Mar 05, 2017 at 05:14:23PM +0100, Dmitry Vyukov wrote:
> On Sun, Mar 5, 2017 at 4:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> > On Sun, Mar 05, 2017 at 12:37:13PM +0100, Dmitry Vyukov wrote:
> >
> >> 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 :)
> >
> > So what does it normally return?  On the runs where we do not hit that
> > use-after-free, that is.
> >
> > What gets triggered there is nd->path.dentry pointing to already freed
> > dentry.  We are in RCU mode, so we are not pinning the dentry and it
> > might have reached dentry_free().  However, anything with DCACHE_RCUACCESS
> > set would have freeing RCU-delayed, making that impossible.
> >
> > memfd stuff does *not* have DCACHE_RCUACCESS, which would've made it
> > plausible, but... there we really should've been stopped cold by
> > the d_can_lookup() check - that is done while we are still holding
> > a reference to struct file, which should've prevented freeing and
> > reuse.  So at the time of that check we have dentry still not reused
> > by anything, and d_can_lookup() should've failed.
> >
> > There is a race that could bugger the things up in that area, but it needs
> > empty name, so this one is something else...
> 
> You can see from the log above that s always empty somehow, so the
> d_can_lookup check is simply not done. I have not looked at the code,
> but it's not racy, so should follow from the arguments passed to
> name_to_handle_at.

Umm...  name_to_handle_at() in your log:
name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300", &(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0, 0x1000)
and unless I'm misreading what you are printing there, you have "./bus0"
passed as the second argument.  Right?  That's pretty much why I asked about
other possible calls triggering it...

If you are somehow getting there with empty name and if there's another
thread closing these memfd descriptors, I understand what's going on there.
It's how we are getting that empty name on your syscall arguments that
looks very odd...
Dmitry Vyukov March 5, 2017, 5:33 p.m. UTC | #4
On Sun, Mar 5, 2017 at 5:33 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Sun, Mar 05, 2017 at 05:14:23PM +0100, Dmitry Vyukov wrote:
>> On Sun, Mar 5, 2017 at 4:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>> > On Sun, Mar 05, 2017 at 12:37:13PM +0100, Dmitry Vyukov wrote:
>> >
>> >> 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 :)
>> >
>> > So what does it normally return?  On the runs where we do not hit that
>> > use-after-free, that is.
>> >
>> > What gets triggered there is nd->path.dentry pointing to already freed
>> > dentry.  We are in RCU mode, so we are not pinning the dentry and it
>> > might have reached dentry_free().  However, anything with DCACHE_RCUACCESS
>> > set would have freeing RCU-delayed, making that impossible.
>> >
>> > memfd stuff does *not* have DCACHE_RCUACCESS, which would've made it
>> > plausible, but... there we really should've been stopped cold by
>> > the d_can_lookup() check - that is done while we are still holding
>> > a reference to struct file, which should've prevented freeing and
>> > reuse.  So at the time of that check we have dentry still not reused
>> > by anything, and d_can_lookup() should've failed.
>> >
>> > There is a race that could bugger the things up in that area, but it needs
>> > empty name, so this one is something else...
>>
>> You can see from the log above that s always empty somehow, so the
>> d_can_lookup check is simply not done. I have not looked at the code,
>> but it's not racy, so should follow from the arguments passed to
>> name_to_handle_at.
>
> Umm...  name_to_handle_at() in your log:
> name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300", &(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0, 0x1000)
> and unless I'm misreading what you are printing there, you have "./bus0"
> passed as the second argument.  Right?  That's pretty much why I asked about
> other possible calls triggering it...
>
> If you are somehow getting there with empty name and if there's another
> thread closing these memfd descriptors, I understand what's going on there.
> It's how we are getting that empty name on your syscall arguments that
> looks very odd...


Added more debug output.

name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300",
&(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0,
0x1000)

actually passes name="" because of the overlapping addresses. Flags
contain AT_EMPTY_PATH.
Dmitry Vyukov March 5, 2017, 5:38 p.m. UTC | #5
On Sun, Mar 5, 2017 at 6:33 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
> On Sun, Mar 5, 2017 at 5:33 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>> On Sun, Mar 05, 2017 at 05:14:23PM +0100, Dmitry Vyukov wrote:
>>> On Sun, Mar 5, 2017 at 4:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>>> > On Sun, Mar 05, 2017 at 12:37:13PM +0100, Dmitry Vyukov wrote:
>>> >
>>> >> 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 :)
>>> >
>>> > So what does it normally return?  On the runs where we do not hit that
>>> > use-after-free, that is.
>>> >
>>> > What gets triggered there is nd->path.dentry pointing to already freed
>>> > dentry.  We are in RCU mode, so we are not pinning the dentry and it
>>> > might have reached dentry_free().  However, anything with DCACHE_RCUACCESS
>>> > set would have freeing RCU-delayed, making that impossible.
>>> >
>>> > memfd stuff does *not* have DCACHE_RCUACCESS, which would've made it
>>> > plausible, but... there we really should've been stopped cold by
>>> > the d_can_lookup() check - that is done while we are still holding
>>> > a reference to struct file, which should've prevented freeing and
>>> > reuse.  So at the time of that check we have dentry still not reused
>>> > by anything, and d_can_lookup() should've failed.
>>> >
>>> > There is a race that could bugger the things up in that area, but it needs
>>> > empty name, so this one is something else...
>>>
>>> You can see from the log above that s always empty somehow, so the
>>> d_can_lookup check is simply not done. I have not looked at the code,
>>> but it's not racy, so should follow from the arguments passed to
>>> name_to_handle_at.
>>
>> Umm...  name_to_handle_at() in your log:
>> name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300", &(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0, 0x1000)
>> and unless I'm misreading what you are printing there, you have "./bus0"
>> passed as the second argument.  Right?  That's pretty much why I asked about
>> other possible calls triggering it...
>>
>> If you are somehow getting there with empty name and if there's another
>> thread closing these memfd descriptors, I understand what's going on there.
>> It's how we are getting that empty name on your syscall arguments that
>> looks very odd...
>
>
> Added more debug output.
>
> name_to_handle_at(r4, &(0x7f0000003000-0x6)="2e2f62757300",
> &(0x7f0000003000-0xd)={0xc, 0x0, "cd21"}, &(0x7f0000002000)=0x0,
> 0x1000)
>
> actually passes name="" because of the overlapping addresses. Flags
> contain AT_EMPTY_PATH.


The problem can be more general as a bunch of xxxat calls support AT_EMPTY_PATH.
diff mbox

Patch

--- 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)) {