mainline inclusion from mainline-v7.2-rc1 commit be6d26bf27499977c746abc163659915082348d8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/16688 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- smb2_query_dir() stores a pointer to its stack-allocated private data in the ksmbd_file readdir_data. Concurrent QUERY_DIRECTORY requests using the same file handle can overwrite this pointer while an iterate_dir() callback is still using it, resulting in a stack use-after-free. Add a per-file mutex and hold it while accessing the shared directory enumeration state. The lock covers scan restart, dot entry state, readdir_data setup and iteration, and response construction. This prevents another request from replacing readdir_data.private before the current request has finished using it and also serializes the shared file position. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-30527 Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> Conflicts: fs/ksmbd/smb2pdu.c fs/ksmbd/vfs_cache.c fs/ksmbd/vfs_cache.h [ctx conflicts] Signed-off-by: Lai Zewei <laizewei3@huawei.com> --- fs/ksmbd/smb2pdu.c | 4 ++++ fs/ksmbd/vfs_cache.c | 1 + fs/ksmbd/vfs_cache.h | 2 ++ 3 files changed, 7 insertions(+) diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index d799f2bbd73f..ff3bcd2f7c46 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -3985,6 +3985,8 @@ int smb2_query_dir(struct ksmbd_work *work) ksmbd_debug(SMB, "Search pattern is %s\n", srch_ptr); } + mutex_lock(&dir_fp->readdir_lock); + ksmbd_debug(SMB, "Directory name is %s\n", dir_fp->filename); if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) { @@ -4073,6 +4075,7 @@ int smb2_query_dir(struct ksmbd_work *work) inc_rfc1001_len(work->response_buf, 8 + d_info.data_count); } + mutex_unlock(&dir_fp->readdir_lock); kfree(srch_ptr); ksmbd_fd_put(work, dir_fp); ksmbd_revert_fsids(work); @@ -4080,6 +4083,7 @@ int smb2_query_dir(struct ksmbd_work *work) err_out: pr_err("error while processing smb2 query dir rc = %d\n", rc); + mutex_unlock(&dir_fp->readdir_lock); kfree(srch_ptr); err_out2: diff --git a/fs/ksmbd/vfs_cache.c b/fs/ksmbd/vfs_cache.c index 2a445befcc62..a56f47a5ad32 100644 --- a/fs/ksmbd/vfs_cache.c +++ b/fs/ksmbd/vfs_cache.c @@ -564,6 +564,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp) INIT_LIST_HEAD(&fp->node); INIT_LIST_HEAD(&fp->lock_list); spin_lock_init(&fp->f_lock); + mutex_init(&fp->readdir_lock); atomic_set(&fp->refcount, 1); fp->filp = filp; diff --git a/fs/ksmbd/vfs_cache.h b/fs/ksmbd/vfs_cache.h index 36239ce31afd..aa0ede0019aa 100644 --- a/fs/ksmbd/vfs_cache.h +++ b/fs/ksmbd/vfs_cache.h @@ -8,6 +8,7 @@ #include <linux/file.h> #include <linux/fs.h> +#include <linux/mutex.h> #include <linux/rwsem.h> #include <linux/spinlock.h> #include <linux/idr.h> @@ -98,6 +99,7 @@ struct ksmbd_file { /* if ls is happening on directory, below is valid*/ struct ksmbd_readdir_data readdir_data; + struct mutex readdir_lock; int dot_dotdot[2]; }; -- 2.52.0