From 9253af95446f5fd994e314174295a4562c854a81 Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Thu, 13 May 2021 11:58:16 +0100 Subject: [PATCH] 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 Change-Id: I486d71cbe20f3c0c87544fa75da4e2704fe57c7c [cyberknight777: backport to 4.14] Signed-off-by: Cyber Knight Signed-off-by: Forenche Signed-off-by: Richard Raya --- fs/fuse/dev.c | 7 ++----- fs/fuse/fuse_i.h | 3 +-- fs/fuse/passthrough.c | 9 ++------- include/uapi/linux/fuse.h | 13 +++---------- 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index c1ec029f5fe1..8cdc1f39e89a 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2288,7 +2288,6 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd, int res; int oldfd; struct fuse_dev *fud = NULL; - struct fuse_passthrough_out pto; if (_IOC_TYPE(cmd) != FUSE_DEV_IOC_MAGIC) return -EINVAL; @@ -2321,13 +2320,11 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd, break; case _IOC_NR(FUSE_DEV_IOC_PASSTHROUGH_OPEN): res = -EFAULT; - if (!copy_from_user(&pto, - (struct fuse_passthrough_out __user *)arg, - sizeof(pto))) { + if (!get_user(oldfd, (__u32 __user *)arg)) { res = -EINVAL; fud = fuse_get_dev(file); if (fud) - res = fuse_passthrough_open(fud, &pto); + res = fuse_passthrough_open(fud, oldfd); } break; default: diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3434ce621423..a486bd292687 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -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); /* passthrough.c */ -int fuse_passthrough_open(struct fuse_dev *fud, - struct fuse_passthrough_out *pto); +int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd); int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff, struct fuse_open_out *openarg); void fuse_passthrough_release(struct fuse_passthrough *passthrough); diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c index f7138d2abce1..1d1253e78484 100644 --- a/fs/fuse/passthrough.c +++ b/fs/fuse/passthrough.c @@ -192,8 +192,7 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma) return ret; } -int fuse_passthrough_open(struct fuse_dev *fud, - struct fuse_passthrough_out *pto) +int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd) { int res; struct file *passthrough_filp; @@ -205,11 +204,7 @@ int fuse_passthrough_open(struct fuse_dev *fud, if (!fc->passthrough) return -EPERM; - /* This field is reserved for future implementation */ - if (pto->len != 0) - return -EINVAL; - - passthrough_filp = fget(pto->fd); + passthrough_filp = fget(lower_fd); if (!passthrough_filp) { pr_err("FUSE: invalid file descriptor for passthrough.\n"); return -EBADF; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 6184f67ede10..7210b489c629 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -708,14 +708,6 @@ struct fuse_in_header { 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 { uint32_t len; int32_t error; @@ -793,8 +785,9 @@ struct fuse_notify_retrieve_in { /* Device ioctls: */ #define FUSE_DEV_IOC_MAGIC 229 #define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) -/* 127 is reserved for the V1 interface implementation in Android */ -#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 127, struct fuse_passthrough_out) +/* 127 is reserved for the V1 interface implementation in Android (deprecated) */ +/* 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 { uint64_t fh;