Skip to content

Commit

Permalink
sandbox: Spit out some info when initial unshare gets EPERM
Browse files Browse the repository at this point in the history
To try and minimise the pain of this issue
(#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).
  • Loading branch information
bjackman committed Dec 8, 2024
1 parent c4bbf3b commit e145d8b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
25 changes: 25 additions & 0 deletions mkosi/resources/man/mkosi.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2904,6 +2904,31 @@ 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 and AppArmor implementations of this
restriction, 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/AppArmor systems, you should be able to remove the restrictions by
adapting this snippet to point to your mkosi binary, copying it to
/etc/apparmor.d/mkosi, and then running `systemctl reload apparmor`:

```
abi <abi/4.0>,
include <tunables/global>
/path/to/mkosi flags=(default_allow) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/mkosi>
}
```

# Frequently Asked Questions (FAQ)

- Why does `mkosi qemu` with KVM not work on Debian/Kali/Ubuntu?
Expand Down
23 changes: 22 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,9 @@ 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)
finally:
os.write(event, ctypes.c_uint64(1))
os.close(event)
Expand Down Expand Up @@ -694,6 +698,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 +820,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

0 comments on commit e145d8b

Please sign in to comment.