[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241112073421.GD1458936@google.com>
Date: Tue, 12 Nov 2024 16:34:21 +0900
From: Sergey Senozhatsky <senozhatsky@...omium.org>
To: Theodore Ts'o <tytso@....edu>,
Andreas Dilger <adilger.kernel@...ger.ca>
Cc: linux-ext4@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: ext4: possible circular locking dependency at ext4_xattr_inode_create
Hi,
I've a following syzkaller report (no reproducer); the report is
against 5.15, but the same call-chain seems possible in current
upstream as well. So I suspect that maybe ext4_xattr_inode_create()
should take nested inode_lock (I_MUTEX_XATTR) instead. Does the
patch below make any sense?
======================================================
WARNING: possible circular locking dependency detected
5.15.168-syzkaller-23766-g3f37c55c6291 #0 Not tainted
------------------------------------------------------
syz-executor297/1452 is trying to acquire lock:
ffff888120b5e750 (&ea_inode->i_rwsem#8/1){+.+.}-{3:3}, at: inode_lock
ffff888120b5e750 (&ea_inode->i_rwsem#8/1){+.+.}-{3:3}, at: ext4_xattr_inode_create
ffff888120b5e750 (&ea_inode->i_rwsem#8/1){+.+.}-{3:3}, at: ext4_xattr_inode_lookup_create
ffff888120b5e750 (&ea_inode->i_rwsem#8/1){+.+.}-{3:3}, at: ext4_xattr_set_entry+0x2aeb/0x3200
but task is already holding lock:
ffff888120b58c68 (&ei->i_data_sem/3){++++}-{3:3}, at: ext4_setattr+0x12b5/0x1950
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&ei->i_data_sem/3){++++}-{3:3}:
down_write+0x38/0x60
ext4_update_i_disksize
ext4_xattr_inode_write
ext4_xattr_inode_lookup_create
ext4_xattr_set_entry+0x2839/0x3200
ext4_xattr_ibody_set+0x113/0x320
ext4_xattr_set_handle+0xa31/0x1440
ext4_xattr_set+0x266/0x3d0
__vfs_setxattr+0x15e/0x1c0
__vfs_setxattr_noperm+0x128/0x5e0
vfs_setxattr+0x1c6/0x410
setxattr+0x1d6/0x270
path_setxattr+0x1cc/0x2b0
__do_sys_lsetxattr
__se_sys_lsetxattr
__x64_sys_lsetxattr+0xb4/0xd0
do_syscall_x64
do_syscall_64+0x69/0xc0
entry_SYSCALL_64_after_hwframe+0x66/0xd0
-> #0 (&ea_inode->i_rwsem#8/1){+.+.}-{3:3}:
check_prev_add
check_prevs_add
validate_chain
__lock_acquire+0x2c95/0x7850
lock_acquire+0x1d2/0x4e0
down_write+0x38/0x60
inode_lock
ext4_xattr_inode_create
ext4_xattr_inode_lookup_create
ext4_xattr_set_entry+0x2aeb/0x3200
ext4_xattr_block_set+0xdc1/0x2de0
ext4_xattr_move_to_block
ext4_xattr_make_inode_space
ext4_expand_extra_isize_ea+0xe58/0x19c0
__ext4_expand_extra_isize+0x2fd/0x400
ext4_try_to_expand_extra_isize
__ext4_mark_inode_dirty+0x58b/0x840
ext4_setattr+0x1341/0x1950
notify_change+0xafb/0xd80
do_truncate+0x218/0x2f0
handle_truncate
do_open
path_openat+0x27d3/0x2e10
do_filp_open+0x23a/0x360
do_sys_openat2+0x188/0x720
do_sys_open+0x1d1/0x220
do_syscall_x64
do_syscall_64+0x69/0xc0
entry_SYSCALL_64_after_hwframe+0x66/0xd0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&ei->i_data_sem/3);
lock(&ea_inode->i_rwsem#8/1);
lock(&ei->i_data_sem/3);
lock(&ea_inode->i_rwsem#8/1);
*** DEADLOCK ***
5 locks held by syz-executor297/1452:
#0: ffff88811231c460 (sb_writers#5){.+.+}-{0:0}, at: mnt_want_write+0x3b/0x80
#1: ffff888120b58de0 (&sb->s_type->i_mutex_key#8){++++}-{3:3}, at: inode_lock
#1: ffff888120b58de0 (&sb->s_type->i_mutex_key#8){++++}-{3:3}, at: do_truncate+0x204/0x2f0
#2: ffff888120b58f80 (mapping.invalidate_lock){++++}-{3:3}, at: filemap_invalidate_lock
#2: ffff888120b58f80 (mapping.invalidate_lock){++++}-{3:3}, at: ext4_setattr+0xd49/0x1950
#3: ffff888120b58c68 (&ei->i_data_sem/3){++++}-{3:3}, at: ext4_setattr+0x12b5/0x1950
#4: ffff888120b58ab8 (&ei->xattr_sem){++++}-{3:3}, at: ext4_write_trylock_xattr
#4: ffff888120b58ab8 (&ei->xattr_sem){++++}-{3:3}, at: ext4_try_to_expand_extra_isize
#4: ffff888120b58ab8 (&ei->xattr_sem){++++}-{3:3}, at: __ext4_mark_inode_dirty+0x4f7/0x840
stack backtrace:
Call Trace:
<TASK>
__dump_stack
dump_stack_lvl+0x1e3/0x2d0
check_noncircular+0x2f3/0x3a0
check_prev_add
check_prevs_add
validate_chain
__lock_acquire+0x2c95/0x7850
lock_acquire+0x1d2/0x4e0
down_write+0x38/0x60
inode_lock
ext4_xattr_inode_create
ext4_xattr_inode_lookup_create
ext4_xattr_set_entry+0x2aeb/0x3200
ext4_xattr_block_set+0xdc1/0x2de0
ext4_xattr_move_to_block
ext4_xattr_make_inode_space
ext4_expand_extra_isize_ea+0xe58/0x19c0
__ext4_expand_extra_isize+0x2fd/0x400
ext4_try_to_expand_extra_isize
__ext4_mark_inode_dirty+0x58b/0x840
ext4_setattr+0x1341/0x1950
notify_change+0xafb/0xd80
do_truncate+0x218/0x2f0
handle_truncate
do_open
path_openat+0x27d3/0x2e10
do_filp_open+0x23a/0x360
do_sys_openat2+0x188/0x720
do_sys_open+0x1d1/0x220
do_syscall_x64
do_syscall_64+0x69/0xc0
entry_SYSCALL_64_after_hwframe+0x66/0xd0
---
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 7647e9f6e190..db3c68fbbadf 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1511,7 +1511,7 @@ static struct inode *ext4_xattr_inode_create(handle_t *handle,
*/
dquot_free_inode(ea_inode);
dquot_drop(ea_inode);
- inode_lock(ea_inode);
+ inode_lock_nested(inode, I_MUTEX_XATTR);
ea_inode->i_flags |= S_NOQUOTA;
inode_unlock(ea_inode);
}
Powered by blists - more mailing lists