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

Manish manishn2 at kpit.com
Thu May 19 09:17:30 UTC 2016


On Wed, 2016-05-18 at 18:52 +0100, Simon McVittie wrote:
> 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.

I have considered that, but given my requirements it may not be
feasible. It is still being discussed and not completely off the table.

> > 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.

Yes, setres(g)uid is what is I will move to finally. This was just a
POC.

> 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.

It's our jargon.. My problem is that dbus_bus_get returns NULL.

> 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.
>

I'm using libdbus.

> > 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).
>

It's dbus_bus_get as mentioned above. Here's the error that I get.
DBusError.name = org.freedesktop.DBus.Error.NotSupported
DBusError.message = Unable to autolaunch when setuid

> > 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).

I've already read about the exploit, and your statement "NOTE: libdbus
maintainers state that this is a vulnerability in the applications that
do not cleanse environment variables, not in libdbus itself: "we do not
support use of libdbus in setuid binaries that do not sanitize their
environment before their first call into libdbus."
This is why I wrote to this mailing list, to try and understand what is
meant by cleansing the environment variables?

If libdbus ignores environment variables in case of a setuid process
then how would one provide the correct $DBUS_SESSION_BUS_ADDRESS
variable to it?

> We currently use a simplistic check whether euid == uid, ...

My problem is exactly that, as noticed in the logs I posted earlier. At
the time of making the dbus calls, I have dropped to euid 1000. So my
euid(1000) = uid(1000)

23:48:10.597: 1| 5060| 5060|-    |setPermissions at kservicebase.cpp:196|
Before GetUID = 1000
23:48:10.597: 1| 5060| 5060|-    |setPermissions at kservicebase.cpp:197|
Before GetEUID = 0
23:48:10.597: 1| 5060| 5060|-    |setPermissions at kservicebase.cpp:201|
Dropped root = 0
23:48:10.597: 1| 5060| 5060|-    |setPermissions at kservicebase.cpp:204|
After GetUID = 1000
23:48:10.597: 1| 5060| 5060|-    |setPermissions at kservicebase.cpp:205|
After GetEUID = 1000
23:48:11.599:DBus| 5060| 5060|Success|Connect at dbusipc.cpp:170|Unable to
connect to the Session bus for error
org.freedesktop.DBus.Error.NotSupported & Unable to autolaunch when
setuid

So if it's a simple euid == uid check, then shouldn't my calls go
through while my euid is 1000?

This message contains information that may be privileged or confidential and is the property of the KPIT Technologies Ltd. It is intended only for the person to whom it is addressed. If you are not the intended recipient, you are not authorized to read, print, retain copy, disseminate, distribute, or use this message or any part thereof. If you receive this message in error, please notify the sender immediately and delete all copies of this message. KPIT Technologies Ltd. does not accept any liability for virus infected mails.


More information about the dbus mailing list