Am Di., 11. Aug. 2020 um 14:14 Uhr schrieb Stephen Smalley <stephen.smalley.work@xxxxxxxxx>: > > On Thu, Aug 6, 2020 at 8:05 AM Stephen Smalley > <stephen.smalley.work@xxxxxxxxx> wrote: > > > > On 8/5/20 3:43 PM, Mike Palmiotto wrote: > > > > > Commit bc2a8f418e3b ("libselinux: add selinux_status_* interfaces for > > > /selinux/status") introduced the sestatus mechanism, which allows for > > > mmap()'ing of the kernel status page as a replacement for avc_netlink. > > > > > > The mechanism was initially intended for userspace object managers that > > > were calculating access decisions within their application and did not > > > rely on the libselinux AVC implementation. In order to properly make use > > > of sestatus within avc_has_perm(), the status mechanism needs to > > > properly set avc internals during status events; else, avc_enforcing is > > > never updated upon sestatus changes. > > > > > > This commit gets rid of the default avc_netlink_open() in > > > avc_init_internal(), replacing it with selinux_status_open(). In the > > > event that the kernel status page cannot be mapped, the netlink fallback > > > will be used. By default, avc_has_perm_noaudit() and > > > selinux_check_access() will now attempt to read the kernel status page, > > > which removes a system call from two critical code paths. > > > > > > Since the AVC thread create/stop callbacks were intended to avoid a > > > system call in the critical code path, they no longer need to be created > > > by default. In the event that the kernel status page is successfully > > > mapped, threads will not be created. Threads will still be > > > created/stopped for the sestatus fallback codepaths. > > > > > > Userspace object managers that still need a netlink socket can call > > > avc_netlink_acquire_fd() to open and/or obtain one. > > > > > > Update the manpage to reflect the new avc_netlink_acquire_fd() > > > functionality. > > > > > > Signed-off-by: Mike Palmiotto <mike.palmiotto@xxxxxxxxxxxxxxx> > > > > Acked-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx> > > Applied. I think in `libselinux/src/sestatus.c` the static variable `last_policyload` does not get updated during `selinux_status_open()`. This leads to policyload-callbacks getting called if the first change to the status page is an enforcing change. Reproducible with trailed test binary: Running the binary and during its runtime changing the enforcing status via setenforce 0/1 triggers the policyload callback: > ./test_selinux_status & [1] 4091 selinux_status_updated returned 0 selinux_status_updated returned 0 > setenforce 0 selinux_status_updated returned 0 uavc: received setenforce notice (enforcing=0) setenforce_cb(0) uavc: received policyload notice (seqno=4) policyload_cb(4) selinux_status_updated returned 1 selinux_status_updated returned 0 > setenforce 1 selinux_status_updated returned 0 uavc: received setenforce notice (enforcing=1) setenforce_cb(1) selinux_status_updated returned 1 selinux_status_updated returned 0 selinux_status_updated returned 0 selinux_status_updated returned 0 [1]+ Done ./test_selinux_status <<<< test binary >>>> #include <stdio.h> #include <unistd.h> #include <selinux/avc.h> int policyload_cb(int seqno) { printf("policyload_cb(%d)\n", seqno); return 0; } int setenforce_cb(int enforcing) { printf("setenforce_cb(%d)\n", enforcing); return 0; } int main(void) { int r; r = selinux_status_open(0); if (r < 0) { fprintf(stderr, "Failed to open SELinux status page: %m\n"); return EXIT_FAILURE; } selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) policyload_cb); selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_cb); for (int i = 0; i < 10; ++i) { sleep(1); r = selinux_status_updated(); printf("selinux_status_updated returned %d\n", r); } selinux_status_close(); return EXIT_SUCCESS; }