# Research: user-level containers with overlayfs Measured on this machine: Ubuntu, kernel 7.0.0-38, AppArmor 5.0.2, slirp4netns 1.3.3, uid 1000, no root at runtime. ## What works unprivileged 1. `clone(CLONE_NEWUSER|NEWNS|NEWPID|NEWUTS|NEWIPC[|NEWNET])`, then the parent writes `setgroups=deny`, `uid_map`, `gid_map` (single entry, own uid). No setuid helpers (`newuidmap`) needed. 2. overlayfs mounts inside the userns (kernel >= 5.11) with the `userxattr` option. Upper and work dirs must be on a filesystem with user xattrs (ext4, tmpfs >= 6.6 verified for ours). 3. Mounts that work inside: tmpfs, proc (needs own pidns), devpts (new instance, no `gid=` since gid 5 is unmapped), bind mounts of host `/dev/{null,zero,full,random,urandom,tty}` (no `mknod` in a userns), read-only remount of `/proc` subpaths (must copy locked flags from `statvfs`). 4. `pivot_root(".", ".")` plus lazy unmount of the old root. ## What does not - Writing mapped uid ranges beyond own uid needs `newuidmap` + `/etc/subuid`. Skipped: single mapping keeps the design dumb. Consequence: no chown/su to other uids inside, so `apt install` as non-root users does not work. - cgroups: no memory/cpu/pid limits without systemd delegation. Not implemented (gap). - Ubuntu 24.04+: `kernel.apparmor_restrict_unprivileged_userns=1` lets any binary create a userns but strips capabilities inside it. Measured: uid_map write succeeds, first `mount` fails with EPERM. Fix is an AppArmor profile granting `userns` to the binary (`apparmor/doos`, install once with sudo). Turning the sysctl off is global and weaker. ## Networking options | Option | Result | |---|---| | slirp4netns (chosen default) | Works unprivileged. Needs only the netns of the child pid. `--disable-host-loopback` blocks the container from reaching host 127.0.0.1 (measured: blocked). DNS via 10.0.2.3 works (measured). | | pasta | Installed here but not used: slirp4netns suffices, one dependency. | | veth + bridge | Needs CAP_NET_ADMIN in the host netns. Not possible unprivileged. | | host netns | Works, zero isolation. Offered as explicit `--net host`. | ## Host safety design - No host paths writable: overlay lower dirs are only reachable through overlay (writes copy up to the container upper). Verified: write to `/usr` and `/etc` inside leaves host untouched. - Only `/usr /etc /opt` and compat dirs are exposed read-through. `/home`, `/var`, `/sys`, `/root` of the host are not present. - Old root detached after pivot, `no_new_privs`, `/proc` hardened, nosuid/nodev on tmpfs/devpts/overlay. - Residual exposure (gaps): host `/etc` is readable inside (any world-readable secret in it); abstract unix sockets are shared in `--net host`; no resource cgroups, so a container can fill the disk through its upper dir or fork-bomb within the user's `RLIMIT_NPROC`; kernel attack surface of userns is that of the host kernel. ## Measurements (this machine, 5 sequential `attach -- true`) | Mode | Per attach | |---|---| | slirp | ~26 ms | | none | ~6 ms | Single run set, one machine; no other hardware measured.