mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
cifsd: add the check if parent is stable by unexpected rename
This patch add the check if parent is stable by unexpected rename. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
d40012a83f
commit
ff1d572725
@ -2844,12 +2844,10 @@ int smb2_open(struct ksmbd_work *work)
|
||||
* is already granted.
|
||||
*/
|
||||
if (daccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_READ_CONTROL_LE)) {
|
||||
if (ksmbd_vfs_inode_permission(path.dentry,
|
||||
open_flags & O_ACCMODE,
|
||||
may_delete)) {
|
||||
rc = -EACCES;
|
||||
rc = ksmbd_vfs_inode_permission(path.dentry,
|
||||
open_flags & O_ACCMODE, may_delete);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3260,7 +3258,7 @@ err_out1:
|
||||
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
|
||||
else if (rc == -EOPNOTSUPP)
|
||||
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
|
||||
else if (rc == -EACCES)
|
||||
else if (rc == -EACCES || rc == -ESTALE)
|
||||
rsp->hdr.Status = STATUS_ACCESS_DENIED;
|
||||
else if (rc == -ENOENT)
|
||||
rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;
|
||||
@ -5938,7 +5936,7 @@ err_out:
|
||||
rsp->hdr.Status = STATUS_DIRECTORY_NOT_EMPTY;
|
||||
else if (rc == -EAGAIN)
|
||||
rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
|
||||
else if (rc == -EBADF)
|
||||
else if (rc == -EBADF || rc == -ESTALE)
|
||||
rsp->hdr.Status = STATUS_INVALID_HANDLE;
|
||||
else if (rc == -EEXIST)
|
||||
rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION;
|
||||
|
@ -70,7 +70,7 @@ static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work,
|
||||
|
||||
int ksmbd_vfs_inode_permission(struct dentry *dentry, int acc_mode, bool delete)
|
||||
{
|
||||
int mask;
|
||||
int mask, ret = 0;
|
||||
|
||||
mask = 0;
|
||||
acc_mode &= O_ACCMODE;
|
||||
@ -86,24 +86,39 @@ int ksmbd_vfs_inode_permission(struct dentry *dentry, int acc_mode, bool delete)
|
||||
return -EACCES;
|
||||
|
||||
if (delete) {
|
||||
struct dentry *parent;
|
||||
struct dentry *child, *parent;
|
||||
|
||||
parent = dget_parent(dentry);
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
|
||||
child = lookup_one_len(dentry->d_name.name, parent,
|
||||
dentry->d_name.len);
|
||||
if (IS_ERR(child)) {
|
||||
ret = PTR_ERR(child);
|
||||
goto out_lock;
|
||||
}
|
||||
|
||||
if (child != dentry) {
|
||||
ret = -ESTALE;
|
||||
dput(child);
|
||||
goto out_lock;
|
||||
}
|
||||
dput(child);
|
||||
|
||||
if (inode_permission(&init_user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) {
|
||||
dput(parent);
|
||||
return -EACCES;
|
||||
ret = -EACCES;
|
||||
goto out_lock;
|
||||
}
|
||||
out_lock:
|
||||
inode_unlock(d_inode(parent));
|
||||
dput(parent);
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksmbd_vfs_query_maximal_access(struct dentry *dentry, __le32 *daccess)
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct dentry *parent, *child;
|
||||
int ret = 0;
|
||||
|
||||
*daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL);
|
||||
|
||||
@ -120,13 +135,28 @@ int ksmbd_vfs_query_maximal_access(struct dentry *dentry, __le32 *daccess)
|
||||
*daccess |= FILE_EXECUTE_LE;
|
||||
|
||||
parent = dget_parent(dentry);
|
||||
if (!parent)
|
||||
return 0;
|
||||
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
|
||||
child = lookup_one_len(dentry->d_name.name, parent,
|
||||
dentry->d_name.len);
|
||||
if (IS_ERR(child)) {
|
||||
ret = PTR_ERR(child);
|
||||
goto out_lock;
|
||||
}
|
||||
|
||||
if (child != dentry) {
|
||||
ret = -ESTALE;
|
||||
dput(child);
|
||||
goto out_lock;
|
||||
}
|
||||
dput(child);
|
||||
|
||||
if (!inode_permission(&init_user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE))
|
||||
*daccess |= FILE_DELETE_LE;
|
||||
|
||||
out_lock:
|
||||
inode_unlock(d_inode(parent));
|
||||
dput(parent);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -726,7 +756,7 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
{
|
||||
struct path dst_path;
|
||||
struct dentry *src_dent_parent, *dst_dent_parent;
|
||||
struct dentry *src_dent, *trap_dent;
|
||||
struct dentry *src_dent, *trap_dent, *src_child;
|
||||
char *dst_name;
|
||||
int err;
|
||||
|
||||
@ -735,11 +765,7 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
return -EINVAL;
|
||||
|
||||
src_dent_parent = dget_parent(fp->filp->f_path.dentry);
|
||||
if (!src_dent_parent)
|
||||
return -EINVAL;
|
||||
|
||||
src_dent = fp->filp->f_path.dentry;
|
||||
dget(src_dent);
|
||||
|
||||
err = kern_path(newname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &dst_path);
|
||||
if (err) {
|
||||
@ -747,20 +773,36 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
goto out;
|
||||
}
|
||||
dst_dent_parent = dst_path.dentry;
|
||||
dget(dst_dent_parent);
|
||||
|
||||
trap_dent = lock_rename(src_dent_parent, dst_dent_parent);
|
||||
dget(src_dent);
|
||||
dget(dst_dent_parent);
|
||||
src_child = lookup_one_len(src_dent->d_name.name, src_dent_parent,
|
||||
src_dent->d_name.len);
|
||||
if (IS_ERR(src_child)) {
|
||||
err = PTR_ERR(src_child);
|
||||
goto out_lock;
|
||||
}
|
||||
|
||||
if (src_child != src_dent) {
|
||||
err = -ESTALE;
|
||||
dput(src_child);
|
||||
goto out_lock;
|
||||
}
|
||||
dput(src_child);
|
||||
|
||||
err = __ksmbd_vfs_rename(work,
|
||||
src_dent_parent,
|
||||
src_dent,
|
||||
dst_dent_parent,
|
||||
trap_dent,
|
||||
dst_name);
|
||||
unlock_rename(src_dent_parent, dst_dent_parent);
|
||||
out_lock:
|
||||
dput(src_dent);
|
||||
dput(dst_dent_parent);
|
||||
unlock_rename(src_dent_parent, dst_dent_parent);
|
||||
path_put(&dst_path);
|
||||
out:
|
||||
dput(src_dent);
|
||||
dput(src_dent_parent);
|
||||
return err;
|
||||
}
|
||||
@ -1050,23 +1092,33 @@ int ksmbd_vfs_remove_xattr(struct dentry *dentry, char *attr_name)
|
||||
|
||||
int ksmbd_vfs_unlink(struct dentry *dir, struct dentry *dentry)
|
||||
{
|
||||
struct dentry *child;
|
||||
int err = 0;
|
||||
|
||||
dget(dentry);
|
||||
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
|
||||
if (!d_inode(dentry) || !d_inode(dentry)->i_nlink) {
|
||||
err = -ENOENT;
|
||||
dget(dentry);
|
||||
child = lookup_one_len(dentry->d_name.name, dir,
|
||||
dentry->d_name.len);
|
||||
if (IS_ERR(child)) {
|
||||
err = PTR_ERR(child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (child != dentry) {
|
||||
err = -ESTALE;
|
||||
dput(child);
|
||||
goto out;
|
||||
}
|
||||
dput(child);
|
||||
|
||||
if (S_ISDIR(d_inode(dentry)->i_mode))
|
||||
err = vfs_rmdir(&init_user_ns, d_inode(dir), dentry);
|
||||
else
|
||||
err = vfs_unlink(&init_user_ns, d_inode(dir), dentry, NULL);
|
||||
|
||||
out:
|
||||
inode_unlock(d_inode(dir));
|
||||
dput(dentry);
|
||||
inode_unlock(d_inode(dir));
|
||||
if (err)
|
||||
ksmbd_debug(VFS, "failed to delete, err %d\n", err);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user