linux/fs/kernfs
Tejun Heo 1edfe4ea16 kernfs: Fix spurious lockdep warning in kernfs_find_and_get_node_by_id()
c25491747b ("kernfs: Add KERNFS_REMOVING flags") made
kernfs_find_and_get_node_by_id() test kernfs_active() instead of
KERNFS_ACTIVATED. kernfs_find_and_get_by_id() is called without holding the
kernfs_rwsem triggering the following lockdep warning.

  WARNING: CPU: 1 PID: 6191 at fs/kernfs/dir.c:36 kernfs_active+0xe8/0x120 fs/kernfs/dir.c:38
  Modules linked in:
  CPU: 1 PID: 6191 Comm: syz-executor.1 Not tainted 6.0.0-syzkaller-09413-g4899a36f91a9 #0
  Hardware name: linux,dummy-virt (DT)
  pstate: 10000005 (nzcV daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
  pc : kernfs_active+0xe8/0x120 fs/kernfs/dir.c:36
  lr : lock_is_held include/linux/lockdep.h:283 [inline]
  lr : kernfs_active+0x94/0x120 fs/kernfs/dir.c:36
  sp : ffff8000182c7a00
  x29: ffff8000182c7a00 x28: 0000000000000002 x27: 0000000000000001
  x26: ffff00000ee1f6a8 x25: 1fffe00001dc3ed5 x24: 0000000000000000
  x23: ffff80000ca1fba0 x22: ffff8000089efcb0 x21: 0000000000000001
  x20: ffff0000091181d0 x19: ffff0000091181d0 x18: ffff00006a9e6b88
  x17: 0000000000000000 x16: 0000000000000000 x15: ffff00006a9e6bc4
  x14: 1ffff00003058f0e x13: 1fffe0000258c816 x12: ffff700003058f39
  x11: 1ffff00003058f38 x10: ffff700003058f38 x9 : dfff800000000000
  x8 : ffff80000e482f20 x7 : ffff0000091d8058 x6 : ffff80000e482c60
  x5 : ffff000009402ee8 x4 : 1ffff00001bd1f46 x3 : 1fffe0000258c6d1
  x2 : 0000000000000003 x1 : 00000000000000c0 x0 : 0000000000000000
  Call trace:
   kernfs_active+0xe8/0x120 fs/kernfs/dir.c:38
   kernfs_find_and_get_node_by_id+0x6c/0x140 fs/kernfs/dir.c:708
   __kernfs_fh_to_dentry fs/kernfs/mount.c:102 [inline]
   kernfs_fh_to_dentry+0x88/0x1fc fs/kernfs/mount.c:128
   exportfs_decode_fh_raw+0x104/0x560 fs/exportfs/expfs.c:435
   exportfs_decode_fh+0x10/0x5c fs/exportfs/expfs.c:575
   do_handle_to_path fs/fhandle.c:152 [inline]
   handle_to_path fs/fhandle.c:207 [inline]
   do_handle_open+0x2a4/0x7b0 fs/fhandle.c:223
   __do_compat_sys_open_by_handle_at fs/fhandle.c:277 [inline]
   __se_compat_sys_open_by_handle_at fs/fhandle.c:274 [inline]
   __arm64_compat_sys_open_by_handle_at+0x6c/0x9c fs/fhandle.c:274
   __invoke_syscall arch/arm64/kernel/syscall.c:38 [inline]
   invoke_syscall+0x6c/0x260 arch/arm64/kernel/syscall.c:52
   el0_svc_common.constprop.0+0xc4/0x254 arch/arm64/kernel/syscall.c:142
   do_el0_svc_compat+0x40/0x70 arch/arm64/kernel/syscall.c:212
   el0_svc_compat+0x54/0x140 arch/arm64/kernel/entry-common.c:772
   el0t_32_sync_handler+0x90/0x140 arch/arm64/kernel/entry-common.c:782
   el0t_32_sync+0x190/0x194 arch/arm64/kernel/entry.S:586
  irq event stamp: 232
  hardirqs last  enabled at (231): [<ffff8000081edf70>] raw_spin_rq_unlock_irq kernel/sched/sched.h:1367 [inline]
  hardirqs last  enabled at (231): [<ffff8000081edf70>] finish_lock_switch kernel/sched/core.c:4943 [inline]
  hardirqs last  enabled at (231): [<ffff8000081edf70>] finish_task_switch.isra.0+0x200/0x880 kernel/sched/core.c:5061
  hardirqs last disabled at (232): [<ffff80000c888bb4>] el1_dbg+0x24/0x80 arch/arm64/kernel/entry-common.c:404
  softirqs last  enabled at (228): [<ffff800008010938>] _stext+0x938/0xf58
  softirqs last disabled at (207): [<ffff800008019380>] ____do_softirq+0x10/0x20 arch/arm64/kernel/irq.c:79
  ---[ end trace 0000000000000000 ]---

The lockdep warning in kernfs_active() is there to ensure that the activated
state stays stable for the caller. For kernfs_find_and_get_node_by_id(), all
that's needed is ensuring that a node which has never been activated can't
be looked up and guaranteeing lookup success when the caller knows the node
to be active, both of which can be achieved by testing the active count
without holding the kernfs_rwsem.

Fix the spurious warning by introducing __kernfs_active() which doesn't have
the lockdep annotation.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: syzbot+590ce62b128e79cf0a35@syzkaller.appspotmail.com
Fixes: c25491747b ("kernfs: Add KERNFS_REMOVING flags")
Cc: Amir Goldstein <amir73il@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Link: https://lore.kernel.org/r/Y0SwqBsZ9BMmZv6x@slm.duckdns.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-11-10 19:03:42 +01:00
..
dir.c kernfs: Fix spurious lockdep warning in kernfs_find_and_get_node_by_id() 2022-11-10 19:03:42 +01:00
file.c kernfs: Skip kernfs_drain_open_files() more aggressively 2022-09-01 18:08:44 +02:00
inode.c kernfs: switch global kernfs_rwsem lock to per-fs lock 2021-11-24 13:55:16 +01:00
Kconfig treewide: Add SPDX license identifier - Makefile/Kconfig 2019-05-21 10:50:46 +02:00
kernfs-internal.h kernfs: Skip kernfs_drain_open_files() more aggressively 2022-09-01 18:08:44 +02:00
Makefile treewide: Add SPDX license identifier - Makefile/Kconfig 2019-05-21 10:50:46 +02:00
mount.c kernfs: Replace global kernfs_open_file_mutex with hashed mutexes. 2022-06-27 16:46:15 +02:00
symlink.c kernfs: switch global kernfs_rwsem lock to per-fs lock 2021-11-24 13:55:16 +01:00