Skip to content

Repository files navigation

defused - a setuid-less fusermount implementation

The Linux kernel's implementation of Filesystem in Userspace requires root permissions, despite its use in unprivileged programs. This has normally been solved via libfuse's setuid helper program fusermount/fusermount3.

This does means that certain kinds of security policies cannot be applied, specifically no_new_privileges process flag.

$ mkdir _lower _mnt
$ # Without no_new_privileges
$ fuse-overlayfs -o lowerdir=_lower _mnt
$ fusermount3 -u _mnt
$ # With no_new_privileges
$ setpriv --no-new-privs -- fuse-overlayfs -o lowerdir=_lower _mnt
/usr/bin/fusermount3: mount failed: Operation not permitted
fuse-overlayfs: cannot mount: Operation not permitted

The no_new_privileges flag is important for proper application sandboxing, as Linux features such as landlock and seccomp-bpf can only be used after a call to prctl(PR_SET_NO_NEW_PRIVS, 1).

Using Unix domain sockets like defused does also means that the FUSE-mounting capability can be granted to applications by allow-listing the socket in the application's AppArmor or Landlock configuration. Doing so with fusermount3 is much more challenging, as it is not compatible with Landlock.

Requirements

Defused requires Linux 6.13 or later: the service authorizes unmounts by resolving a client's pidfd to its pid via the PIDFD_GET_INFO ioctl, which was added in 6.13. Support for older kernels is possible by falling back to parsing /proc/self/fdinfo/<pidfd>'s Pid: line, but that fallback is not currently implemented.

Project structure

This project provides the following:

  • A system service that listens on /run/defused/defused.sock.
  • A replacement fusermount3 binary to communicate with the service.

The system service is written to use systemd socket activation with Accept=yes. For testing or on systems without systemd, defused --daemon can be used to create the Varlink socket and fork off child processes to handle accepted connections.

Root callers are delegated directly to libfuse's fusermount3, since they do not need the unprivileged service path. This means libfuse's fusermount3 should still be installed, just not in /usr/bin (ex. /usr/lib/fuse3/fusermount3).

Mountpoint ownership model

Defused uses a different mountpoint ownership model than libfuse's setuid fusermount3. For non-root mounts, the mountpoint must be a directory or regular file owned by the caller. It must be writable by that caller, and directories must also be searchable.

This means defused rejects mounts on writable shared directories owned by another user, even when libfuse's setuid helper would allow them because the directory is not sticky. The stricter rule keeps the privileged service's authorization decision tied to the mountpoint file descriptor it receives, instead of trying to reproduce libfuse's path-based access(W_OK) check across the client/service protocol.

This does lead to some additional mounting possibilities, all due to other filesystem restrictions. If a given file path is owned by the user, but the process is unable to write to the path due to POSIX ACLs, LSMs like SELinux, AppArmor, or Landlock, libfuse's setuid implementation will deny the mount while this implementation will still perform it. I do not believe this is an issue, however, as sandboxed applications should deny access to /dev/fuse or /run/defused/defused.sock.

See protocol.md for more information on how defused works.

Nix binary cache

I am using cachix as a binary cache:

# Add to nix.conf
extra-substituters = https://defused.cachix.org
extra-trusted-public-keys = defused.cachix.org-1:/YD+2Bmle49JSliBhGRqTKpLYhvruoFyMPPU071YCAY=

Contributing

See contributing.md.

Licensing

This project copies a some helpers from libfuse in util.h, which are either GPL-2.0-only or LGPL-2.1-only (marked via SPDX snippets in util.c). All of my code is licensed under GPL-2.0-or-later, but the resulting binary will be GPL-2.0-only.

About

A setuid-less fusermount implementation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages