From: Brendan Jackman Date: Sun, 8 Dec 2024 12:03:57 +0000 (+0100) Subject: sandbox: Spit out some info when initial unshare gets EPERM X-Git-Tag: v25~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b398597eee08a449b6ee8241f227065b0203a69b;p=thirdparty%2Fmkosi.git sandbox: Spit out some info when initial unshare gets EPERM To try and minimise the pain of this issue (https://github.com/systemd/mkosi/issues/3265), dump some info that might help users resolve it. I had a quick look around expecting to find a document from Red Hat discussing this topic much like the Ubuntu one I've linked here, but I didn't find it. Hopefully if it exists someone else can add it later. I'm doing this via a direct write to stderr because of the comment at the top of sandbox.py saying to avoid imports. If this is highly undesirable it looks like log.log_notice would be the right choice here (then you don't need the annoying ANSI codes). --- diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index d2ff8a9b0..ab842ec1f 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -2904,6 +2904,29 @@ images you want to build. 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 , + +include + +/path/to/mkosi flags=(default_allow) { + userns, +} +``` + # Frequently Asked Questions (FAQ) - Why does `mkosi qemu` with KVM not work on Debian/Kali/Ubuntu? diff --git a/mkosi/sandbox.py b/mkosi/sandbox.py index be1a0370f..51ae6a3cf 100755 --- a/mkosi/sandbox.py +++ b/mkosi/sandbox.py @@ -28,6 +28,7 @@ CLONE_NEWIPC = 0x08000000 CLONE_NEWNET = 0x40000000 CLONE_NEWNS = 0x00020000 CLONE_NEWUSER = 0x10000000 +EPERM = 1 ENOENT = 2 LINUX_CAPABILITY_U32S_3 = 2 LINUX_CAPABILITY_VERSION_3 = 0x20080522 @@ -342,6 +343,10 @@ def become_user(uid: int, gid: int) -> None: 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) @@ -694,6 +699,16 @@ See the mkosi-sandbox(1) man page for details.\ """ +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 @@ -806,7 +821,14 @@ def main() -> None: 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: