fuse/passthrough: API V2 with __u32 open argument

The initial FUSE passthrough interface has the issue of introducing an
ioctl which receives as a parameter a data structure containing a
pointer. What happens is that, depending on the architecture, the size
of this struct might change, and especially for 32-bit userspace running
on 64-bit kernel, the size mismatch results into different a single
ioctl the behavior of which depends on the data that is passed (e.g.,
with an enum). This is just a poor ioctl design as mentioned by Arnd
Bergmann [1].

Introduce the new FUSE_PASSTHROUGH_OPEN ioctl which only gets the fd of
the lower file system, which is a fixed-size __u32, dropping the
confusing fuse_passthrough_out data structure.

[1] https://lore.kernel.org/lkml/CAK8P3a2K2FzPvqBYL9W=Yut58SFXyetXwU4Fz50G5O3TsS0pPQ@mail.gmail.com/

Bug: 175195837
Signed-off-by: Alessio Balsini <balsini@google.com>
Change-Id: I486d71cbe20f3c0c87544fa75da4e2704fe57c7c
[cyberknight777: backport to 4.14]
Signed-off-by: Cyber Knight <cyberknight755@gmail.com>
Signed-off-by: Forenche <prahul2003@gmail.com>
Signed-off-by: Richard Raya <rdxzv.dev@gmail.com>
This commit is contained in:
Alessio Balsini 2021-05-13 11:58:16 +01:00 committed by Richard Raya
parent 176fc3b3b4
commit 9253af9544
4 changed files with 8 additions and 24 deletions

View File

@ -2288,7 +2288,6 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
int res; int res;
int oldfd; int oldfd;
struct fuse_dev *fud = NULL; struct fuse_dev *fud = NULL;
struct fuse_passthrough_out pto;
if (_IOC_TYPE(cmd) != FUSE_DEV_IOC_MAGIC) if (_IOC_TYPE(cmd) != FUSE_DEV_IOC_MAGIC)
return -EINVAL; return -EINVAL;
@ -2321,13 +2320,11 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
break; break;
case _IOC_NR(FUSE_DEV_IOC_PASSTHROUGH_OPEN): case _IOC_NR(FUSE_DEV_IOC_PASSTHROUGH_OPEN):
res = -EFAULT; res = -EFAULT;
if (!copy_from_user(&pto, if (!get_user(oldfd, (__u32 __user *)arg)) {
(struct fuse_passthrough_out __user *)arg,
sizeof(pto))) {
res = -EINVAL; res = -EINVAL;
fud = fuse_get_dev(file); fud = fuse_get_dev(file);
if (fud) if (fud)
res = fuse_passthrough_open(fud, &pto); res = fuse_passthrough_open(fud, oldfd);
} }
break; break;
default: default:

View File

@ -1035,8 +1035,7 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type);
int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type); int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type);
/* passthrough.c */ /* passthrough.c */
int fuse_passthrough_open(struct fuse_dev *fud, int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd);
struct fuse_passthrough_out *pto);
int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff, int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
struct fuse_open_out *openarg); struct fuse_open_out *openarg);
void fuse_passthrough_release(struct fuse_passthrough *passthrough); void fuse_passthrough_release(struct fuse_passthrough *passthrough);

View File

@ -192,8 +192,7 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
return ret; return ret;
} }
int fuse_passthrough_open(struct fuse_dev *fud, int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd)
struct fuse_passthrough_out *pto)
{ {
int res; int res;
struct file *passthrough_filp; struct file *passthrough_filp;
@ -205,11 +204,7 @@ int fuse_passthrough_open(struct fuse_dev *fud,
if (!fc->passthrough) if (!fc->passthrough)
return -EPERM; return -EPERM;
/* This field is reserved for future implementation */ passthrough_filp = fget(lower_fd);
if (pto->len != 0)
return -EINVAL;
passthrough_filp = fget(pto->fd);
if (!passthrough_filp) { if (!passthrough_filp) {
pr_err("FUSE: invalid file descriptor for passthrough.\n"); pr_err("FUSE: invalid file descriptor for passthrough.\n");
return -EBADF; return -EBADF;

View File

@ -708,14 +708,6 @@ struct fuse_in_header {
uint32_t padding; uint32_t padding;
}; };
/* fuse_passthrough_out for passthrough V1 */
struct fuse_passthrough_out {
uint32_t fd;
/* For future implementation */
uint32_t len;
void *vec;
};
struct fuse_out_header { struct fuse_out_header {
uint32_t len; uint32_t len;
int32_t error; int32_t error;
@ -793,8 +785,9 @@ struct fuse_notify_retrieve_in {
/* Device ioctls: */ /* Device ioctls: */
#define FUSE_DEV_IOC_MAGIC 229 #define FUSE_DEV_IOC_MAGIC 229
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) #define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
/* 127 is reserved for the V1 interface implementation in Android */ /* 127 is reserved for the V1 interface implementation in Android (deprecated) */
#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 127, struct fuse_passthrough_out) /* 126 is reserved for the V2 interface implementation in Android */
#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 126, __u32)
struct fuse_lseek_in { struct fuse_lseek_in {
uint64_t fh; uint64_t fh;