mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-17 01:23:58 -04:00
smb/server: avoid deadlock when linking with ReplaceIfExists
If smb2_create_link() is called with ReplaceIfExists set and the name does exist then a deadlock will happen. ksmbd_vfs_kern_path_locked() will return with success and the parent directory will be locked. ksmbd_vfs_remove_file() will then remove the file. ksmbd_vfs_link() will then be called while the parent is still locked. It will try to lock the same parent and will deadlock. This patch moves the ksmbd_vfs_kern_path_unlock() call to *before* ksmbd_vfs_link() and then simplifies the code, removing the file_present flag variable. Signed-off-by: NeilBrown <neil@brown.name> Acked-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
@@ -6037,7 +6037,6 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||||||
{
|
{
|
||||||
char *link_name = NULL, *target_name = NULL, *pathname = NULL;
|
char *link_name = NULL, *target_name = NULL, *pathname = NULL;
|
||||||
struct path path, parent_path;
|
struct path path, parent_path;
|
||||||
bool file_present = false;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (buf_len < (u64)sizeof(struct smb2_file_link_info) +
|
if (buf_len < (u64)sizeof(struct smb2_file_link_info) +
|
||||||
@@ -6070,11 +6069,8 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
if (rc != -ENOENT)
|
if (rc != -ENOENT)
|
||||||
goto out;
|
goto out;
|
||||||
} else
|
} else {
|
||||||
file_present = true;
|
if (file_info->ReplaceIfExists) {
|
||||||
|
|
||||||
if (file_info->ReplaceIfExists) {
|
|
||||||
if (file_present) {
|
|
||||||
rc = ksmbd_vfs_remove_file(work, &path);
|
rc = ksmbd_vfs_remove_file(work, &path);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
@@ -6082,21 +6078,17 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||||||
link_name);
|
link_name);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
|
||||||
if (file_present) {
|
|
||||||
rc = -EEXIST;
|
rc = -EEXIST;
|
||||||
ksmbd_debug(SMB, "link already exists\n");
|
ksmbd_debug(SMB, "link already exists\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ksmbd_vfs_link(work, target_name, link_name);
|
rc = ksmbd_vfs_link(work, target_name, link_name);
|
||||||
if (rc)
|
if (rc)
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
out:
|
out:
|
||||||
if (file_present)
|
|
||||||
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
|
|
||||||
|
|
||||||
if (!IS_ERR(link_name))
|
if (!IS_ERR(link_name))
|
||||||
kfree(link_name);
|
kfree(link_name);
|
||||||
|
|||||||
Reference in New Issue
Block a user