[syzbot ci] Re: kernfs: Add inotify IN_DELETE_SELF, IN_IGNORED support

0 views
Skip to first unread message

syzbot ci

unread,
5:14 AM (17 hours ago) 5:14 AM
to amir...@gmail.com, cgr...@vger.kernel.org, drive...@lists.linux.dev, gre...@linuxfoundation.org, ja...@suse.cz, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, sh...@kernel.org, t...@kernel.org, tjme...@google.com, syz...@lists.linux.dev, syzkall...@googlegroups.com
syzbot ci has tested the following series

[v4] kernfs: Add inotify IN_DELETE_SELF, IN_IGNORED support
https://lore.kernel.org/all/20260220055449....@google.com
* [PATCH v4 1/3] kernfs: Don't set_nlink for directories being removed
* [PATCH v4 2/3] kernfs: Send IN_DELETE_SELF and IN_IGNORED
* [PATCH v4 3/3] selftests: memcg: Add tests for IN_DELETE_SELF and IN_IGNORED

and found the following issue:
possible deadlock in __kernfs_remove

Full report is available here:
https://ci.syzbot.org/series/4b44d5c2-c2eb-4425-a19a-f9963b64f74f

***

possible deadlock in __kernfs_remove

tree: bpf-next
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next.git
base: ba268514ea14b44570030e8ed2aef92a38679e85
arch: amd64
compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
config: https://ci.syzbot.org/builds/45ab774f-e8d7-4def-8279-888a5cb2d01e/config
syz repro: https://ci.syzbot.org/findings/b74cbc6a-1cef-4ae9-be46-dd9e8b29b648/syz_repro

======================================================
WARNING: possible circular locking dependency detected
syzkaller #0 Not tainted
------------------------------------------------------
kworker/u8:1/13 is trying to acquire lock:
ffff88816ef2b878 (kn->active#5){++++}-{0:0}, at: __kernfs_remove+0x47e/0x8c0 fs/kernfs/dir.c:1533

but task is already holding lock:
ffff8881012e8ab8 (&root->kernfs_supers_rwsem){++++}-{4:4}, at: kernfs_remove_by_name_ns+0x3f/0x140 fs/kernfs/dir.c:1745

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #2 (&root->kernfs_supers_rwsem){++++}-{4:4}:
down_read+0x47/0x2e0 kernel/locking/rwsem.c:1537
kernfs_remove_by_name_ns+0x3f/0x140 fs/kernfs/dir.c:1745
acpi_unbind_one+0x2d8/0x3b0 drivers/acpi/glue.c:337
device_platform_notify_remove drivers/base/core.c:2386 [inline]
device_del+0x547/0x8f0 drivers/base/core.c:3881
serdev_controller_add+0x46f/0x640 drivers/tty/serdev/core.c:785
serdev_tty_port_register+0x159/0x260 drivers/tty/serdev/serdev-ttyport.c:291
tty_port_register_device_attr_serdev+0xe7/0x170 drivers/tty/tty_port.c:187
serial_core_add_one_port drivers/tty/serial/serial_core.c:3107 [inline]
serial_core_register_port+0x103a/0x28b0 drivers/tty/serial/serial_core.c:3305
serial8250_register_8250_port+0x1658/0x1fd0 drivers/tty/serial/8250/8250_core.c:822
serial_pnp_probe+0x568/0x7f0 drivers/tty/serial/8250/8250_pnp.c:480
pnp_device_probe+0x30b/0x4c0 drivers/pnp/driver.c:111
call_driver_probe drivers/base/dd.c:-1 [inline]
really_probe+0x267/0xaf0 drivers/base/dd.c:661
__driver_probe_device+0x18c/0x320 drivers/base/dd.c:803
driver_probe_device+0x4f/0x240 drivers/base/dd.c:833
__driver_attach+0x3e7/0x710 drivers/base/dd.c:1227
bus_for_each_dev+0x23b/0x2c0 drivers/base/bus.c:383
bus_add_driver+0x345/0x670 drivers/base/bus.c:715
driver_register+0x23a/0x320 drivers/base/driver.c:249
serial8250_init+0x8f/0x160 drivers/tty/serial/8250/8250_platform.c:317
do_one_initcall+0x250/0x840 init/main.c:1378
do_initcall_level+0x104/0x190 init/main.c:1440
do_initcalls+0x59/0xa0 init/main.c:1456
kernel_init_freeable+0x2a6/0x3d0 init/main.c:1688
kernel_init+0x1d/0x1d0 init/main.c:1578
ret_from_fork+0x51b/0xa40 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246

-> #1 (&device->physical_node_lock){+.+.}-{4:4}:
__mutex_lock_common kernel/locking/mutex.c:614 [inline]
__mutex_lock+0x19f/0x1300 kernel/locking/mutex.c:776
acpi_get_first_physical_node drivers/acpi/bus.c:691 [inline]
acpi_primary_dev_companion drivers/acpi/bus.c:710 [inline]
acpi_companion_match+0x8a/0x120 drivers/acpi/bus.c:764
acpi_device_uevent_modalias+0x1a/0x30 drivers/acpi/device_sysfs.c:280
platform_uevent+0x3c/0xb0 drivers/base/platform.c:1411
dev_uevent+0x446/0x8a0 drivers/base/core.c:2692
kobject_uevent_env+0x477/0x9e0 lib/kobject_uevent.c:573
kobject_synth_uevent+0x585/0xbd0 lib/kobject_uevent.c:207
uevent_store+0x26/0x70 drivers/base/core.c:2773
kernfs_fop_write_iter+0x3af/0x540 fs/kernfs/file.c:352
new_sync_write fs/read_write.c:593 [inline]
vfs_write+0x61d/0xb90 fs/read_write.c:686
ksys_write+0x150/0x270 fs/read_write.c:738
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

-> #0 (kn->active#5){++++}-{0:0}:
check_prev_add kernel/locking/lockdep.c:3165 [inline]
check_prevs_add kernel/locking/lockdep.c:3284 [inline]
validate_chain kernel/locking/lockdep.c:3908 [inline]
__lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237
lock_acquire+0x106/0x330 kernel/locking/lockdep.c:5868
kernfs_drain+0x27c/0x5f0 fs/kernfs/dir.c:511
__kernfs_remove+0x47e/0x8c0 fs/kernfs/dir.c:1533
kernfs_remove_by_name_ns+0xc0/0x140 fs/kernfs/dir.c:1751
sysfs_remove_file include/linux/sysfs.h:780 [inline]
device_remove_file drivers/base/core.c:3071 [inline]
device_del+0x506/0x8f0 drivers/base/core.c:3876
device_unregister+0x21/0xf0 drivers/base/core.c:3919
mac80211_hwsim_del_radio+0x2dc/0x490 drivers/net/wireless/virtual/mac80211_hwsim.c:5918
hwsim_exit_net+0xede/0xfa0 drivers/net/wireless/virtual/mac80211_hwsim.c:6807
ops_exit_list net/core/net_namespace.c:199 [inline]
ops_undo_list+0x49f/0x940 net/core/net_namespace.c:252
cleanup_net+0x4df/0x7b0 net/core/net_namespace.c:696
process_one_work kernel/workqueue.c:3257 [inline]
process_scheduled_works+0xaec/0x17a0 kernel/workqueue.c:3340
worker_thread+0xda6/0x1360 kernel/workqueue.c:3421
kthread+0x726/0x8b0 kernel/kthread.c:463
ret_from_fork+0x51b/0xa40 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246

other info that might help us debug this:

Chain exists of:
kn->active#5 --> &device->physical_node_lock --> &root->kernfs_supers_rwsem

Possible unsafe locking scenario:

CPU0 CPU1
---- ----
rlock(&root->kernfs_supers_rwsem);
lock(&device->physical_node_lock);
lock(&root->kernfs_supers_rwsem);
lock(kn->active#5);

*** DEADLOCK ***

4 locks held by kworker/u8:1/13:
#0: ffff888100ef7948 ((wq_completion)netns){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3232 [inline]
#0: ffff888100ef7948 ((wq_completion)netns){+.+.}-{0:0}, at: process_scheduled_works+0x9d4/0x17a0 kernel/workqueue.c:3340
#1: ffffc90000127bc0 (net_cleanup_work){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3233 [inline]
#1: ffffc90000127bc0 (net_cleanup_work){+.+.}-{0:0}, at: process_scheduled_works+0xa0f/0x17a0 kernel/workqueue.c:3340
#2: ffffffff8f99d2d0 (pernet_ops_rwsem){++++}-{4:4}, at: cleanup_net+0xfe/0x7b0 net/core/net_namespace.c:670
#3: ffff8881012e8ab8 (&root->kernfs_supers_rwsem){++++}-{4:4}, at: kernfs_remove_by_name_ns+0x3f/0x140 fs/kernfs/dir.c:1745

stack backtrace:
CPU: 0 UID: 0 PID: 13 Comm: kworker/u8:1 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Workqueue: netns cleanup_net
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_circular_bug+0x2e1/0x300 kernel/locking/lockdep.c:2043
check_noncircular+0x12e/0x150 kernel/locking/lockdep.c:2175
check_prev_add kernel/locking/lockdep.c:3165 [inline]
check_prevs_add kernel/locking/lockdep.c:3284 [inline]
validate_chain kernel/locking/lockdep.c:3908 [inline]
__lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237
lock_acquire+0x106/0x330 kernel/locking/lockdep.c:5868
kernfs_drain+0x27c/0x5f0 fs/kernfs/dir.c:511
__kernfs_remove+0x47e/0x8c0 fs/kernfs/dir.c:1533
kernfs_remove_by_name_ns+0xc0/0x140 fs/kernfs/dir.c:1751
sysfs_remove_file include/linux/sysfs.h:780 [inline]
device_remove_file drivers/base/core.c:3071 [inline]
device_del+0x506/0x8f0 drivers/base/core.c:3876
device_unregister+0x21/0xf0 drivers/base/core.c:3919
mac80211_hwsim_del_radio+0x2dc/0x490 drivers/net/wireless/virtual/mac80211_hwsim.c:5918
hwsim_exit_net+0xede/0xfa0 drivers/net/wireless/virtual/mac80211_hwsim.c:6807
ops_exit_list net/core/net_namespace.c:199 [inline]
ops_undo_list+0x49f/0x940 net/core/net_namespace.c:252
cleanup_net+0x4df/0x7b0 net/core/net_namespace.c:696
process_one_work kernel/workqueue.c:3257 [inline]
process_scheduled_works+0xaec/0x17a0 kernel/workqueue.c:3340
worker_thread+0xda6/0x1360 kernel/workqueue.c:3421
kthread+0x726/0x8b0 kernel/kthread.c:463
ret_from_fork+0x51b/0xa40 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246
</TASK>
hsr_slave_0: left promiscuous mode
hsr_slave_1: left promiscuous mode
batman_adv: batadv0: Interface deactivated: batadv_slave_0
batman_adv: batadv0: Removing interface: batadv_slave_0
batman_adv: batadv0: Interface deactivated: batadv_slave_1
batman_adv: batadv0: Removing interface: batadv_slave_1
veth1_macvtap: left promiscuous mode
veth0_macvtap: left promiscuous mode
veth1_vlan: left promiscuous mode
veth0_vlan: left promiscuous mode
team0 (unregistering): Port device team_slave_1 removed
team0 (unregistering): Port device team_slave_0 removed
netdevsim netdevsim2 netdevsim0: set [1, 0] type 2 family 0 port 6081 - 0
netdevsim netdevsim2 netdevsim1: set [1, 0] type 2 family 0 port 6081 - 0
netdevsim netdevsim2 netdevsim2: set [1, 0] type 2 family 0 port 6081 - 0
netdevsim netdevsim2 netdevsim3: set [1, 0] type 2 family 0 port 6081 - 0


***

If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syz...@syzkaller.appspotmail.com

---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzk...@googlegroups.com.

T.J. Mercier

unread,
1:44 PM (9 hours ago) 1:44 PM
to syzbot ci, amir...@gmail.com, cgr...@vger.kernel.org, drive...@lists.linux.dev, gre...@linuxfoundation.org, ja...@suse.cz, linux-...@vger.kernel.org, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, sh...@kernel.org, t...@kernel.org, syz...@lists.linux.dev, syzkall...@googlegroups.com
Hm, I can see two ways to fix this.

The first is to drop the acpi_dev->physical_node_lock mutex in
acpi_unbind_one before calling sysfs_remove_link. This keeps the node
ID reserved while the sysfs files are still being removed, so that we
don't get any sysfs filename collisions (which are based on the node
ID). This seems like a good optimization to do anyway:

+++ b/drivers/acpi/glue.c
@@ -329,18 +329,22 @@ int acpi_unbind_one(struct device *dev)
list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
if (entry->dev == dev) {
char physnode_name[PHYSICAL_NODE_NAME_SIZE];

- list_del(&entry->node);
- acpi_dev->physical_node_count--;
+ entry->dev = NULL;
+ mutex_unlock(&acpi_dev->physical_node_lock);

acpi_physnode_link_name(physnode_name, entry->node_id);
sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
sysfs_remove_link(&dev->kobj, "firmware_node");
ACPI_COMPANION_SET(dev, NULL);
/* Drop references taken by acpi_bind_one(). */
put_device(dev);
acpi_dev_put(acpi_dev);
+
+ mutex_lock(&acpi_dev->physical_node_lock);
+ list_del(&entry->node);
+ acpi_dev->physical_node_count--;
kfree(entry);
break;
}


The second is to drop the kernfs_supers_rwsem for the kernfs_drain,
similar to how the kernfs_rwsem is dropped there. I don't think
kernfs_supers_rwsem is usually heavily contended, but it's probably a
good idea to avoid holding it while potentially sleeping in
kernfs_drain. Since the kernfs_supers_rwsem is only held for
kernfs_drain in __kernfs_remove (but not kernfs_show) that means:

+++ b/fs/kernfs/dir.c
@@ -486,7 +486,7 @@ void kernfs_put_active(struct kernfs_node *kn)
* removers may invoke this function concurrently on @kn and all will
* return after draining is complete.
*/
-static void kernfs_drain(struct kernfs_node *kn)
+static void kernfs_drain(struct kernfs_node *kn, bool drop_supers)
__releases(&kernfs_root(kn)->kernfs_rwsem)
__acquires(&kernfs_root(kn)->kernfs_rwsem)
{
@@ -506,6 +506,8 @@ static void kernfs_drain(struct kernfs_node *kn)
return;

up_write(&root->kernfs_rwsem);
+ if (drop_supers)
+ up_read(&root->kernfs_supers_rwsem);

if (kernfs_lockdep(kn)) {
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
@@ -524,6 +526,8 @@ static void kernfs_drain(struct kernfs_node *kn)
if (kernfs_should_drain_open_files(kn))
kernfs_drain_open_files(kn);

+ if (drop_supers)
+ down_read(&root->kernfs_supers_rwsem);
down_write(&root->kernfs_rwsem);
}

@@ -1465,7 +1469,7 @@ void kernfs_show(struct kernfs_node *kn, bool show)
kn->flags |= KERNFS_HIDDEN;
if (kernfs_active(kn))
atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
- kernfs_drain(kn);
+ kernfs_drain(kn, false);
}

up_write(&root->kernfs_rwsem);
@@ -1530,7 +1534,7 @@ static void __kernfs_remove(struct kernfs_node *kn)
*/
kernfs_get(pos);

- kernfs_drain(pos);
+ kernfs_drain(pos, true);
parent = kernfs_parent(pos);
/*
* kernfs_unlink_sibling() succeeds once per node. Use it
Reply all
Reply to author
Forward
0 new messages