From: "Darrick J. Wong" <djwong@kernel.org>
To: Bernd Schubert <bschubert@ddn.com>
Cc: "linux-fsdevel@vger.kernel.org" <linux-fsdevel@vger.kernel.org>,
"bernd@bsbernd.com" <bernd@bsbernd.com>,
"miklos@szeredi.hu" <miklos@szeredi.hu>,
"neal@gompa.dev" <neal@gompa.dev>,
"joannelkoong@gmail.com" <joannelkoong@gmail.com>
Subject: Re: [PATCH 02/17] mount_service: add systemd/inetd socket service mounting helper
Date: Mon, 30 Mar 2026 14:37:21 -0700 [thread overview]
Message-ID: <20260330213721.GG6202@frogsfrogsfrogs> (raw)
In-Reply-To: <508e2a84-fe5e-4254-b4ce-ff6b400f5dc3@ddn.com>
On Mon, Mar 30, 2026 at 08:44:21PM +0000, Bernd Schubert wrote:
> On 3/27/26 02:25, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Create a mount helper program that can start a fuse server that runs as
> > a socket-based systemd service, and a new libfuse module to wrap all the
> > details of communicating between the mount helper and the containerized
> > fuse server.
> >
> > This enables untrusted ext4 mounts via systemd service containers, which
> > avoids the problem of malicious filesystems compromising the integrity
> > of the running kernel through memory corruption.
> >
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > ---
> > include/fuse_service.h | 215 +++++
> > include/fuse_service_priv.h | 127 +++
> > lib/mount_common_i.h | 3
> > util/mount_service.h | 32 +
> > .github/workflows/abicheck.yml | 2
> > .github/workflows/abicheck_prev_release.yml | 2
> > .github/workflows/pr-ci.yml | 2
> > doc/fuservicemount3.8 | 24 +
> > doc/meson.build | 3
> > include/meson.build | 4
> > lib/fuse_service.c | 989 +++++++++++++++++++++++++
> > lib/fuse_service_stub.c | 96 ++
> > lib/fuse_versionscript | 16
> > lib/helper.c | 53 +
> > lib/meson.build | 16
> > lib/mount.c | 12
> > meson.build | 29 +
> > meson_options.txt | 6
> > util/fuservicemount.c | 18
> > util/meson.build | 9
> > util/mount_service.c | 1088 +++++++++++++++++++++++++++
> > 21 files changed, 2741 insertions(+), 5 deletions(-)
> > create mode 100644 include/fuse_service.h
> > create mode 100644 include/fuse_service_priv.h
> > create mode 100644 util/mount_service.h
> > create mode 100644 doc/fuservicemount3.8
> > create mode 100644 lib/fuse_service.c
> > create mode 100644 lib/fuse_service_stub.c
> > create mode 100644 util/fuservicemount.c
> > create mode 100644 util/mount_service.c
> >
> >
> > diff --git a/include/fuse_service.h b/include/fuse_service.h
> > new file mode 100644
> > index 00000000000000..f0a4e63b2f11a7
> > --- /dev/null
> > +++ b/include/fuse_service.h
> > @@ -0,0 +1,215 @@
> > +/*
> > + * FUSE: Filesystem in Userspace
> > + * Copyright (C) 2025-2026 Oracle.
> > + * Author: Darrick J. Wong <djwong@kernel.org>
> > + *
> > + * This program can be distributed under the terms of the GNU LGPLv2.
> > + * See the file LGPL2.txt.
> > + */
> > +#ifndef FUSE_SERVICE_H_
> > +#define FUSE_SERVICE_H_
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +#if FUSE_MAKE_VERSION(3, 19) <= FUSE_USE_VERSION
> > +
> > +struct fuse_service;
> > +
> > +/**
> > + * Accept a socket created by mount.service for information exchange.
> > + *
> > + * @param sfp pointer to pointer to a service context. The pointer will always
> > + * be initialized by this function; use fuse_service_accepted to
> > + * find out if the fuse server is actually running as a service.
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_accept(struct fuse_service **sfp);
> > +
> > +/**
> > + * Has the fuse server accepted a service context?
> > + *
> > + * @param sf service context
> > + * @return true if it has, false if not
> > + */
> > +static inline bool fuse_service_accepted(struct fuse_service *sf)
> > +{
> > + return sf != NULL;
> > +}
> > +
> > +/**
> > + * Will the mount service helper accept the allow_other option?
> > + *
> > + * @param sf service context
> > + * @return true if it has, false if not
> > + */
> > +bool fuse_service_can_allow_other(struct fuse_service *sf);
> > +
> > +/**
> > + * Release all resources associated with the service context.
> > + *
> > + * @param sfp service context
> > + */
> > +void fuse_service_release(struct fuse_service *sf);
> > +
> > +/**
> > + * Destroy a service context and release all resources
> > + *
> > + * @param sfp pointer to pointer to a service context
> > + */
> > +void fuse_service_destroy(struct fuse_service **sfp);
> > +
> > +/**
> > + * Append the command line arguments from the mount service helper to an
> > + * existing fuse_args structure. The fuse_args should have been initialized
> > + * with the argc and argv passed to main().
> > + *
> > + * @param sfp service context
> > + * @param args arguments to modify (input+output)
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_append_args(struct fuse_service *sf, struct fuse_args *args);
> > +
> > +/**
> > + * Generate the effective fuse server command line from the args structure.
> > + * The args structure should be the outcome from fuse_service_append_args.
> > + * The resulting string is suitable for setproctitle and must be freed by the
> > + * callre.
> > + *
> > + * @param argc argument count passed to main()
> > + * @param argv argument vector passed to main()
> > + * @param args fuse args structure
> > + * @return effective command line string, or NULL
> > + */
> > +char *fuse_service_cmdline(int argc, char *argv[], struct fuse_args *args);
> > +
> > +struct fuse_cmdline_opts;
> > +
> > +/**
> > + * Utility function to parse common options for simple file systems
> > + * using the low-level API. A help text that describes the available
> > + * options can be printed with `fuse_cmdline_help`. A single
> > + * non-option argument is treated as the mountpoint. Multiple
> > + * non-option arguments will result in an error.
> > + *
> > + * If neither -o subtype= or -o fsname= options are given, a new
> > + * subtype option will be added and set to the basename of the program
> > + * (the fsname will remain unset, and then defaults to "fuse").
> > + *
> > + * Known options will be removed from *args*, unknown options will
> > + * remain. The mountpoint will not be checked here; that is the job of
> > + * mount.service.
> > + *
> > + * @param args argument vector (input+output)
> > + * @param opts output argument for parsed options
> > + * @return 0 on success, -1 on failure
> > + */
> > +int fuse_service_parse_cmdline_opts(struct fuse_args *args,
> > + struct fuse_cmdline_opts *opts);
> > +
> > +/**
> > + * Ask the mount.service helper to open a file on behalf of the fuse server.
> > + *
> > + * @param sf service context
> > + * @param path the path to file
> > + * @param open_flags O_ flags
> > + * @param create_mode mode with which to create the file
> > + * @param request_flags set of FUSE_SERVICE_REQUEST_* flags
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_request_file(struct fuse_service *sf, const char *path,
> > + int open_flags, mode_t create_mode,
> > + unsigned int request_flags);
> > +
> > +/**
> > + * Ask the mount.service helper to open a block device on behalf of the fuse
> > + * server.
> > + *
> > + * @param sf service context
> > + * @param path the path to file
> > + * @param open_flags O_ flags
> > + * @param create_mode mode with which to create the file
> > + * @param request_flags set of FUSE_SERVICE_REQUEST_* flags
> > + * @param block_size set the block device block size to this value
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_request_blockdev(struct fuse_service *sf, const char *path,
> > + int open_flags, mode_t create_mode,
> > + unsigned int request_flags,
> > + unsigned int block_size);
> > +
> > +/**
> > + * Receive a file previously requested.
> > + *
> > + * @param sf service context
> > + * @param path to file
> > + * @fdp pointer to file descriptor, which will be set a non-negative file
> > + * descriptor value on success, or negative errno on failure
> > + * @return 0 on success, or negative errno on socket communication failure
> > + */
> > +int fuse_service_receive_file(struct fuse_service *sf,
> > + const char *path, int *fdp);
> > +
> > +/**
> > + * Prevent the mount.service server from sending us any more open files.
> > + *
> > + * @param sf service context
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_finish_file_requests(struct fuse_service *sf);
> > +
> > +/**
> > + * Require that the filesystem mount point have the expected file format
> > + * (S_IFDIR/S_IFREG). Can be overridden when calling
> > + * fuse_service_session_mount.
> > + *
> > + * @param sf service context
> > + * @param expected_fmt expected mode (S_IFDIR/S_IFREG) for mount point, or 0
> > + * to skip checks
> > + */
> > +void fuse_service_expect_mount_mode(struct fuse_service *sf,
> > + mode_t expected_fmt);
> > +
> > +/**
> > + * Bind a FUSE file system to the fuse session inside a fuse service process,
> > + * then ask the mount.service helper to mount the filesystem for us. The fuse
> > + * client will begin sending requests to the fuse server immediately after
> > + * this.
> > + *
> > + * @param sf service context
> > + * @param se fuse session
> > + * @param expected_fmt expected mode (S_IFDIR/S_IFREG) for mount point, or 0
> > + * to skip checks
> > + * @param opts command line options
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_session_mount(struct fuse_service *sf, struct fuse_session *se,
> > + mode_t expected_fmt,
> > + struct fuse_cmdline_opts *opts);
> > +
> > +/**
> > + * Bid farewell to the mount.service helper. It is still necessary to call
> > + * fuse_service_destroy after this.
> > + *
> > + * @param sf service context
> > + * @param exitcode fuse server process exit status
> > + * @return 0 on success, or negative errno on failure
> > + */
> > +int fuse_service_send_goodbye(struct fuse_service *sf, int exitcode);
> > +
> > +/**
> > + * Exit routine for a fuse server running as a systemd service.
> > + *
> > + * @param ret 0 for success, nonzero for service failure.
> > + * @return a value to be passed to exit() or returned from main
> > + */
> > +int fuse_service_exit(int ret);
> > +
> > +#endif /* FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 19) */
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* FUSE_SERVICE_H_ */
> > diff --git a/include/fuse_service_priv.h b/include/fuse_service_priv.h
> > new file mode 100644
> > index 00000000000000..d1fdd6221b5268
> > --- /dev/null
> > +++ b/include/fuse_service_priv.h
> > @@ -0,0 +1,127 @@
> > +/*
> > + * FUSE: Filesystem in Userspace
> > + * Copyright (C) 2025-2026 Oracle.
> > + * Author: Darrick J. Wong <djwong@kernel.org>
> > + *
> > + * This program can be distributed under the terms of the GNU LGPLv2.
> > + * See the file LGPL2.txt.
> > + */
> > +#ifndef FUSE_SERVICE_PRIV_H_
> > +#define FUSE_SERVICE_PRIV_H_
> > +
> > +/* All numeric fields are network order (big-endian) when going across the socket */
> > +
> > +struct fuse_service_memfd_arg {
> > + uint32_t pos;
> > + uint32_t len;
> > +};
> > +
> > +struct fuse_service_memfd_argv {
> > + uint32_t magic;
> > + uint32_t argc;
> > +};
> > +
> > +#define FUSE_SERVICE_ARGS_MAGIC 0x41524753 /* ARGS */
> > +
> > +/* mount.service sends a hello to the server and it replies */
> > +#define FUSE_SERVICE_HELLO_CMD 0x53414654 /* SAFT */
>
> What "SAFT" stand for? (The German meaning of the word is "juice" ;) ).
"SAFeTy", compressed.
--D
>
> Thanks,
> Bernd
next prev parent reply other threads:[~2026-03-30 21:37 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-27 1:24 [PATCHSET v3] libfuse: run fuse servers as a contained service Darrick J. Wong
2026-03-27 1:25 ` [PATCH 01/17] Refactor mount code / move common functions to mount_util.c Darrick J. Wong
2026-03-27 1:25 ` [PATCH 02/17] mount_service: add systemd/inetd socket service mounting helper Darrick J. Wong
2026-03-30 20:44 ` Bernd Schubert
2026-03-30 21:37 ` Darrick J. Wong [this message]
2026-03-27 1:25 ` [PATCH 03/17] mount_service: create high level fuse helpers Darrick J. Wong
2026-03-30 19:37 ` Bernd Schubert
2026-03-30 20:30 ` Darrick J. Wong
2026-03-30 20:51 ` Bernd Schubert
2026-03-30 21:09 ` Darrick J. Wong
2026-03-27 1:25 ` [PATCH 04/17] mount_service: use the new mount api for the mount service Darrick J. Wong
2026-03-30 21:06 ` Bernd Schubert
2026-03-30 21:18 ` Darrick J. Wong
2026-03-30 21:40 ` Bernd Schubert
2026-03-30 21:47 ` Darrick J. Wong
2026-03-27 1:26 ` [PATCH 05/17] mount_service: update mtab after a successful mount Darrick J. Wong
2026-03-27 1:26 ` [PATCH 06/17] util: hoist the fuse.conf parsing code Darrick J. Wong
2026-03-27 1:26 ` [PATCH 07/17] util: fix checkpatch complaints in fuser_conf.[ch] Darrick J. Wong
2026-03-27 1:26 ` [PATCH 08/17] mount_service: read fuse.conf to enable allow_other for unprivileged mounts Darrick J. Wong
2026-03-27 1:27 ` [PATCH 09/17] util: hoist the other non-root user limits Darrick J. Wong
2026-03-27 1:27 ` [PATCH 10/17] util: fix more checkpatch complaints in fuser_conf.[ch] Darrick J. Wong
2026-03-27 1:27 ` [PATCH 11/17] mount_service: use over the other non-root user checks Darrick J. Wong
2026-03-27 1:27 ` [PATCH 12/17] mount.fuse3: integrate systemd service startup Darrick J. Wong
2026-03-27 1:28 ` [PATCH 13/17] mount_service: allow installation as a setuid program Darrick J. Wong
2026-03-27 1:28 ` [PATCH 14/17] example/service_ll: create a sample systemd service fuse server Darrick J. Wong
2026-03-27 1:28 ` [PATCH 15/17] example/service: create a sample systemd service for a high-level " Darrick J. Wong
2026-03-27 1:28 ` [PATCH 16/17] example/hello_ll: port to single-file common code Darrick J. Wong
2026-03-27 1:29 ` [PATCH 17/17] nullfs: support fuse systemd service mode Darrick J. Wong
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=20260330213721.GG6202@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=bernd@bsbernd.com \
--cc=bschubert@ddn.com \
--cc=joannelkoong@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=neal@gompa.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox