Commit 14d4ac19 authored by Prithvi Tambewagh's avatar Prithvi Tambewagh Committed by Martin K. Petersen
Browse files

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: default avatar <syzbot+f6e8174215573a84b797@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=f6e8174215573a84b797


Tested-by: default avatar <syzbot+f6e8174215573a84b797@syzkaller.appspotmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPrithvi Tambewagh <activprithvi@gmail.com>
Reviewed-by: default avatarDmitry Bogdanov <d.bogdanov@yadro.com>
Link: https://patch.msgid.link/20260216062002.61937-1-activprithvi@gmail.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 80bf3b28
Loading
Loading
Loading
Loading
+6 −9
Original line number Diff line number Diff line
@@ -108,8 +108,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
					const char *page, size_t count)
{
	ssize_t read_bytes;
	struct file *fp;
	ssize_t r = -EINVAL;
	struct path path = {};

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

	/* validate new db root before accepting it */
	fp = filp_open(db_root_stage, O_RDONLY, 0);
	if (IS_ERR(fp)) {
	r = kern_path(db_root_stage, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
	if (r) {
		pr_err("db_root: cannot open: %s\n", db_root_stage);
		goto unlock;
	}
	if (!S_ISDIR(file_inode(fp)->i_mode)) {
		filp_close(fp, NULL);
		if (r == -ENOTDIR)
			pr_err("db_root: not a directory: %s\n", db_root_stage);
		goto unlock;
	}
	filp_close(fp, NULL);
	path_put(&path);

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