From: Namjae Jeon namjae.jeon@samsung.com
mainline inclusion from mainline-5.15-rc1 commit c36fca8630dda0fba7b9672f3c99ac4e260a0fd0 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I60T7G CVE: NA
Reference: https://git.kernel.org/torvalds/linux/c/c36fca8630dd
-------------------------------
This patch add the check to work file lock and rename behaviors like Windows if POSIX extensions are not negotiated.
Signed-off-by: Namjae Jeon namjae.jeon@samsung.com Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- fs/cifsd/vfs.c | 101 +++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 45 deletions(-)
diff --git a/fs/cifsd/vfs.c b/fs/cifsd/vfs.c index e860ff9145a7..f93cc55ea153 100644 --- a/fs/cifsd/vfs.c +++ b/fs/cifsd/vfs.c @@ -370,7 +370,6 @@ int ksmbd_vfs_read(struct ksmbd_work *work, char *rbuf, *name; struct inode *inode; char namebuf[NAME_MAX]; - int ret;
rbuf = work->aux_payload_buf; filp = fp->filp; @@ -391,11 +390,15 @@ int ksmbd_vfs_read(struct ksmbd_work *work, if (ksmbd_stream_fd(fp)) return ksmbd_vfs_stream_read(fp, rbuf, pos, count);
- ret = check_lock_range(filp, *pos, *pos + count - 1, - READ); - if (ret) { - ksmbd_err("unable to read due to lock\n"); - return -EAGAIN; + if (!work->tcon->posix_extensions) { + int ret; + + ret = check_lock_range(filp, *pos, *pos + count - 1, + READ); + if (ret) { + ksmbd_err("unable to read due to lock\n"); + return -EAGAIN; + } }
nbytes = kernel_read(filp, rbuf, count, pos); @@ -504,11 +507,13 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, goto out; }
- err = check_lock_range(filp, *pos, *pos + count - 1, WRITE); - if (err) { - ksmbd_err("unable to write due to lock\n"); - err = -EAGAIN; - goto out; + if (!work->tcon->posix_extensions) { + err = check_lock_range(filp, *pos, *pos + count - 1, WRITE); + if (err) { + ksmbd_err("unable to write due to lock\n"); + err = -EAGAIN; + goto out; + } }
/* Do we need to break any of a levelII oplock? */ @@ -706,21 +711,23 @@ static int __ksmbd_vfs_rename(struct ksmbd_work *work, struct dentry *dst_dent; int err;
- spin_lock(&src_dent->d_lock); - list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { - struct ksmbd_file *child_fp; + if (!work->tcon->posix_extensions) { + spin_lock(&src_dent->d_lock); + list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { + struct ksmbd_file *child_fp;
- if (d_really_is_negative(dst_dent)) - continue; + if (d_really_is_negative(dst_dent)) + continue;
- child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); - if (child_fp) { - spin_unlock(&src_dent->d_lock); - ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); - return -EACCES; + child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); + if (child_fp) { + spin_unlock(&src_dent->d_lock); + ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); + return -EACCES; + } } + spin_unlock(&src_dent->d_lock); } - spin_unlock(&src_dent->d_lock);
if (d_really_is_negative(src_dent_parent)) return -ENOENT; @@ -820,7 +827,6 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, { struct path path; int err = 0; - struct inode *inode;
if (name) { err = kern_path(name, 0, &path); @@ -842,18 +848,21 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, /* Do we need to break any of a levelII oplock? */ smb_break_all_levII_oplock(work, fp, 1);
- inode = file_inode(filp); - if (size < inode->i_size) { - err = check_lock_range(filp, size, - inode->i_size - 1, WRITE); - } else { - err = check_lock_range(filp, inode->i_size, - size - 1, WRITE); - } + if (!work->tcon->posix_extensions) { + struct inode *inode = file_inode(filp);
- if (err) { - ksmbd_err("failed due to lock\n"); - return -EAGAIN; + if (size < inode->i_size) { + err = check_lock_range(filp, size, + inode->i_size - 1, WRITE); + } else { + err = check_lock_range(filp, inode->i_size, + size - 1, WRITE); + } + + if (err) { + ksmbd_err("failed due to lock\n"); + return -EAGAIN; + } }
err = vfs_truncate(&filp->f_path, size); @@ -1860,17 +1869,19 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
smb_break_all_levII_oplock(work, dst_fp, 1);
- for (i = 0; i < chunk_count; i++) { - src_off = le64_to_cpu(chunks[i].SourceOffset); - dst_off = le64_to_cpu(chunks[i].TargetOffset); - len = le32_to_cpu(chunks[i].Length); - - if (check_lock_range(src_fp->filp, src_off, - src_off + len - 1, READ)) - return -EAGAIN; - if (check_lock_range(dst_fp->filp, dst_off, - dst_off + len - 1, WRITE)) - return -EAGAIN; + if (!work->tcon->posix_extensions) { + for (i = 0; i < chunk_count; i++) { + src_off = le64_to_cpu(chunks[i].SourceOffset); + dst_off = le64_to_cpu(chunks[i].TargetOffset); + len = le32_to_cpu(chunks[i].Length); + + if (check_lock_range(src_fp->filp, src_off, + src_off + len - 1, READ)) + return -EAGAIN; + if (check_lock_range(dst_fp->filp, dst_off, + dst_off + len - 1, WRITE)) + return -EAGAIN; + } }
src_file_size = i_size_read(file_inode(src_fp->filp));