Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sandbox: Spit out some info when unsharing userns gets EPERM #3266

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions mkosi/resources/man/mkosi.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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?
Expand Down
24 changes: 23 additions & 1 deletion mkosi/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
CLONE_NEWNET = 0x40000000
CLONE_NEWNS = 0x00020000
CLONE_NEWUSER = 0x10000000
EPERM = 1
ENOENT = 2
LINUX_CAPABILITY_U32S_3 = 2
LINUX_CAPABILITY_VERSION_3 = 0x20080522
Expand Down Expand Up @@ -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)
bjackman marked this conversation as resolved.
Show resolved Hide resolved
raise
finally:
os.write(event, ctypes.c_uint64(1))
os.close(event)
Expand Down Expand Up @@ -694,6 +699,16 @@ def execute(self, oldroot: str, newroot: str) -> None:
"""


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
Expand Down Expand Up @@ -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:
Expand Down
Loading