diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index d4610ff7a922..d201e59a7086 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -140,6 +140,8 @@ int fuse_open_backing(struct fuse_args *fa, struct fuse_mount *fm = get_fuse_mount(inode); const struct fuse_open_in *foi = fa->in_args[0].value; struct fuse_file *ff; + int retval; + int mask; struct fuse_dentry *fd = get_fuse_dentry(file->f_path.dentry); struct file *backing_file; @@ -148,9 +150,31 @@ int fuse_open_backing(struct fuse_args *fa, return -ENOMEM; file->private_data = ff; + switch (foi->flags & O_ACCMODE) { + case O_RDONLY: + mask = MAY_READ; + break; + + case O_WRONLY: + mask = MAY_WRITE; + break; + + case O_RDWR: + mask = MAY_READ | MAY_WRITE; + break; + + default: + return -EINVAL; + } + + retval = inode_permission(get_fuse_inode(inode)->backing_inode, mask); + if (retval) + return retval; + backing_file = dentry_open(&fd->backing_path, foi->flags, current_cred()); + if (IS_ERR(backing_file)) { fuse_file_free(ff); file->private_data = NULL; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b1da68b09456..b2aa101ab2ef 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1514,6 +1514,7 @@ static int fuse_permission(struct inode *inode, int mask) struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; int err = 0; + struct fuse_inode *fi = get_fuse_inode(inode); if (fuse_is_bad(inode)) return -EIO; @@ -1526,7 +1527,6 @@ static int fuse_permission(struct inode *inode, int mask) */ if (fc->default_permissions || ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { - struct fuse_inode *fi = get_fuse_inode(inode); u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID; if (perm_mask & READ_ONCE(fi->inval_mask) || @@ -1566,6 +1566,8 @@ static int fuse_permission(struct inode *inode, int mask) if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } + } else if (!(mask & MAY_NOT_BLOCK) && fi->backing_inode) { + err = fuse_access(inode, mask); } return err; }