Filesystem Utility for Sandboxes and Stuff
Forwarding Userspace Syscalls Silently
FUSE unnecessary - syscalls sufficient
File Union Sans Setuid
Look ma, no FUSE! A userspace overlay filesystem implementation using ptrace-based syscall interception. No FUSE, no kernel modules, no mount permissions required.
Writeup: Look ma, no FUSE!
fuss wraps your program and intercepts filesystem syscalls, redirecting them through a virtual filesystem layer compatible with overlayfs/fuse-overlayfs. Syscalls that don't use paths are just passed through transparently.
fuss stores layers, whiteout markers and opaque directory markers exactly as fuse-overlayfs and overlayfs would. This means you can use fuss and then decide you're a huge fan of mounting filesystems after all. It will still "just work™," with your data intact and available. In fact, fuss was extensively tested by "chrooting" into overlay layers from real-life Docker images just to prove that it can.
go install github.com/psarna/fuss/cmd/fuss@latestor build from source like a pro:
git clone https://github.com/psarna/fuss
cd fuss
go build -o fuss ./cmd/fussfuss [options] -- command [args...]
Options:
--mountpoint PATH- Virtual mount point (required)--lowerdir PATH- Read-only lower layers, colon-separated (rightmost = bottom)--upperdir PATH- Writable upper layer directory--whiteout MODE- Whiteout style: "chardev" or "fileprefix" (default: fileprefix)
Debug logging:
FUSS_LOG_LEVEL=intercept- log only intercepted syscalls (human-readable names)FUSS_LOG_LEVEL=debug- verbose syscall tracing (same asFUSS_DEBUG=1)
Basic overlay with one lower layer:
fuss --mountpoint=/app \
--lowerdir=/opt/myapp \
--upperdir=/tmp/changes \
-- bashMulti-layer (think Docker container):
fuss --mountpoint=/rootfs \
--lowerdir=/layers/base:/layers/deps:/layers/app \
--upperdir=/tmp/runtime \
-- ./start.shRun a build in isolation:
fuss --mountpoint=/home/user/project \
--lowerdir=/home/user/project \
--upperdir=/tmp/build-output \
-- make allIntercept-only logging (shows just intercepted syscalls):
sarna@sarna-work:~/repo/fuss$ FUSS_LOG_LEVEL=intercept ./fuss --mountpoint=/mnt --lowerdir=/tmp/rust-1.93-slim-bullseye/layers/2-71d08cce6d45/rootfs:/tmp/rust-1.93-slim-bullseye/layers/1-1c3e0f92551c/rootfs --upperdir=/tmp/upper -- /bin/bash
sarna@sarna-work:~/repo/fuss$ ls -lash /mnt/var/lock
time=2026-02-09T18:22:50.417+01:00 level=INFO msg=intercept syscall=statx path=/mnt/var/lock resolved=/mnt/var/lock vfs=/var/lock
ls: /mnt/var/lock
time=2026-02-09T18:22:50.417+01:00 level=INFO msg=intercept syscall=readlink path=/mnt/var/lock resolved=/mnt/var/lock vfs=/var/lock
time=2026-02-09T18:22:50.417+01:00 level=INFO msg=intercept syscall=statx path=/mnt/var/lock resolved=/mnt/var/lock vfs=/var/lock
0 lrwxrwxrwx 1 sarna sarna 9 lut 2 01:00 /mnt/var/lock -> /run/lock- fuss starts your command as a child process with ptrace attached
- Every filesystem syscall (open, read, write, stat, etc.) is intercepted
- Paths under --mountpoint are redirected to the overlay VFS
- The overlay resolves files across layers (upper first, then lowers)
- Writes trigger copy-up from lower to upper layer
- Deletes create whiteout markers to hide lower-layer files
fuss uses formats compatible with Linux overlayfs:
fileprefix (default, portable):
- Deleted files:
.wh.<filename>empty file - Opaque dirs:
.wh..wh..opqfile inside directory
chardev (kernel overlayfs compatible):
- Deleted files: character device with major:minor 0:0
- Opaque dirs:
trusted.overlay.opaque=yxattr - Requires CAP_MKNOD
After running fuss, you can mount the same directories with fuse-overlayfs or kernel overlayfs and see consistent results.
The pkg/passthrough package provides a simple reference implementation of the VFS interface. Use it as a template to implement custom filesystem behaviors:
- Logging/auditing filesystem
- Encryption layer
- Caching layer
- Access control
- Linux x86_64 and arm64 only (ptrace is architecture-specific)
- Some syscall edge cases may not be fully handled
- Performance penalty expected from ptrace
- Applications that trace themselves (e.g. gdb, strace) will not work out-of-the-box due to one process only being traceable by one tracer at a time
pkg/vfs/ - Virtual filesystem interface
pkg/tracer/ - Ptrace-based syscall interception
pkg/overlay/ - Overlay filesystem implementation
pkg/passthrough/ - Simple passthrough VFS (reference implementation)
cmd/fuss/ - CLI entrypoint
MIT

