Note that the minimum required Python version is 3.9.
+mkosi needs unrestricted abilities to create and act within namespaces. Some
+distros restrict creation of, or capabilities within, user namespaces, which
+breaks mkosi.
+
+For information about Ubuntu, that implements such restrictions using AppArmor, see
+https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces.
+For other systems, try researching the `kernel.unprivileged_userns_clone` or
+`user.max.user_namespace` sysctls.
+
+For Ubuntu systems, you can remove the restrictions for mkosi by
+adapting this snippet to point to your mkosi binary, copying it to
+`/etc/apparmor.d/path.to.mkosi`, and then running `systemctl reload apparmor`:
+
+```
+abi <abi/4.0>,
+
+include <tunables/global>
+
+/path/to/mkosi flags=(default_allow) {
+ userns,
+}
+```
+
# Frequently Asked Questions (FAQ)
- Why does `mkosi qemu` with KVM not work on Debian/Kali/Ubuntu?
CLONE_NEWNET = 0x40000000
CLONE_NEWNS = 0x00020000
CLONE_NEWUSER = 0x10000000
+EPERM = 1
ENOENT = 2
LINUX_CAPABILITY_U32S_3 = 2
LINUX_CAPABILITY_VERSION_3 = 0x20080522
try:
unshare(CLONE_NEWUSER)
+ except OSError as e:
+ if e.errno == EPERM:
+ print(UNSHARE_EPERM_MSG, file=sys.stderr)
+ raise
finally:
os.write(event, ctypes.c_uint64(1))
os.close(event)
"""
+UNSHARE_EPERM_MSG = """
+mkosi was forbidden to unshare namespaces.
+
+This probably means your distribution has restricted unprivileged user namespaces.
+
+Please consult the REQUIREMENTS section of the mkosi man page, e.g. via "mkosi
+documentation", for workarounds.
+"""
+
+
def main() -> None:
# We don't use argparse as it takes +- 10ms to import and since this is purely for internal
# use, it's not necessary to have good UX for this CLI interface so it's trivial to write
if suppress_chown and (userns or userns_has_single_user()):
seccomp_suppress_chown()
- unshare(namespaces)
+ try:
+ unshare(namespaces)
+ except OSError as e:
+ # This can happen here as well as in become_user, it depends on exactly
+ # how the userns restrictions are implemented.
+ if e.errno == EPERM:
+ print(UNSHARE_EPERM_MSG, file=sys.stderr)
+ raise
# If we unshared the user namespace the mount propagation of root is changed to slave automatically.
if not userns: