提交 ff1d5727 编写于 作者: N Namjae Jeon 提交者: Steve French

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: NHyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: NNamjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: NSteve French <stfrench@microsoft.com>
上级 d40012a8
......@@ -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 @@ int smb2_open(struct ksmbd_work *work)
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 @@ int smb2_set_info(struct ksmbd_work *work)
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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册