Linux host setup
minimald and mip run every session and task inside their own
sandbox composed of an unprivileged user namespace and other Linux
namespaces, similar to how containers are sandboxed on
Kubernetes. Root/sudo access is not needed to create these sandboxes;
however, some Linux distributions require enabling unprivileged user
namespace creation.
Most distributions allow this by default. Ubuntu 24.04 and later require the small configuration change described below.
The symptom
Ubuntu 24.04 ships kernel.apparmor_restrict_unprivileged_userns=1, which stops
an unconfined program from creating a user namespace. The sandbox child dies
writing its uid map before it runs anything, so no session can start:
DIAG hakoniwa container/process exited non-zero code=125 exit_code=None
reason=write("/proc/self/uid_map", ..) => Operation not permitted (os error 1)
On such a host min session activate fails before any session exists.
The daemon checks the namespace on every create and refuses with the
cause and its fix, which min prints as its error. mip prints the
same cause and the fix for its own binary when a task starts. Make sure
that the host is the cause with stock tools, no Minimal involved:
$ cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns
1
$ unshare --user --map-root-user id
unshare: write failed /proc/self/uid_map: Operation not permitted
The fix, by cause
The refusal names one of two causes. Each has its own fix. Minimal
does not suggest kernel.apparmor_restrict_unprivileged_userns=0: that
sysctl turns the protection off for every program on the host.
Ubuntu restricts unprivileged user namespaces
This is the AppArmor restriction above. An AppArmor profile that grants
userns to one binary lifts it for that binary alone, and the profile
attaches by binary path.
For minimald, installed with the curl … | sh installer, finish the
install. The step loads the profile for the installed daemon:
$ min finalize-install --show
$ min finalize-install
The profile takes effect when the daemon next starts. Run min stop,
then your command again. To remove the profile run:
$ min finalize-install --undo
For a minimald built from source, run the loader from the checkout
with the binary’s path:
$ sudo scripts/install-apparmor-profile.sh --path "$PWD/target/debug/minimald"
For mip, which builds every task in the same kind of sandbox, attach
the profile to the mip binary with --path. min finalize-install
covers the daemon alone. The installer places the loader under the
Minimal data directory:
$ sudo bash ~/.local/share/minimal/apparmor/install-apparmor-profile.sh --path "$(command -v mip)"
From a checkout, the same loader is scripts/install-apparmor-profile.sh,
and one run can take several --path flags:
$ sudo scripts/install-apparmor-profile.sh --path "$PWD/target/debug/minimald" --path "$PWD/target/debug/mip"
To remove a profile the loader installed:
$ sudo scripts/install-apparmor-profile.sh --uninstall # from a checkout
User namespaces switched off
Separately from the AppArmor restriction, no program can create a user
namespace on a kernel built without CONFIG_USER_NS, or on a host with
user.max_user_namespaces set to 0. No profile lifts this. The daemon
reads the sysctl on every create, so the first command below clears the
refusal at once. The second keeps it across reboots:
$ sudo sysctl -w user.max_user_namespaces=15000
$ sudo sh -c "echo 'user.max_user_namespaces=15000' > /etc/sysctl.d/60-minimal-userns.conf"
On a kernel built without CONFIG_USER_NS, use a kernel with user
namespaces enabled. Debian-derived kernels that carry
kernel.unprivileged_userns_clone need it set to 1 too. The daemon
does not read that key, so it does not refuse the create. The session
then fails at attach with the uid_map error above.
Last updated