From 7497016418f8c4cdf0f3e3c259d20f65bfa75800 Mon Sep 17 00:00:00 2001 From: Davidson Francis Date: Sat, 2 May 2026 18:02:59 -0300 Subject: [PATCH] SELinuxMeter: improve SELinux detection in constrained environments Up to now, SELinux detection depended on the existence of the '/etc/selinux/config' file, which may not exist in all environments, such as Android. The getenforce tool (libselinux) has a conditional compilation, where the check for the file is skipped in Android environments. However, this check can be removed entirely, and the checks would only have to deal with the existence of /sys/fs/selinux and /sys/fs/selinux/enforce. In Android environments, SELinux has been used since v4.3 [1], and in fact, the 'hasSELinuxMount' function returns successfully; however, when reading from /sys/fs/selinux/enforce, EACCES is returned, indicating the file exists but is not readable from the current SELinux domain. This commit then proposes adding a third 'enabled' state: enabled; mode: unknown This shows that SELinux does indeed exist in the environment in question, but it was not possible to obtain the enforcing level. Other meters, such as 'Uptime', have a similar behavior, also returning '(unknown)' when it is not possible to read the data. Also fixes a latent bug where read/parse failures of /sys/fs/selinux/enforce were silently rendered as permissive; these now correctly map to unknown. [1]: https://source.android.com/docs/security/features/selinux#background Signed-off-by: Davidson Francis --- linux/SELinuxMeter.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/linux/SELinuxMeter.c b/linux/SELinuxMeter.c index 1a130855a..7d8850dcc 100644 --- a/linux/SELinuxMeter.c +++ b/linux/SELinuxMeter.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include "CRT.h" +#include #include #include #include @@ -27,8 +28,19 @@ static const int SELinuxMeter_attributes[] = { METER_TEXT, }; -static bool enabled = false; -static bool enforcing = false; +typedef enum { + SELINUX_PERMISSIVE, + SELINUX_ENFORCING, + SELINUX_UNKNOWN, + SELINUX_DISABLED, +} EnforcingMode; + +static const char* const enforcingText[] = { + [SELINUX_PERMISSIVE] = "enabled; mode: permissive", + [SELINUX_ENFORCING] = "enabled; mode: enforcing", + [SELINUX_UNKNOWN] = "enabled; mode: unknown", + [SELINUX_DISABLED] = "disabled", +}; static bool hasSELinuxMount(void) { struct statfs sfbuf; @@ -51,32 +63,28 @@ static bool hasSELinuxMount(void) { } static bool isSelinuxEnabled(void) { - return hasSELinuxMount() && (0 == access("/etc/selinux/config", F_OK)); + return hasSELinuxMount(); } -static bool isSelinuxEnforcing(void) { - if (!enabled) { - return false; - } +static EnforcingMode getSelinuxEnforcing(void) { + if (!isSelinuxEnabled()) + return SELINUX_DISABLED; char buf[20]; ssize_t r = Compat_readfile("/sys/fs/selinux/enforce", buf, sizeof(buf)); if (r < 0) - return false; + return (r == -ENOENT) ? SELINUX_DISABLED : SELINUX_UNKNOWN; int enforce = 0; - if (sscanf(buf, "%d", &enforce) != 1) { - return false; - } + if (sscanf(buf, "%d", &enforce) != 1) + return SELINUX_UNKNOWN; - return !!enforce; + return enforce ? SELINUX_ENFORCING : SELINUX_PERMISSIVE; } static void SELinuxMeter_updateValues(Meter* this) { - enabled = isSelinuxEnabled(); - enforcing = isSelinuxEnforcing(); - - xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s%s", enabled ? "enabled" : "disabled", enabled ? (enforcing ? "; mode: enforcing" : "; mode: permissive") : ""); + EnforcingMode enforcing = getSelinuxEnforcing(); + xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s", enforcingText[enforcing]); } const MeterClass SELinuxMeter_class = {