Control: clone -1 -2
Control: reassign -2 adduser 3.137
Control: retitle -2 adduser: logger --id fails with "Operation not permitted" 
in unprivileged containers

Context for adduser maintainers: autopkgtest creates a "testbed"
(chroot, container or VM) via a pluggable backend, and tries to create an
unprivileged user in the testbed so it can run tests as that user, using
adduser (if installed in the testbed) or plain useradd (otherwise). Peter
Colberg reported that when autopkgtest is using the podman backend,
in a "full system" container that is running systemd as pid 1, this
fails, because `logger --id` requires the ability to log with fake
SCM_CREDENTIALS (pretending to be the adduser process rather than its
child), and unprivileged podman containers do not normally have the
necessary capability (CAP_SYS_ADMIN) to achieve that.

Reproducer (this requires the ability to run podman, but no elevated
privileges):

$ autopkgtest-build-podman --init=systemd --release=sid
$ autopkgtest hello -- podman --init localhost/autopkgtest/systemd/debian:sid

I see that either `logger id` exits with status 0 or `adduser` ignores
a nonzero exit status, so in fact the only reason this fails is that
autopkgtest is being extra-careful and refusing to continue if its
create-normal-user script produces output on stderr.

On Sun, 30 Jun 2024 at 17:17:47 -0400, Peter Colberg wrote:
> The permission error is triggered by logger's --id option:
> 
>   podman exec "$container" strace -f adduser --disabled-login --gecos 
> "Temporary autopkgtest user,,," test
> 
>   [pid   370] execve("/bin/logger", ["logger", "--id=369", "--tag=adduser", 
> "--priority=user.crit", "", "--", "The user `test' already exists."], 
> 0x55efa22252d0 /* 7 vars */) = 0
> 
> When specifying an existing process, this fails in podman:
> 
>   podman exec "$container" logger --id=1 Testing
> 
>   logger: send message failed: Operation not permitted
> 
> See also https://github.com/jonathanio/update-systemd-resolved/issues/25
> 
> I believe the permission is CAP_SYS_ADMIN; from capabilities(7):
> 
> > forge PID when passing socket credentials via UNIX domain sockets;
> 
> Starting the container with CAP_SYS_ADMIN resolves the issue:
> 
>   container=$(podman run --cap-add=sys_admin --detach=true 
> autopkgtest/systemd/debian:sid /sbin/init)

As far as I know, running podman/Docker containers that can exercise
CAP_SYS_ADMIN is discouraged, because it reduces hardening against sandbox
escapes that can elevate privileges from root in the container to the uid
that ran the container on the host system. I don't know whether
CAP_SYS_ADMIN is sufficient on its own to carry out that privilege
elevation attack. I believe CAP_SYS_ADMIN *would* be sufficient to escape
from Docker.

With autopkgtest hat on, I would prefer not to make it add CAP_SYS_ADMIN,
so that we can be somewhat confident that the code under test cannot escape
from the container (or at least that if it could, that would be treated as
a podman security vulnerability).

> I am unsure whether this should be considered a bug in adduser

I think it should (let's use the cloned bug for this).

For example adduser could check for CAP_SYS_ADMIN and only use --id
if that capability is available, or it could log via Sys::Syslog if
available (falling back to stderr or to logger(1) without --id if the
full perl package isn't installed).

It could also be argued that this is a logger (util-linux) bug, because
logger(1) says "otherwise the socket credentials are not modified and
the problem is silently ignored", but this bug report indicates that
the problem is in fact not *silently* ignored.

> if not,
> if adduser is correct in assuming CAP_SYS_ADMIN, dropping adduser from
> create-normal-user and always using useradd seems a reasonable solution.

If the adduser limitation cannot be fixed soon, then I think it might
also be wise to do one of these in autopkgtest:

- avoid adduser and use useradd directly
  (or possibly systemd-sysusers if it happens to be installed)

- or tolerate output on stderr from adduser

- or avoid adduser conditionally, if `setpriv --dump` reports that we
  don't have sys_admin in our capability bounding set (but I don't know
  how old `setpriv --dump` is, and autopkgtest is meant to support being
  run against very old testbeds)

Let's keep the original bug number #1059725 for this.

    smcv

Reply via email to