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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
* 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
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>