summaryrefslogtreecommitdiffstats
path: root/src/core/selinux-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/selinux-setup.c')
-rw-r--r--src/core/selinux-setup.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
new file mode 100644
index 0000000..1ac05b8
--- /dev/null
+++ b/src/core/selinux-setup.c
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include "log.h"
+#include "macro.h"
+#include "selinux-setup.h"
+#include "selinux-util.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "util.h"
+
+#if HAVE_SELINUX
+_printf_(2,3)
+static int null_log(int type, const char *fmt, ...) {
+ return 0;
+}
+#endif
+
+int mac_selinux_setup(bool *loaded_policy) {
+
+#if HAVE_SELINUX
+ int enforce = 0;
+ usec_t before_load, after_load;
+ char *con;
+ int r;
+ static const union selinux_callback cb = {
+ .func_log = null_log,
+ };
+
+ bool initialized = false;
+
+ assert(loaded_policy);
+
+ /* Turn off all of SELinux' own logging, we want to do that */
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ /* Don't load policy in the initrd if we don't appear to have
+ * it. For the real root, we check below if we've already
+ * loaded policy, and return gracefully.
+ */
+ if (in_initrd() && access(selinux_path(), F_OK) < 0)
+ return 0;
+
+ /* Already initialized by somebody else? */
+ r = getcon_raw(&con);
+ /* getcon_raw can return 0, and still give us a NULL pointer if
+ * /proc/self/attr/current is empty. SELinux guarantees this won't
+ * happen, but that file isn't specific to SELinux, and may be provided
+ * by some other arbitrary LSM with different semantics. */
+ if (r == 0 && con) {
+ initialized = !streq(con, "kernel");
+ freecon(con);
+ }
+
+ /* Make sure we have no fds open while loading the policy and
+ * transitioning */
+ log_close();
+
+ /* Now load the policy */
+ before_load = now(CLOCK_MONOTONIC);
+ r = selinux_init_load_policy(&enforce);
+ if (r == 0) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
+ char timespan[FORMAT_TIMESPAN_MAX];
+
+ mac_selinux_retest();
+
+ /* Transition to the new context */
+ r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
+ if (r < 0 || !label) {
+ log_open();
+ log_error("Failed to compute init label, ignoring.");
+ } else {
+ r = setcon_raw(label);
+
+ log_open();
+ if (r < 0)
+ log_error("Failed to transition into init label '%s', ignoring.", label);
+ }
+
+ after_load = now(CLOCK_MONOTONIC);
+
+ log_info("Successfully loaded SELinux policy in %s.",
+ format_timespan(timespan, sizeof(timespan), after_load - before_load, 0));
+
+ *loaded_policy = true;
+
+ } else {
+ log_open();
+
+ if (enforce > 0) {
+ if (!initialized)
+ return log_emergency_errno(SYNTHETIC_ERRNO(EIO),
+ "Failed to load SELinux policy.");
+
+ log_warning("Failed to load new SELinux policy. Continuing with old policy.");
+ } else
+ log_debug("Unable to load SELinux policy. Ignoring.");
+ }
+#endif
+
+ return 0;
+}