310 Commits

Author SHA1 Message Date
Darrick J. Wong dc6ce72129 libfuse: remove unmount command from the service api
Bernd received a complaint via github that the "unmount" command in the
new fuse service API is prone to malicious symlink creation races
because the umount2 call doesn't use UMOUNT_NOFOLLOW.  Therefore, if you
can trick a fuse service into asking the mount service helper to undo
the mount just after you've replaced the mount with a symlink to a
sensitive mount (e.g. /sys) then you whack a system hard.

I don't know why this unmounting functionality exists in libfuse, and
apparently Bernd doesn't like it.  Since the fuse service API has not
yet been released, let's just rip out the command and pretend it never
existed.

Fixes: 5d8b9a39a1 ("mount_service: add systemd socket service mounting helper")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-06-12 12:57:19 +02:00
Darrick J. Wong d4e199cb63 mountservice: advertise fuseblk support
Amazingly, permission for the use of the "blkdev" mount option (aka
mounting with fuseblk.SUBTYPE instead of fuse.SUBTYPE) rests solely on a
getuid()==0 check in userspace.  That /might/ be an indication that the
kernel also won't allow this, but as that's the criteria, let's
advertise fuseblk explicitly so that a fuse server can discover the
capability before calling fuse_service_session_mount().

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-06-12 12:57:19 +02:00
Darrick J. Wong 413437630c mountservice: don't print bdev preparation error when quiet mode is enabled
If the fuse server tries to open a file with
FUSE_SERVICE_REQUEST_FILE_QUIET, that means they don't want the mount
helper to emit any error messages about the file open() failing.  We did
this for the main open() call, but not for any of the code in prep_bdev.
Oops.

Fixes: 5d8b9a39a1 ("mount_service: add systemd socket service mounting helper")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-06-12 12:57:19 +02:00
Darrick J. Wong 50f6c907b2 mount_service: call the new fsmount ms_flags helpers in the right order
Codex noticed a discrepancy between the new fsmount code that Bernd
wrote and my port of the even newer mount service code to use the
helpers that Bernd wrote.  Specifically, set_fsconfig_ms_flags only
clears bits from MS_FLAGS if there's no corresponding MOUNT_ATTR_ flag,
whereas ms_flags_to_mount_attrs always clears them.

In other words, set_fsconfig_ms_flags MUST be called before
ms_flags_to_mount_attrs or we can lose the 'ro' option.  Fix this.

Fixes: 7211953256 ("mount_service: use the fsmount API helpers from mount_fsmount.c")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-06-12 12:57:19 +02:00
Darrick J. Wong 3c30d1c0c2 mount_service: don't pass the chopped buffer to apply_fsconfig_mount_opts
If mount_service_handle_mntopts_cmd previously looked at the mount
options to screen for allow_{other,root}, then tokstr (aka oc->value)
has been modified and not put back.  This causes truncation of the mount
options passed to fsconfig, so let's use the snapshot that we took
previously.  Codex noticed this.

Fixes: 7211953256 ("mount_service: use the fsmount API helpers from mount_fsmount.c")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-06-12 12:57:19 +02:00
Bernd Schubert 1fbf44e06c fusermount: restrict pin_mountpoint owner check to sticky directories
The pinned-fd TOCTOU fix rejected any mountpoint not owned by the
mounting user, but check_nonroot_dir_access() only enforces ownership
for sticky directories. Restrict the pinned-inode check to match.

Fixes: bad8b22c91 ("fusermount: fix sync-init TOCTOU by mounting on a pinned mountpoint fd")
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-06-12 12:08:57 +02:00
Bernd Schubert 3fedbac9b6 mount.fuse: clear error and test skip when binary unreachable after privilege drop
With drop_privileges, mount.fuse3 execs the file system binary only
after dropping all capabilities (CAP_DAC_OVERRIDE included) while
keeping uid 0. The kernel then applies plain DAC checks to the exec, so
a binary under a directory the capability-less process cannot traverse
(e.g. a user-owned mode-0700 home) fails with EACCES and /bin/sh prints
a bare 'Permission denied', surfacing in the tests as 'file system
process terminated prematurely'.

Resolving and opening the binary before the drop was rejected: it would
perform a privileged path resolution and open() on invoker-influenced
input (confused-deputy / privilege-escalation risk). The drop-first,
resolve-after order is preserved.

Instead, pre-flight the upcoming PATH lookup after the drop and fail
with a diagnostic that names the binary and points at mount.fuse3(8).
The check runs with the final credentials, so it is deny-only. The test
detects the same situation up front (uid/gid-aware traversal check) and
skips with a precise reason; root-owned CI checkouts keep running.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-06-12 12:08:57 +02:00
Bernd Schubert bad8b22c91 fusermount: fix sync-init TOCTOU by mounting on a pinned mountpoint fd
The --sync-init code path validates the mountpoint in
mount_fuse_prepare() (check_perm() chdir()s into the directory and
rewrites the path to ".", or opens a regular-file mountpoint and
rewrites it to /proc/self/fd/N), but that pinned reference is a local
variable that is discarded. mount_fuse_finish_fsmount() later mounts
using the original path string, which move_mount() re-resolves through
whatever the symlinks now say.

An unprivileged user controls the sync-init socket, so
wait_for_signal() gives an unbounded check-to-use window: validate an
attacker-owned directory, swap a parent component to a symlink into
/etc, then signal -- the mount lands on a root-owned directory,
defeating check_nonroot_dir_access(). With user_allow_other this yields
local root via a fake sudoers drop-in.

Pin the validated inode as a single fd (mount_context.mnt_fd) obtained
from the already-chdir'd CWD or the open mountpoint fd, mount onto it
via move_mount() with MOVE_MOUNT_T_EMPTY_PATH (no path re-resolution),
and assert at the mount site that fstat(mnt_fd) still matches the stat
captured during validation. The legacy mount() path and the library
direct-mount path are unchanged (mnt_fd == -1 keeps path resolution).

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-06-11 15:38:47 +02:00
Abhinav Agarwal 349b83231b fusermount: Check fstat return value for comm fd validation
The fstat() call on the communication fd from _FUSE_COMMFD was not
checking its return value. On failure (e.g., invalid fd number),
statbuf remains uninitialized and the subsequent S_ISSOCK check
operates on garbage stack data, potentially bypassing the socket
type validation.

Check the return value and fail closed on error.

Signed-off-by: Abhinav Agarwal <abhinavagarwal1996@gmail.com>
2026-06-11 10:45:20 +02:00
Abhinav Agarwal 5e3f016bef fusermount: Reject invalid negative mount_max in fuse.conf
mount_max is parsed with %i (signed) from /etc/fuse.conf. The value
-1 is the documented sentinel for "no limit", but any other negative
value (e.g., -2 from a typo) passes the mount_max != -1 guard and
makes the mount_count >= mount_max comparison always true, blocking
all non-root FUSE mounts.

Reject values below -1 with a warning rather than silently accepting
them.

Signed-off-by: Abhinav Agarwal <abhinavagarwal1996@gmail.com>
2026-06-10 11:02:18 +02:00
Abhinav Agarwal 8eda8f9566 fusermount: Guard trailing comma removal against empty string
get_mnt_opts() accesses (*mnt_optsp)[l-1] without checking that
l > 0. If the option string is empty (reachable via read-only mount
with no additional options), this is an out-of-bounds read at
index -1.

Signed-off-by: Abhinav Agarwal <abhinavagarwal1996@gmail.com>
2026-06-10 11:02:18 +02:00
Bernd Schubert 65afaab71a Fix unbounded strcpy/strcat in mount.fuse.c
Replace strcpy() with strncpy() and strcat() with strncat().
Ensure null-termination after bounded operations.

Fixes: GitHub CodeQL Alert #104, #105
CWE-120, CWE-787, CWE-805

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-06-09 16:47:20 +02:00
Bernd Schubert d799270b76 mount_service.c: Remove an argc > 0 check (CodeQL)
As annotated by CodeQL, argc already test for above and cannot be
smaller than 3, no need to check again.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-26 14:45:38 +02:00
Bernd Schubert c17960b337 fuse_service: Avoid modifying counters in for loop
CodeQL annotates that and I personally prefer while loops for such loops
as well.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-26 14:38:28 +02:00
Bernd Schubert e2f7c7d990 Merge branch 'master' into fuse-service-container
* master:
  Change use_subtype_prefix type to bool in fuse_mnt_build_source()
  lib mount: fix fsfd leakage on error
  lib mount: include linux/mount.h in mount_i_linux.h
  lib mount: no need to fsconfig mtab options
  Fix ENODEV fallback logic for block devices with fsname
  Update the condition when to use synchronous init
  fuse_daemonize_early: Rename is_active to is_used, add new is_active
  Add a missing NULL check for x_mtab_opts in mount_fuse()
  fusermount: Fix heap buffer overflow in perform_mount()
  lib/mount.c: Restore "subtype#fsname" format for legacy kernel fallback
  fuse: No need to call strlen
2026-05-26 14:18:51 +02:00
Bernd Schubert e3fe270d74 Change use_subtype_prefix type to bool in fuse_mnt_build_source()
Just a minor API cleanup from yesterday, change type from int to
bool and add comment why the argument is needed.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-26 14:13:51 +02:00
Bernd Schubert 1d70e30b52 Fix ENODEV fallback logic for block devices with fsname
The ENODEV fallback logic in both lib/mount.c and util/fusermount.c
incorrectly combined two conditions, causing block devices with fsname
to be treated as if they had no fsname.

Original behavior (before commit 50fa7f0bc2):
    if (mo->fsname) {
        if (!mo->blkdev)
            sprintf(source, "%s#%s", mo->subtype, mo->fsname);
        // else: keep existing source (fsname for blkdev)
    } else {
        strcpy(source, type);
    }

This handled three cases:
1. fsname + non-blkdev -> "subtype#fsname"
2. fsname + blkdev     -> fsname (unchanged)
3. no fsname           -> type

Previous patches incorrectly changed this to:
    if (mo->fsname && !mo->blkdev) {
        source = fuse_mnt_build_source()
    } else {
        source = strdup(type);
    }

This only handled two cases, causing case 2 (fsname + blkdev) to be
treated as case 3 (no fsname).

This patch restores the three-way logic.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-25 23:48:40 +02:00
Bernd Schubert e4a4a3a135 Add a missing NULL check for x_mtab_opts in mount_fuse()
There might be have been null-ptr derefences.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-25 23:48:40 +02:00
Bernd Schubert 5b205b6d3f fusermount: Fix heap buffer overflow in perform_mount()
Commit 50fa7f0bc2 ("Move fuse_mnt_build_{source,type} to mount_util.c"
introduced a heap buffer overflow in the ENODEV fallback
path in fusermount.c. The prepare_mount() function now allocates source
with only strlen(fsname) + 1 bytes via fuse_mnt_build_source(), but
perform_mount() writes strlen(subtype) + 1 + strlen(fsname) + 1 bytes
when building the legacy "subtype#fsname" format.

Fix by removing source/type from struct mount_params and building them
as local variables in perform_mount() with correct allocation using the
new use_subtype_prefix parameter added in the previous commit.

The source and type strings are now:
- Built in perform_mount() with proper size allocation
- Returned via output parameters to the caller
- No longer stored in the mount_params structure

Fixes: 50fa7f0bc2 ("Move fuse_mnt_build_{source,type} to mount_util.c")
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-25 23:48:40 +02:00
Darrick J. Wong acb5e53dab mount/fuse_service: replace strcpy calls with memcpy
Remove dangerous strcpy calls with memcpy based on the lengths we used
to compute the dynamic structure size.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-21 12:11:06 -07:00
Darrick J. Wong 0f8157e72f mount_service: fix null pointer deref in mount_service_init
In theory, fuservicemount can be called with argv[0] == NULL, so let's
protect ourselves against that.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-21 12:11:06 -07:00
Darrick J. Wong ba6e172cac mount.fuse: constify arguments to try_service_main
This function no longer alters its arguments.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-21 12:11:06 -07:00
Darrick J. Wong d18df35c4e mount_service: rename IGNORE_MTAB and constify it
IGNORE_MTAB is already a preprocessor define, so don't use it as a
global variable name in mount_service.c.  Fix that by lowercasing the
name, and make the variable const to catch stray accesses.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-21 12:11:05 -07:00
Darrick J. Wong 2a97fc1e94 mount_service: fix some pointer handling
Don't leak memory or try to free static data.  Pointed out by
clang-check.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-20 19:57:57 -07:00
Darrick J. Wong cb07e6af9d fuse: use fuse_args in try_service_main instead of opencoding it
Don't open-code the argument array, just use the existing helpers.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-20 19:57:57 -07:00
Darrick J. Wong 93892e469d libfuse: fix cppcheck warnings in the new mount service code
Fix some cppcheck warnings.  No functional changes.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-19 15:04:54 -07:00
Darrick J. Wong 7211953256 mount_service: use the fsmount API helpers from mount_fsmount.c
The new fsmount API code in mount_service.c should use the new helper
functions that were recently added to mount_fsmount.c.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-11 13:19:55 -07:00
Darrick J. Wong 7e950ba1d6 Merge remote-tracking branch 'origin/master' into djwong-dev3
Merge upstream origin/master into bsbernd/fuse-service-container.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-11 09:58:07 -07:00
Bernd Schubert 2e7f517e0f lib, util: rename mnt_opts to mtab_opts at all build sites
mnt_opts was rather confusing, mtab_opts is much easier to read

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-10 22:33:36 +02:00
Bernd Schubert b9c10de892 Fix deref-before-check in mount.fuse.c
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-08 19:15:22 +02:00
Darrick J. Wong 64e0d0505d mount_service: use the mount_flags table instead of declaring our own
Use the canonical mount flags table in mount_util.c instead of
opencoding our own version in mount_service.c.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-08 19:15:21 +02:00
Darrick J. Wong 1300bca9b1 fuser_conf: fix cppcheck complaints
Since I touched this file recently, let's fix the cppcheck complaints.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-08 19:15:18 +02:00
Darrick J. Wong 8b1f63ad89 util: fix cppcheck complaints about constifying pointers
Fix various cppcheck complaints about pointers that could be const
pointers instead.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
2026-05-08 19:15:17 +02:00
Darrick J. Wong 23e8253c4d util/mount.fuse.c: loop in waitpid
waitpid can return EINTR if interrupted by a signal; don't abort when
this happens.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-08 19:15:10 +02:00
Darrick J. Wong a9ead05d3b libfuse: always send the subtype to the kernel when using fsconfig()
Although it's possible to supply a filesystem subtype when calling
fsopen(), it does not pass the stuff after the dot to the mount option
parsing mechanism like the legacy mount() call does.  Therefore, it's
necessary to pass the subtype explicitly via fsconfig() or else the
subtype will be missing from the /proc/mounts output.

For example, fuse4fs with the old mount API produces this:

/dev/sda /mnt fuse.ext4 rw,nosuid,nodev,relatime,user_id=0,group_id=0 0 0

But with the new mount API, we only get:

/dev/sda /mnt fuse rw,nosuid,nodev,relatime,user_id=0,group_id=0 0 0

...which breaks fstests, which requires the fsname to match the string
that it passes to mount -t.  Update the comment in mount_service.c to
match this requirement.

Fixes: 14cb7b93bb ("Add support for the new linux mount API")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-08 19:15:01 +02:00
Darrick J. Wong 16b8bb980c mount_service: allow installation as a setuid program
Allow installation of the mount service helper as a setuid program so
that regular users can access containerized filesystem drivers.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-04 17:24:16 +02:00
Darrick J. Wong f127c2de34 mount.fuse3: integrate systemd service startup
Teach mount.fuse3 how to start fuse via systemd service, if present.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-04 17:24:12 +02:00
Darrick J. Wong 96702c5b80 mount_service: enable unprivileged users in a similar manner as fusermount
Some Linux distributions allow unprivileged users to mount fuse
filesystems through the use of the setuid fusermount helper program.  It
would be useful to provide similar functionality when mounting a
filesystem that runs as a systemd service.

Therefore, read the fuse config file and implement the same checks as
fusermount.  The only new requirement is that the unprivileged user must
be able to open the mountpoint for write access if it's a regular file;
or have write access if it's a directory.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-04 17:24:10 +02:00
Bernd Schubert 2d1c8fe498 util: hoist the fuse.conf parsing and setuid mode enforcement code
Move all the code that parses fuse.conf into a separate file in util/ so
that fuservicemount can read the same file, then add the security checks
that occur when fusermount is trying to start up a filesystem but is not
running as root.  We'll want that for fusermount in a moment.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-04 17:23:53 +02:00
Darrick J. Wong 95cf8ff83b mount_service: update mtab after a successful mount
Update "mtab" so that non-kernel mount options (e.g. "x-fubar=XXX") are
recorded somewhere so that userspace utilities can pick that up.  Note
that this likely is not the venerable /etc/mtab, which has been a
symlink to procfs for years.  On a modern system, these non-kernel
options end up /run/mount/utab.

But that's not a detail that libfuse has to worry about directly; it's
really just calling mount -f(ake) to make the changes it wants.  Old
hats may remember the use of mount -f to update /etc/mtab after mounting
the root filesystem.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-02 17:52:42 +02:00
Darrick J. Wong f3f0869eec mount_service: use the new mount api for the mount service
Use the new fsopen/fsmount system calls to mount the filesystem so that
we get somewhat better diagnostics if something gets screwed up.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-02 17:52:42 +02:00
Darrick J. Wong 5d8b9a39a1 mount_service: add systemd socket service mounting helper
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.

In theory this could also be supported via inetd and clones, though the
author hasn't found one that supports AF_UNIX sockets.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-02 17:52:38 +02:00
Bernd Schubert 188ca87860 Verify in fuse_mnt_get_devname() that the kern device is valid
codeql gave a warning that a user might pass a random device,
so we better check the device in /dev and the device is a character
device.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-02 15:45:40 +02:00
Bernd Schubert 50fa7f0bc2 Move fuse_mnt_build_{source,type} to mount_util.c
Also make it more generic and avoid taking struct mount_opts
as parameter.

mount_fsmount.c and fusermount.c use these functions now.

Also use asprintf as suggested by Darrick.
For safety also free source and type in fuse_kern_do_mount()
when subtype is not supported - right now it would be safe
because without subtype the allocated memory is just a bit too
large, but would easy to break in future commits.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
2026-05-02 15:45:40 +02:00
Bernd Schubert d07e5f3668 Add support for sync-init of unprivileged daemons
This makes use of the bidirectional fusermount. Added is
doc/README.mount, which explains the new bidirectional
communication with fusermount.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>
2026-05-02 15:45:40 +02:00
Bernd Schubert 7f37b1ff93 Make fusermount work bidirectional for sync init
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
2026-05-02 15:45:40 +02:00
Bernd Schubert 75df12d60e fusermount: Refactor extract_x_options
Just to make it better readable.

Also add a NULL check for *regular_opts and *x_prefixed_opts,
there will be multiple callers in an upcoming commit and
it becomes harder to track that no caller has an error.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-02 15:45:40 +02:00
Bernd Schubert 235e9a1f80 fusermout: Remove the large read check
<quote Darrick>
Nobody's running 2.4 kernels
anymore, right?
</quote>

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-02 15:45:40 +02:00
Bernd Schubert c1653cf6e3 Split the fusermount do_mount function
We will need new API and old API and need to pass the options to
two different functions - factor out the option parsing.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-02 15:45:40 +02:00
Bernd Schubert eec851bedd Move 'struct mount_flags' to util.h
We actually need these in fusermount.c and for the
new mount API, which goes into its own file.

Also extend the struct with the extra safe field
used by fusermount.c

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
2026-05-02 15:45:40 +02:00