Jiri Slaby 221c28
From: Baokun Li <libaokun1@huawei.com>
Jiri Slaby 221c28
Date: Tue, 10 Jan 2023 21:34:36 +0800
Jiri Slaby 221c28
Subject: [PATCH] ext4: fix task hung in ext4_xattr_delete_inode
Jiri Slaby 221c28
References: bsc#1012628
Jiri Slaby 221c28
Patch-mainline: 6.2.8
Jiri Slaby 221c28
Git-commit: 0f7bfd6f8164be32dbbdf36aa1e5d00485c53cd7
Jiri Slaby 221c28
Jiri Slaby 221c28
[ Upstream commit 0f7bfd6f8164be32dbbdf36aa1e5d00485c53cd7 ]
Jiri Slaby 221c28
Jiri Slaby 221c28
Syzbot reported a hung task problem:
Jiri Slaby 221c28
==================================================================
Jiri Slaby 221c28
INFO: task syz-executor232:5073 blocked for more than 143 seconds.
Jiri Slaby 221c28
      Not tainted 6.2.0-rc2-syzkaller-00024-g512dee0c00ad #0
Jiri Slaby 221c28
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Jiri Slaby 221c28
task:syz-exec232 state:D stack:21024 pid:5073 ppid:5072 flags:0x00004004
Jiri Slaby 221c28
Call Trace:
Jiri Slaby 221c28
 <TASK>
Jiri Slaby 221c28
 context_switch kernel/sched/core.c:5244 [inline]
Jiri Slaby 221c28
 __schedule+0x995/0xe20 kernel/sched/core.c:6555
Jiri Slaby 221c28
 schedule+0xcb/0x190 kernel/sched/core.c:6631
Jiri Slaby 221c28
 __wait_on_freeing_inode fs/inode.c:2196 [inline]
Jiri Slaby 221c28
 find_inode_fast+0x35a/0x4c0 fs/inode.c:950
Jiri Slaby 221c28
 iget_locked+0xb1/0x830 fs/inode.c:1273
Jiri Slaby 221c28
 __ext4_iget+0x22e/0x3ed0 fs/ext4/inode.c:4861
Jiri Slaby 221c28
 ext4_xattr_inode_iget+0x68/0x4e0 fs/ext4/xattr.c:389
Jiri Slaby 221c28
 ext4_xattr_inode_dec_ref_all+0x1a7/0xe50 fs/ext4/xattr.c:1148
Jiri Slaby 221c28
 ext4_xattr_delete_inode+0xb04/0xcd0 fs/ext4/xattr.c:2880
Jiri Slaby 221c28
 ext4_evict_inode+0xd7c/0x10b0 fs/ext4/inode.c:296
Jiri Slaby 221c28
 evict+0x2a4/0x620 fs/inode.c:664
Jiri Slaby 221c28
 ext4_orphan_cleanup+0xb60/0x1340 fs/ext4/orphan.c:474
Jiri Slaby 221c28
 __ext4_fill_super fs/ext4/super.c:5516 [inline]
Jiri Slaby 221c28
 ext4_fill_super+0x81cd/0x8700 fs/ext4/super.c:5644
Jiri Slaby 221c28
 get_tree_bdev+0x400/0x620 fs/super.c:1282
Jiri Slaby 221c28
 vfs_get_tree+0x88/0x270 fs/super.c:1489
Jiri Slaby 221c28
 do_new_mount+0x289/0xad0 fs/namespace.c:3145
Jiri Slaby 221c28
 do_mount fs/namespace.c:3488 [inline]
Jiri Slaby 221c28
 __do_sys_mount fs/namespace.c:3697 [inline]
Jiri Slaby 221c28
 __se_sys_mount+0x2d3/0x3c0 fs/namespace.c:3674
Jiri Slaby 221c28
 do_syscall_x64 arch/x86/entry/common.c:50 [inline]
Jiri Slaby 221c28
 do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80
Jiri Slaby 221c28
 entry_SYSCALL_64_after_hwframe+0x63/0xcd
Jiri Slaby 221c28
RIP: 0033:0x7fa5406fd5ea
Jiri Slaby 221c28
RSP: 002b:00007ffc7232f968 EFLAGS: 00000202 ORIG_RAX: 00000000000000a5
Jiri Slaby 221c28
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fa5406fd5ea
Jiri Slaby 221c28
RDX: 0000000020000440 RSI: 0000000020000000 RDI: 00007ffc7232f970
Jiri Slaby 221c28
RBP: 00007ffc7232f970 R08: 00007ffc7232f9b0 R09: 0000000000000432
Jiri Slaby 221c28
R10: 0000000000804a03 R11: 0000000000000202 R12: 0000000000000004
Jiri Slaby 221c28
R13: 0000555556a7a2c0 R14: 00007ffc7232f9b0 R15: 0000000000000000
Jiri Slaby 221c28
 </TASK>
Jiri Slaby 221c28
==================================================================
Jiri Slaby 221c28
Jiri Slaby 221c28
The problem is that the inode contains an xattr entry with ea_inum of 15
Jiri Slaby 221c28
when cleaning up an orphan inode <15>. When evict inode <15>, the reference
Jiri Slaby 221c28
counting of the corresponding EA inode is decreased. When EA inode <15> is
Jiri Slaby 221c28
found by find_inode_fast() in __ext4_iget(), it is found that the EA inode
Jiri Slaby 221c28
holds the I_FREEING flag and waits for the EA inode to complete deletion.
Jiri Slaby 221c28
As a result, when inode <15> is being deleted, we wait for inode <15> to
Jiri Slaby 221c28
complete the deletion, resulting in an infinite loop and triggering Hung
Jiri Slaby 221c28
Task. To solve this problem, we only need to check whether the ino of EA
Jiri Slaby 221c28
inode and parent is the same before getting EA inode.
Jiri Slaby 221c28
Jiri Slaby 221c28
Link: https://syzkaller.appspot.com/bug?extid=77d6fcc37bbb92f26048
Jiri Slaby 221c28
Reported-by: syzbot+77d6fcc37bbb92f26048@syzkaller.appspotmail.com
Jiri Slaby 221c28
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Jiri Slaby 221c28
Reviewed-by: Jan Kara <jack@suse.cz>
Jiri Slaby 221c28
Link: https://lore.kernel.org/r/20230110133436.996350-1-libaokun1@huawei.com
Jiri Slaby 221c28
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Jiri Slaby 221c28
Signed-off-by: Sasha Levin <sashal@kernel.org>
Jiri Slaby 221c28
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby 221c28
---
Jiri Slaby 221c28
 fs/ext4/xattr.c | 11 +++++++++++
Jiri Slaby 221c28
 1 file changed, 11 insertions(+)
Jiri Slaby 221c28
Jiri Slaby 221c28
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
Jiri Slaby 221c28
index 494994d9..f66c3fae 100644
Jiri Slaby 221c28
--- a/fs/ext4/xattr.c
Jiri Slaby 221c28
+++ b/fs/ext4/xattr.c
Jiri Slaby 221c28
@@ -388,6 +388,17 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
Jiri Slaby 221c28
 	struct inode *inode;
Jiri Slaby 221c28
 	int err;
Jiri Slaby 221c28
 
Jiri Slaby 221c28
+	/*
Jiri Slaby 221c28
+	 * We have to check for this corruption early as otherwise
Jiri Slaby 221c28
+	 * iget_locked() could wait indefinitely for the state of our
Jiri Slaby 221c28
+	 * parent inode.
Jiri Slaby 221c28
+	 */
Jiri Slaby 221c28
+	if (parent->i_ino == ea_ino) {
Jiri Slaby 221c28
+		ext4_error(parent->i_sb,
Jiri Slaby 221c28
+			   "Parent and EA inode have the same ino %lu", ea_ino);
Jiri Slaby 221c28
+		return -EFSCORRUPTED;
Jiri Slaby 221c28
+	}
Jiri Slaby 221c28
+
Jiri Slaby 221c28
 	inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_NORMAL);
Jiri Slaby 221c28
 	if (IS_ERR(inode)) {
Jiri Slaby 221c28
 		err = PTR_ERR(inode);
Jiri Slaby 221c28
-- 
Jiri Slaby 221c28
2.35.3
Jiri Slaby 221c28