Skip to content

Instantly share code, notes, and snippets.

@mgerstner
Created November 23, 2021 10:43
Show Gist options
  • Save mgerstner/3690727b9d532f4ab845b79680cbd985 to your computer and use it in GitHub Desktop.
Save mgerstner/3690727b9d532f4ab845b79680cbd985 to your computer and use it in GitHub Desktop.
Connection to hosts D-Bus daemon not working from within user namespace

When trying to enter a user namespace and still communicating with the rest of the Linux system via D-Bus then this won't work:

$ unshare -U -r
$ root # dbus-monitor --system
Failed to open connection to system bus: Did not receive a reply. Possible causes include: \
 the remote application did not send a reply, the message bus security policy blocked the reply, \
 the reply timeout expired, or the network connection was broken.

The reason for this is a bit intricate. It is not found on kernel permission level but in the D-Bus userspace logic. It is explained in this mailing list post:

https://lists.linuxcontainers.org/pipermail/lxc-users/2017-March/012934.html

Basically the D-Bus client from within the user namespace explicitly sends its preceived uid (i.e. 0 in this case) to the D-Bus daemon. This is then rejected by the D-Bus daemon, probably because it doesn't match what the kernel reports via the SO_PEERCREDS socket option.

There is no easy workaround but an LD_PRELOAD library seems to help:

$ cat <<EOF >geteuid_preload.c
#include <unistd.h>

// simply report the real host UID unconditionally
// you need to replace UID 1000 by whatever UID you user has
// in the host user namespace
uid_t geteuid() {
    return 1000;
}
EOF

$ gcc geteuid_preload.c -shared -o geteuid_preload.so

By using this library we can make the D-Bus protocol authentication work again:

$ unshare -U -r

# in the user namespace we appear to have uid 0
$ root # id -u
0

$ root # export LD_PRELOAD=$PWD/geteuid_preload.so
# now it seems we have uid 1000 as outside the user namespace
$ root # id -u
1000

$ root # dbus-monitor --system
signal time=1637663883.226976 sender=org.freedesktop.DBus -> destination=:1.27 serial=2 \
 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired

Note that this means that programs that should think they're actually root in the user namespace could get confused again, because geteuid() not longer returns zero. For some use cases it works out, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment