From: "Darrick J. Wong" <djwong@kernel.org>
To: bernd@bsbernd.com
Cc: fuse-devel@lists.linux.dev, neal@gompa.dev
Subject: Re: [PATCH v2 02/14] mount_service: warn about paths not named on the command line
Date: Mon, 28 Sep 2026 19:10:27 -0700 [thread overview]
Message-ID: <20260929021027.GB6253@frogsfrogsfrogs> (raw)
In-Reply-To: <20260928-mount-service-bound-open-v2-2-0f9f501d05ce@bsbernd.com>
On Mon, Sep 28, 2026 at 01:02:04PM +0200, Bernd Schubert via B4 Relay wrote:
> From: Bernd Schubert <bernd@bsbernd.com>
>
> In a service mount, the fuse server runs as a systemd service in a
> sandbox that has no access to the user's files. The user runs mount,
> which starts fuservicemount3, a setuid-root helper. The fuse server
> sends requests to the helper over a socket. With an OPEN request, the
> server asks the helper to open its backing file, for example the disk
> image named on the mount command line. The helper opens the file with
> the user's credentials and passes the file descriptor to the server.
> fusermount3 opens nothing for the fuse server except /dev/fuse; the
> server runs as the user and opens its own files.
>
> The helper opens any path the server sends. An attacker who controlled
> the server could use this to read every file the user can read, for
> example ~/.ssh/id_ed25519, and the sandbox does not prevent it. The
> helper now prints a warning if the user did not name the path when
> mounting: as a whole argument, as the value of a name=value option, or
> glued to a short option as in "-J/dev/sdb1". The helper splits the
> options with fuse_opt_parse(), as the fuse server does, so both see the
> same option values. The helper still opens the path, because a server
> can take a path in a form that none of these checks recognizes.
>
> Enforced permissions follow up in the next commit.
>
> Assisted-by: LLM
> Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
I wonder if there are any fuse servers out there that take parameters
like:
-o bdevs=/dev/sda:/dev/sdb,otheroption=whatever
but ... let's let them come out of the woodwork?
I think this is a good addition :)
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> ---
> util/mount_service.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 66 insertions(+), 7 deletions(-)
>
> diff --git a/util/mount_service.c b/util/mount_service.c
> index 7549e0b5024f..446f37f61916 100644
> --- a/util/mount_service.c
> +++ b/util/mount_service.c
> @@ -770,9 +770,55 @@ static bool arg_in_cmdline(int argc, const char * const argv[],
> return false;
> }
>
> +struct option_value_match {
> + const char *path;
> + bool found;
> +};
> +
> +/* fuse_opt_parse() callback: set match->found if the path is this option's value */
> +static int match_option_value(void *data, const char *arg, int key,
> + struct fuse_args *outargs)
> +{
> + struct option_value_match *match = data;
> + const char *value = strchr(arg, '=');
> +
> + (void) outargs;
> +
> + if (key != FUSE_OPT_KEY_OPT)
> + return 0;
> +
> + if (value && !strcmp(value + 1, match->path))
> + match->found = true;
> +
> + /* Short option with its value glued on, as in "-J/dev/sdb1" */
> + if (arg[0] == '-' && arg[1] && arg[1] != '-' &&
> + !strcmp(arg + 2, match->path))
> + match->found = true;
> +
> + return 0;
> +}
> +
> +/* @return true for the path in "-o name=path", "--name=path" or "-Xpath" */
> +static bool option_value_in_cmdline(int argc, const char * const argv[],
> + const char *path)
> +{
> + struct option_value_match match = {
> + .path = path,
> + };
> + struct fuse_args args = FUSE_ARGS_INIT(argc, (char **)argv);
> + int ret;
> +
> + /* Parse like the fuse server does, so both see the same values */
> + ret = fuse_opt_parse(&args, &match, NULL, match_option_value);
> + fuse_opt_free_args(&args);
> +
> + return !ret && match.found;
> +}
> +
> static int mount_service_open_path(const struct mount_service *mo,
> mode_t expected_fmt,
> - struct fuse_service_packet *p, size_t psz)
> + struct fuse_service_packet *p, size_t psz,
> + int argc, const char * const argv[])
> {
> const struct fuse_service_open_command *oc =
> container_of(p, struct fuse_service_open_command, p);
> @@ -800,6 +846,15 @@ static int mount_service_open_path(const struct mount_service *mo,
> return mount_service_send_file_error(mo, EINVAL, oc->path);
> }
>
> + /*
> + * The file is opened outside the service sandbox, so report a path
> + * the user did not name.
> + */
> + if (!arg_in_cmdline(argc, argv, oc->path) &&
> + !option_value_in_cmdline(argc, argv, oc->path))
> + fprintf(stderr, "%s: %s: warning: file not in command line arguments\n",
> + mo->msgtag, oc->path);
> +
> open_flags = ntohl(oc->open_flags) | O_CLOEXEC;
> drop_privs();
> fd = open(oc->path, open_flags, ntohl(oc->create_mode));
> @@ -834,16 +889,18 @@ static int mount_service_open_path(const struct mount_service *mo,
>
> static int mount_service_handle_open_cmd(const struct mount_service *mo,
> struct fuse_service_packet *p,
> - size_t psz)
> + size_t psz, int argc,
> + const char * const argv[])
> {
> - return mount_service_open_path(mo, 0, p, psz);
> + return mount_service_open_path(mo, 0, p, psz, argc, argv);
> }
>
> static int mount_service_handle_open_bdev_cmd(const struct mount_service *mo,
> struct fuse_service_packet *p,
> - size_t psz)
> + size_t psz, int argc,
> + const char * const argv[])
> {
> - return mount_service_open_path(mo, S_IFBLK, p, psz);
> + return mount_service_open_path(mo, S_IFBLK, p, psz, argc, argv);
> }
>
> #ifdef HAVE_NEW_MOUNT_API
> @@ -1838,10 +1895,12 @@ int mount_service_main(int argc, char *argv[])
>
> switch (ntohl(p->magic)) {
> case FUSE_SERVICE_OPEN_CMD:
> - ret = mount_service_handle_open_cmd(&mo, p, sz);
> + ret = mount_service_handle_open_cmd(&mo, p, sz,
> + argc, (const char * const *)argv);
> break;
> case FUSE_SERVICE_OPEN_BDEV_CMD:
> - ret = mount_service_handle_open_bdev_cmd(&mo, p, sz);
> + ret = mount_service_handle_open_bdev_cmd(&mo, p, sz,
> + argc, (const char * const *)argv);
> break;
> case FUSE_SERVICE_FSOPEN_CMD:
> ret = mount_service_handle_fsopen_cmd(&mo, p, sz);
>
> --
> 2.53.0
>
>
>
next prev parent reply other threads:[~2026-09-29 2:10 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 11:02 [PATCH v2 00/14] libfuse: Add mount service safety checks and tests Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 01/14] mount_service: move the command line check into arg_in_cmdline() Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 02/14] mount_service: warn about paths not named on the command line Bernd Schubert via B4 Relay
2026-09-29 2:10 ` Darrick J. Wong [this message]
2026-09-30 11:06 ` Bernd Schubert
2026-09-28 11:02 ` [PATCH v2 03/14] mount_service: refuse paths the user did not name Bernd Schubert via B4 Relay
2026-09-29 2:26 ` Darrick J. Wong
2026-09-30 11:46 ` Bernd Schubert
2026-09-28 11:02 ` [PATCH v2 04/14] mount_service: use openat to OPEN paths Bernd Schubert via B4 Relay
2026-09-29 2:27 ` Darrick J. Wong
2026-09-28 11:02 ` [PATCH v2 05/14] util: give fuservicemount3 an absolute build-tree runpath Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 06/14] mount.fuse: free the options on the service mount return path Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 07/14] example/single_file: take no sector size from a regular backing file Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 08/14] test: check which files fuservicemount3 opens for the server Bernd Schubert via B4 Relay
2026-09-29 3:52 ` Darrick J. Wong
2026-09-28 11:02 ` [PATCH v2 09/14] test: check what fuservicemount3 refuses Bernd Schubert via B4 Relay
2026-09-29 3:55 ` Darrick J. Wong
2026-09-28 11:02 ` [PATCH v2 10/14] test: mount the service examples through fuservicemount3 Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 11/14] test: run mkfs.ext4 through the service examples Bernd Schubert via B4 Relay
2026-09-28 11:02 ` [PATCH v2 12/14] fuse_service: bound argc and arg len read from the args memfd Bernd Schubert via B4 Relay
2026-09-29 2:33 ` Darrick J. Wong
2026-09-28 11:02 ` [PATCH v2 13/14] build: move the default service socket directory to /run/fuse Bernd Schubert via B4 Relay
2026-09-29 2:34 ` Darrick J. Wong
2026-09-28 11:02 ` [PATCH v2 14/14] Improve documentation for fuse service mount Bernd Schubert via B4 Relay
2026-09-29 2:43 ` Darrick J. Wong
2026-09-30 13:09 ` Bernd Schubert
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=20260929021027.GB6253@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=bernd@bsbernd.com \
--cc=fuse-devel@lists.linux.dev \
--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