Skip to content

Commit 14d4ac1

Browse files
rkt-1597martinkpetersen
authored andcommitted
scsi: target: Fix recursive locking in __configfs_open_file()
In flush_write_buffer, &p->frag_sem is acquired and then the loaded store function is called, which, here, is target_core_item_dbroot_store(). This function called filp_open(), following which these functions were called (in reverse order), according to the call trace: down_read __configfs_open_file do_dentry_open vfs_open do_open path_openat do_filp_open file_open_name filp_open target_core_item_dbroot_store flush_write_buffer configfs_write_iter target_core_item_dbroot_store() tries to validate the new file path by trying to open the file path provided to it; however, in this case, the bug report shows: db_root: not a directory: /sys/kernel/config/target/dbroot indicating that the same configfs file was tried to be opened, on which it is currently working on. Thus, it is trying to acquire frag_sem semaphore of the same file of which it already holds the semaphore obtained in flush_write_buffer(), leading to acquiring the semaphore in a nested manner and a possibility of recursive locking. Fix this by modifying target_core_item_dbroot_store() to use kern_path() instead of filp_open() to avoid opening the file using filesystem-specific function __configfs_open_file(), and further modifying it to make this fix compatible. Reported-by: syzbot+f6e8174215573a84b797@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=f6e8174215573a84b797 Tested-by: syzbot+f6e8174215573a84b797@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com> Reviewed-by: Dmitry Bogdanov <d.bogdanov@yadro.com> Link: https://patch.msgid.link/20260216062002.61937-1-activprithvi@gmail.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 80bf3b2 commit 14d4ac1

1 file changed

Lines changed: 6 additions & 9 deletions

File tree

drivers/target/target_core_configfs.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
108108
const char *page, size_t count)
109109
{
110110
ssize_t read_bytes;
111-
struct file *fp;
112111
ssize_t r = -EINVAL;
112+
struct path path = {};
113113

114114
mutex_lock(&target_devices_lock);
115115
if (target_devices) {
@@ -131,17 +131,14 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
131131
db_root_stage[read_bytes - 1] = '\0';
132132

133133
/* validate new db root before accepting it */
134-
fp = filp_open(db_root_stage, O_RDONLY, 0);
135-
if (IS_ERR(fp)) {
134+
r = kern_path(db_root_stage, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
135+
if (r) {
136136
pr_err("db_root: cannot open: %s\n", db_root_stage);
137+
if (r == -ENOTDIR)
138+
pr_err("db_root: not a directory: %s\n", db_root_stage);
137139
goto unlock;
138140
}
139-
if (!S_ISDIR(file_inode(fp)->i_mode)) {
140-
filp_close(fp, NULL);
141-
pr_err("db_root: not a directory: %s\n", db_root_stage);
142-
goto unlock;
143-
}
144-
filp_close(fp, NULL);
141+
path_put(&path);
145142

146143
strscpy(db_root, db_root_stage);
147144
pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root);

0 commit comments

Comments
 (0)