Unable to connect to DBus session bus after dropping privileges from a setuid binary

Simon McVittie simon.mcvittie at collabora.co.uk
Wed May 18 17:52:30 UTC 2016

On 18/05/16 15:20, Manish Narang wrote:
> I have an application that needs CAP_NET_ADMIN to use setsockopt on a
> netlink socket. For this I thought of starting as root, and then
> dropping to user 1000 after claiming a subset of essential capabilities.

This is a privileged process. Privileged processes are dangerous, and
shouldn't share a process-space with more code than they need to.

Have you considered carrying out your root-required actions in a
separate process that is not the one that connects to the session bus? A
popular pattern for this is to have a service that runs on the system
bus (like NetworkManager, ConnMan, udisks, etc.) and have ordinary user
processes submit requests to it. If required, it can use polkit
(formerly PolicyKit) to determine whether the request should be obeyed
or rejected.

> LOG1((TEXT("Dropped root = %d\n"),setuid(getuid())));
> LOG1((TEXT("Dropped group= %d\n"),setgid(getgid())));

You probably want to use setresuid(), setresgid() to give up any ability
to go back to being root.

You can use dbus-daemon as an example of this, in fact: if configured
with audit support (for SELinux and/or AppArmor), the system bus starts
as uid 0, retains CAP_AUDIT_WRITE, and loses all other capabilities when
it drops privileges to its own uid (typically a system user named
"messagebus" or "dbus").

> The dbus calls start after the above function is executed. The session
> bus ID is returned as 0 which is incorrect.

What is a "session bus ID"? That isn't a piece of standard D-Bus jargon.

You haven't said whether you are using libdbus (part of the reference
implementation "dbus"), GDBus (part of GLib), sd-bus (part of systemd)
or some other implementation of the client side of the D-Bus protocol.

> 22:35:01.641:DBus|  612|  612|Success|Connect at dbusipc.cpp:170|Unable
> to connect to the Session bus for error
> org.freedesktop.DBus.Error.NotSupported

It might help to run your process through strace or similar, and find
out which system call (if any) is raising this error.

It might also help to read the human-readable message that should have
accompanied this machine-readable error name (in libdbus they're
DBusError.message and DBusError.name respectively).

> unix:abstract=/tmp/dbus-QB8cEiSybh // This is just a system("echo
> $DBUS_SESSION_BUS_ADDRESS"); call to indicate that the bus address is
> available in the program environment variables. *****

Note that libdbus deliberately does not trust the environment when it
detects that it was used in a setuid or similarly privileged binary, to
mitigate security vulnerabilities caused when setuid binaries do not
sanitize their (attacker-supplied) environment variables (CVE-2012-3524).

We currently use a simplistic check whether euid == uid, because using
secure_getenv() broke gnome-keyring-daemon, a process that (like yours)
starts with capabilities that it later drops. However, we might use
secure_getenv() in future, if gnome-keyring has subsequently been fixed
- it is the correct thing to do. This would result in the
potentially-attacker-supplied environment being ignored entirely,
because secure_getenv() checks whether the process *was ever*
privileged, not whether it *is now* privileged.

Simon McVittie
Collabora Ltd. <http://www.collabora.com/>

More information about the dbus mailing list