From 5e424f85962b0353631642f4da402f2003c218ba Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Thu, 13 May 2021 11:58:16 +0100 Subject: [PATCH] ANDROID: 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 --- 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 94da3cfca7f8..7ab6bc3ce498 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2249,7 +2249,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; @@ -2282,13 +2281,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 f664d50a2a5a..86b7dadcc5e7 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1249,8 +1249,7 @@ bool fuse_dax_check_alignment(struct fuse_conn *fc, unsigned int map_alignment); void fuse_dax_cancel_work(struct fuse_conn *fc); /* 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 1df94c1d8a00..52068065fddc 100644 --- a/fs/fuse/passthrough.c +++ b/fs/fuse/passthrough.c @@ -179,8 +179,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; @@ -192,11 +191,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 c9f98e225db6..bf3c62dd7112 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -810,14 +810,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; @@ -895,8 +887,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;