On 10/18/2024 7:52 AM, Stephen Smalley wrote:
On Fri, Oct 18, 2024 at 10:44 AM Stephen Smalley
<stephen.smalley.work@xxxxxxxxx> wrote:
On Thu, Oct 17, 2024 at 3:42 PM Matthew Sheets
<masheets@xxxxxxxxxxxxxxxxxxx> wrote:
Hi All,
I am currently working on an update for dbus-broker to trigger reload of
its configuration whenever an SELinux policy load event is seen.
For some background dbus-broker is comprised of two major elements the
launcher and the broker. To trigger a config reload you can either send
a SIGHUP to the launcher or send a message to the launcher over dbus.
In most cases the launcher will be the brokers parent.
Here is a link to my current PR:
https://github.com/bus1/dbus-broker/pull/379
In this current state things work. The broker will see the POLICY_LOAD
event and properly send a SIGHUP to its parent, but as David pointed out
my initial attempt at the fix is no good since there is no guarantee
that the brokers parent will be the launcher.
My attempts at moving the callback registration into the launcher have
been less successful. From what my debugging has told me is that the
selinux_set_callback is going through successfully and the function
pointer is correctly pointing to the callback function I define. But
when I trigger a load_policy my callback function is never called.
I am not familiar with how the callbacks in libselinux work under the
hood so I am unsure about what could be blocking them in this situation.
Caveat: I haven't looked deeply so take this with a grain of salt (or two).
There are generally two ways of discovering when policy has been reloaded:
1. Create and receive notifications on a SELinux netlink socket, or
2. Map the SELinux status page and poll it for updates to the policy seqno.
Internally libselinux has switched to using the status page whenever
the kernel supports it since doing so is more efficient (no syscall
required to read it once you've mapped the page). As an aside, the
status page is also more easily "virtualizable" for SELinux namespaces
since it is per-SELinux state/namespace already (the netlink socket
can also be virtualized via a separate network namespace if/when my
namespace patches land but that requires you to unshare the network
namespace too).
As far as libselinux APIs are concerned for the status page, you can
check for a policy reload or enforcing mode change by calling
selinux_status_updated() at any time after having done an initial
selinux_status_open(). selinux_status_updated() will call any
registered callbacks if enforcing mode or policy was changed, and, it
returns an indicator as to whether anything changed since the last
time it was called.
Or if you choose to use the netlink socket and want to use the
libselinux APIs, you'd call avc_netlink_acquire_fd() to create and
take ownership of the SELinux netlink socket and then poll/select on
it for notifications, and upon receiving them, calling
avc_netlink_check_nb() to process them, including calling your
callbacks.
But you have to do one of those two things in order for your callback
to be invoked. I assume dbus and dbus-broker are already doing one of
them which is why it works for them but not for the launcher.
Also, both avc_has_perm*() and selinux_check_access() internally call
selinux_status_updated() to ensure that they are using the latest
enforcing mode and policy. So anything using those libselinux
functions would get the status update for free.
Just to close the loop. With the info above I was able to trace down
that selinux_status_updated is being called by when the broker calls
selinux_check_access. Thus triggering the callback. The launcher has
no such check access call. Thanks for your help Stephen.