dbus-daemon, passing fd and SELinux
David Sommerseth
dbus at lists.topphemmelig.net
Wed Nov 7 20:53:50 UTC 2018
On 07/11/2018 20:01, Tom Gundersen wrote:
> Hi David,
Hi Tom! Didn't recall you're paying attention here too (you can ignore the
private mail ;-) ) ... thanks a lot for a great feedback!
And thanks to you too, Simon, for valuable insight as well!
> On Wed, Nov 7, 2018 at 3:31 PM David Sommerseth <dbus at lists.topphemmelig.net
> <mailto:dbus at lists.topphemmelig.net>> wrote:
>
> The raw SELinux denial is:
> ---------------------------------------------------------------------
> type=AVC msg=audit(1541594038.506:688):
> avc: denied { read write }
> for pid=4880 comm="dbus-daemon"
> path="/dev/net/tun" dev="devtmpfs" ino=2711
> scontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023
> tcontext=system_u:object_r:tun_tap_device_t:s0
> tclass=chr_file
> permissive=0
>
> type=SYSCALL msg=audit(1541594038.506:688): arch=x86_64
> syscall=recvmsg success=yes exit=EBADRQC
> a0=63 a1=7ffc08dc7630 a2=40000000 <tel:400%2000%20000> a3=9
> items=0 ppid=1 pid=4880
> auid=4294967295
> uid=81 gid=81 euid=81 suid=81 fsuid=81 egid=81 sgid=81 fsgid=81
> tty=(none) ses=4294967295
> comm=dbus-daemon exe=/usr/bin/dbus-daemon
> subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 key=(null)
> ---------------------------------------------------------------------
>
>
> So this is a _denial_ where SELinux denied the dbus-daemon to do read/write
> operations on /dev/net/tun. The source (dbus-daemon) runs under the
> system_dbusd_t context (scontext) and it tries to target a chr_file (tclass)
> labelled with the tun_ap_device_t context (tcontext). So, this is the default
> SELinux targeted policy on RHEL/Fedora.
>
>
> This is not exactly right (and SELinux is misleading here). The failure is not
> necessarily due to dbus-daemon doing a read/write on /dev/net/tun, it is due
> to dbus-daemon doing SOMETHING which requires read/write access to
> /dev/net/tun (more about what later).
>
> The dbus-daemon tried to do a recvmsg() syscall which returned EBADRQC, which
> I believe means "Invalid Request Code". This is anyhow something the kernel
> returned, so I presume it is correct behaviour.
>
>
> This part is highly misleading. I don't know what tool you used to get
> "exit=EBADRQC", but what the kernel should be sending out is "exit=56". This
> means that the syscall succeeded, and that it returned 56. That sounds about
> right, as recvmsg() returns the number of bytes received.
I used the tool from the sealert/seapplet tools, which does decode the strings
a bit. I saw the "exit=" with an error code and it didn't occur to me that it
would be number of bytes when success=yes. I merely interpreted it as "the
call returned successfully with an error". It did puzzle me a bit having a
successful error as a result, but I expected the tooling to do a far more
accurate interpretation :)
Thanks for clarifying this!
> The crucial part of this is that it was recvmsg() that triggered the above AVC
> failure.
>
> As far as I've understood, the dbus-daemon needs to do the recvmsg()/sendmsg()
> dance on the FD to be able to pass the FD from the service to the caller.
>
>
> Correct, dbus-daemon calls recvmsg() / sendmsg() to receive and forward
> messages between its clients. The FD in question is then passed along as
> auxillary data. Apart from doing this forwarding, dbus-daemon does not touch
> the FD, it is the receiving of the FD itself that fails.
Good! Then I at least have a better idea how to beat SELinux into submission :)
> What actually happens is that in order to receive an FD, dbus-daemon needs to
> have the same SELinux permissions necessary to open the FD in the first place.
> The FD you are passing is opened RW, and opening something RW requires your
> SELinux context to be permitted to actually read and write to it, even if it
> never does. That is the failure you are seeing. That said, the effect of the
> failure is not to fail the recvmsg() call, the payload is returned just as
> normal. However, the array of FDs passed as auxillary data is truncated at the
> first FD that is not permitted to be transmitted, in effect it is silently
> dropped (from the point of view of dbus-daemon, obviously there is still the
> log message).
>
> So to my questions:
>
> - When this error occurs (dbus-daemon being denied the recvmsg() call), the
> netcfg service hits the GBusNameLostCallback function and the service is
> being shutdown. Why does this happen? Is this expected?
>
>
> Even though the recvmsg() call succeeds, the resulting DBus message contains
> fewer FDs than exepected, which is a protocol violation. The client is
> therefore disconnected. So yes, this is expected.
That's a fair point. And since there is no way to extract any information of
why this happened, we just have to provide a list of "check this" in the error
message on the service side; like "Ensure the OpenVPN 3 SELinux module is
properly installed and enabled".
I'm also pondering in this case if it makes sense to make the service trying
recover. When this happens, I do have a list of all registered object paths
and pointers to the corresponding C++ objects. So it would be possible then
to whack the original D-Bus connection, reconnect and start recovering based
on this existing list. As these objects provides and interface for VPN
clients to modify routing tables and DNS settings and also saves some state
information. I would hate to lose the chance to restore network settings to
the previous state when the VPN connection closes - if the netcfg service
D-Bus connection goes into a limbo in between startup and closing of VPN tunnels.
> To summarise, you need your SELinux policy to give the dbus-daemon the right
> access to any FDs you pass through it. If I remember correctly, I think I have
> seen some patches to do this for other services in the upstream policy.
I will double-check with the SELinux guys ... I doubt I'm the only one hitting
this challenge :)
> Hope that helps,
It sure did, thanks a lot!
--
kind regards,
David Sommerseth
OpenVPN Inc
More information about the dbus
mailing list