All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Rosenberg <drosen@google.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Amir Goldstein <amir73il@gmail.com>,
	linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-unionfs@vger.kernel.org, bpf@vger.kernel.org,
	kernel-team@android.com, Daniel Rosenberg <drosen@google.com>
Subject: [RFC PATCH v2 05/21] fuse-bpf: Add ioctl interface for /dev/fuse
Date: Mon, 21 Nov 2022 18:15:20 -0800	[thread overview]
Message-ID: <20221122021536.1629178-6-drosen@google.com> (raw)
In-Reply-To: <20221122021536.1629178-1-drosen@google.com>

This introduces an alternative method of responding to fuse requests.
Lookups supplying a backing fd or bpf will need to call through the
ioctl to ensure there can be no attempts to fool priveledged processes
into inadvertantly performing other actions.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
 fs/fuse/dev.c             | 56 ++++++++++++++++++++++++++++++++-------
 fs/fuse/fuse_i.h          |  1 +
 include/uapi/linux/fuse.h |  1 +
 3 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 79d2fb6adc83..fbc519c37e66 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1013,18 +1013,19 @@ static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size)
 
 /* Copy the fuse-bpf lookup args and verify them */
 #ifdef CONFIG_FUSE_BPF
-static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size)
+static int fuse_copy_lookup(struct fuse_copy_state *cs, unsigned via_ioctl, void *val, unsigned size)
 {
 	struct fuse_bpf_entry_out *fbeo = (struct fuse_bpf_entry_out *)val;
 	struct fuse_bpf_entry *feb = container_of(fbeo, struct fuse_bpf_entry, out[0]);
 	int num_entries = size / sizeof(*fbeo);
 	int err;
 
-	if (size && size % sizeof(*fbeo) != 0)
+	if (size && (size % sizeof(*fbeo) != 0 || !via_ioctl))
 		return -EINVAL;
 
 	if (num_entries > FUSE_BPF_MAX_ENTRIES)
 		return -EINVAL;
+
 	err = fuse_copy_one(cs, val, size);
 	if (err)
 		return err;
@@ -1033,7 +1034,7 @@ static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size
 	return err;
 }
 #else
-static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size)
+static int fuse_copy_lookup(struct fuse_copy_state *cs, unsigned via_ioctl, void *val, unsigned size)
 {
 	return fuse_copy_one(cs, val, size);
 }
@@ -1042,7 +1043,7 @@ static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size
 /* Copy request arguments to/from userspace buffer */
 static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
 			  unsigned argpages, struct fuse_arg *args,
-			  int zeroing, unsigned is_lookup)
+			  int zeroing, unsigned is_lookup, unsigned via_ioct)
 {
 	int err = 0;
 	unsigned i;
@@ -1052,7 +1053,7 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
 		if (i == numargs - 1 && argpages)
 			err = fuse_copy_pages(cs, arg->size, zeroing);
 		else if (i == numargs - 1 && is_lookup)
-			err = fuse_copy_lookup(cs, arg->value, arg->size);
+			err = fuse_copy_lookup(cs, via_ioct, arg->value, arg->size);
 		else
 			err = fuse_copy_one(cs, arg->value, arg->size);
 	}
@@ -1330,7 +1331,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	err = fuse_copy_one(cs, &req->in.h, sizeof(req->in.h));
 	if (!err)
 		err = fuse_copy_args(cs, args->in_numargs, args->in_pages,
-				     (struct fuse_arg *) args->in_args, 0, 0);
+				     (struct fuse_arg *) args->in_args, 0, 0, 0);
 	fuse_copy_finish(cs);
 	spin_lock(&fpq->lock);
 	clear_bit(FR_LOCKED, &req->flags);
@@ -1869,7 +1870,8 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,
 		lastarg->size -= diffsize;
 	}
 	return fuse_copy_args(cs, args->out_numargs, args->out_pages,
-			      args->out_args, args->page_zeroing, args->is_lookup);
+			      args->out_args, args->page_zeroing, args->is_lookup,
+			      args->via_ioctl);
 }
 
 /*
@@ -1879,7 +1881,7 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,
  * it from the list and copy the rest of the buffer to the request.
  * The request is finished by calling fuse_request_end().
  */
-static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
+static ssize_t fuse_dev_do_write(struct fuse_dev *fud, bool from_ioctl,
 				 struct fuse_copy_state *cs, size_t nbytes)
 {
 	int err;
@@ -1951,6 +1953,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
 	if (!req->args->page_replace)
 		cs->move_pages = 0;
 
+	req->args->via_ioctl = from_ioctl;
 	if (oh.error)
 		err = nbytes != sizeof(oh) ? -EINVAL : 0;
 	else
@@ -1989,7 +1992,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
 
 	fuse_copy_init(&cs, 0, from);
 
-	return fuse_dev_do_write(fud, &cs, iov_iter_count(from));
+	return fuse_dev_do_write(fud, false, &cs, iov_iter_count(from));
 }
 
 static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
@@ -2070,7 +2073,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
 	if (flags & SPLICE_F_MOVE)
 		cs.move_pages = 1;
 
-	ret = fuse_dev_do_write(fud, &cs, len);
+	ret = fuse_dev_do_write(fud, false, &cs, len);
 
 	pipe_lock(pipe);
 out_free:
@@ -2283,6 +2286,33 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
 	return 0;
 }
 
+// Provides an alternate means to respond to a fuse request
+static int fuse_handle_ioc_response(struct fuse_dev *dev, void *buff, uint32_t size)
+{
+	struct fuse_copy_state cs;
+	struct iovec *iov = NULL;
+	struct iov_iter iter;
+	int res;
+
+	if (size > PAGE_SIZE)
+		return -EINVAL;
+	iov = (struct iovec *) __get_free_page(GFP_KERNEL);
+	if (!iov)
+		return -ENOMEM;
+
+	iov->iov_base = buff;
+	iov->iov_len = size;
+
+	iov_iter_init(&iter, READ, iov, 1, size);
+	fuse_copy_init(&cs, 0, &iter);
+
+
+	res = fuse_dev_do_write(dev, true, &cs, size);
+	free_page((unsigned long) iov);
+
+	return res;
+}
+
 static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 			   unsigned long arg)
 {
@@ -2316,6 +2346,12 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 		}
 		break;
 	default:
+		if (_IOC_TYPE(cmd) == FUSE_DEV_IOC_MAGIC
+				&& _IOC_NR(cmd) == _IOC_NR(FUSE_DEV_IOC_BPF_RESPONSE(0))
+				&& _IOC_DIR(cmd) == _IOC_WRITE) {
+			res = fuse_handle_ioc_response(fuse_get_dev(file), (void *) arg, _IOC_SIZE(cmd));
+			break;
+		}
 		res = -ENOTTY;
 		break;
 	}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d67325af5e72..3452530aba94 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -314,6 +314,7 @@ struct fuse_args {
 	bool page_replace:1;
 	bool may_block:1;
 	bool is_lookup:1;
+	bool via_ioctl:1;
 	struct fuse_in_arg in_args[3];
 	struct fuse_arg out_args[2];
 	void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 0e19076729d9..e49e5a8e044c 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -972,6 +972,7 @@ 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)
+#define FUSE_DEV_IOC_BPF_RESPONSE(N) _IOW(FUSE_DEV_IOC_MAGIC, 125, char[N])
 
 struct fuse_lseek_in {
 	uint64_t	fh;
-- 
2.38.1.584.g0f3c55d4c2-goog


  parent reply	other threads:[~2022-11-22  2:16 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-22  2:15 [RFC PATCH v2 00/21] FUSE BPF: A Stacked Filesystem Extension for FUSE Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 01/21] fs: Generic function to convert iocb to rw flags Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 02/21] fuse-bpf: Update fuse side uapi Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 03/21] fuse-bpf: Prepare for fuse-bpf patch Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 04/21] fuse: Add fuse-bpf, a stacked fs extension for FUSE Daniel Rosenberg
2022-11-22 10:19   ` Amir Goldstein
2022-11-22 21:23     ` Daniel Rosenberg
2022-11-23 23:31   ` kernel test robot
2022-11-22  2:15 ` Daniel Rosenberg [this message]
2022-11-22 14:20   ` [RFC PATCH v2 05/21] fuse-bpf: Add ioctl interface for /dev/fuse kernel test robot
2022-11-22  2:15 ` [RFC PATCH v2 06/21] fuse-bpf: Don't support export_operations Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 07/21] fuse-bpf: Add support for FUSE_ACCESS Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 08/21] fuse-bpf: Partially add mapping support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 09/21] fuse-bpf: Add lseek support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 10/21] fuse-bpf: Add support for fallocate Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 11/21] fuse-bpf: Support file/dir open/close Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 12/21] fuse-bpf: Support mknod/unlink/mkdir/rmdir Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 13/21] fuse-bpf: Add support for read/write iter Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 14/21] fuse-bpf: support FUSE_READDIR Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 15/21] fuse-bpf: Add support for sync operations Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 16/21] fuse-bpf: Add Rename support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 17/21] fuse-bpf: Add attr support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 18/21] fuse-bpf: Add support for FUSE_COPY_FILE_RANGE Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 19/21] fuse-bpf: Add xattr support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 20/21] fuse-bpf: Add symlink/link support Daniel Rosenberg
2022-11-22  2:15 ` [RFC PATCH v2 21/21] fuse-bpf: allow mounting with no userspace daemon Daniel Rosenberg
2022-11-22 11:13 ` [RFC PATCH v2 00/21] FUSE BPF: A Stacked Filesystem Extension for FUSE Amir Goldstein
2022-11-22 20:56   ` Daniel Rosenberg
2022-11-22 21:23     ` Bernd Schubert
2023-02-02  8:47       ` Amir Goldstein
2023-02-02 22:01         ` Bernd Schubert
2023-02-03 11:43           ` Amir Goldstein
2023-02-10  9:38             ` Miklos Szeredi
2023-02-10  9:41               ` Nikolaus Rath
2023-02-10 10:53                 ` Miklos Szeredi
2023-02-14 16:53                   ` Attending LFS (was: [RFC PATCH v2 00/21] FUSE BPF: A Stacked Filesystem Extension for FUSE) Nikolaus Rath
2023-02-14 18:04                     ` Amir Goldstein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221122021536.1629178-6-drosen@google.com \
    --to=drosen@google.com \
    --cc=amir73il@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=kernel-team@android.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.