From 0b3325e79eb98f2e5bc19a1b0efd99e693b31a99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jul 2011 23:52:23 +0200 Subject: [PATCH] selinux: use setcon() instead of reexec to apply selinux policy --- src/main.c | 46 +++++++++++++++++++++----------- src/mount-setup.c | 15 +++++++++-- src/mount-setup.h | 2 +- src/selinux-setup.c | 65 +++++++++++++++++++++++++++++---------------- src/selinux-setup.h | 4 ++- 5 files changed, 89 insertions(+), 43 deletions(-) diff --git a/src/main.c b/src/main.c index f8682d24..40d03ca7 100644 --- a/src/main.c +++ b/src/main.c @@ -1020,6 +1020,9 @@ int main(int argc, char *argv[]) { const char *shutdown_verb = NULL; dual_timestamp initrd_timestamp = { 0ULL, 0ULL }; char systemd[] = "systemd"; + bool is_reexec = false; + int j; + bool loaded_policy = false; #ifdef HAVE_SYSV_COMPAT if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { @@ -1033,6 +1036,16 @@ int main(int argc, char *argv[]) { } #endif + /* Determine if this is a reexecution or normal bootup. We do + * the full command line parsing much later, so let's just + * have a quick peek here. */ + + for (j = 1; j < argc; j++) + if (streq(argv[j], "--deserialize")) { + break; + is_reexec = true; + } + /* If we get started via the /sbin/init symlink then we are called 'init'. After a subsequent reexecution we are then called 'systemd'. That is confusing, hence let's call us @@ -1050,25 +1063,26 @@ int main(int argc, char *argv[]) { if (getpid() == 1) { arg_running_as = MANAGER_SYSTEM; log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_SYSLOG_OR_KMSG); - log_open(); - /* This might actually not return, but cause a - * reexecution */ - if (selinux_setup(argv) < 0) - goto finish; + if (!is_reexec) + if (selinux_setup(&loaded_policy) < 0) + goto finish; + + log_open(); if (label_init() < 0) goto finish; - if (hwclock_is_localtime() > 0) { - int err, min; + if (!is_reexec) + if (hwclock_is_localtime() > 0) { + int min; - err = hwclock_apply_localtime_delta(&min); - if (err < 0) - log_error("Failed to apply local time delta: %s", strerror(-err)); - else - log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); - } + r = hwclock_apply_localtime_delta(&min); + if (r < 0) + log_error("Failed to apply local time delta, ignoring: %s", strerror(-r)); + else + log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); + } } else { arg_running_as = MANAGER_USER; @@ -1082,7 +1096,7 @@ int main(int argc, char *argv[]) { /* Mount /proc, /sys and friends, so that /proc/cmdline and * /proc/$PID/fd is available. */ if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS")) - if (mount_setup() < 0) + if (mount_setup(loaded_policy) < 0) goto finish; /* Reset all signal handlers. */ @@ -1179,7 +1193,7 @@ int main(int argc, char *argv[]) { /* Reset the console, but only if this is really init and we * are freshly booted */ if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) { - console_setup(getpid() == 1 && !serialization); + console_setup(getpid() == 1 && !is_reexec); make_null_stdio(); } @@ -1194,7 +1208,7 @@ int main(int argc, char *argv[]) { log_full(arg_running_as == MANAGER_SYSTEM ? LOG_INFO : LOG_DEBUG, PACKAGE_STRING " running in %s mode. (" SYSTEMD_FEATURES "; " DISTRIBUTION ")", manager_running_as_to_string(arg_running_as)); - if (arg_running_as == MANAGER_SYSTEM && !serialization) { + if (arg_running_as == MANAGER_SYSTEM && !is_reexec) { locale_setup(); if (arg_show_status || plymouth_running()) diff --git a/src/mount-setup.c b/src/mount-setup.c index f236ab74..29069893 100644 --- a/src/mount-setup.c +++ b/src/mount-setup.c @@ -226,7 +226,7 @@ static int nftw_cb( return 0; }; -int mount_setup(void) { +int mount_setup(bool loaded_policy) { const char symlinks[] = "/proc/kcore\0" "/dev/core\0" @@ -247,9 +247,20 @@ int mount_setup(void) { * the appropriate labels, after mounting. The other virtual * API file systems like /sys and /proc do not need that, they * use the same label for all their files. */ - if (unlink("/dev/.systemd-relabel-run-dev") >= 0) { + if (loaded_policy) { + usec_t before_relabel, after_relabel; + char timespan[FORMAT_TIMESPAN_MAX]; + + before_relabel = now(CLOCK_MONOTONIC); + nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS); nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS); + + after_relabel = now(CLOCK_MONOTONIC); + + log_info("Relabelled /dev and /run in %s.", + format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel)); + } /* Create a few default symlinks, which are normally created diff --git a/src/mount-setup.h b/src/mount-setup.h index 150ec408..f05ee317 100644 --- a/src/mount-setup.h +++ b/src/mount-setup.h @@ -24,7 +24,7 @@ #include -int mount_setup(void); +int mount_setup(bool loaded_policy); bool mount_point_is_api(const char *path); bool mount_point_ignore(const char *path); diff --git a/src/selinux-setup.c b/src/selinux-setup.c index 793cb034..fdc31604 100644 --- a/src/selinux-setup.c +++ b/src/selinux-setup.c @@ -33,15 +33,21 @@ #include "macro.h" #include "util.h" #include "log.h" +#include "label.h" + +int selinux_setup(bool *loaded_policy) { -int selinux_setup(char *const argv[]) { #ifdef HAVE_SELINUX int enforce = 0; - usec_t n; + usec_t before_load, after_load; security_context_t con; + int r; + + assert(loaded_policy); - /* Already initialized? */ - if (getcon_raw(&con) == 0) { + /* Already initialized by somebody else? */ + r = getcon_raw(&con); + if (r == 0) { bool initialized; initialized = !streq(con, "kernel"); @@ -51,33 +57,46 @@ int selinux_setup(char *const argv[]) { return 0; } - /* Before we load the policy we create a flag file to ensure - * that after the reexec we iterate through /run and /dev to - * relabel things. */ - touch("/dev/.systemd-relabel-run-dev"); + /* Make sure we have no fds open while loading the policy and + * transitioning */ + log_close(); - n = now(CLOCK_MONOTONIC); - if (selinux_init_load_policy(&enforce) == 0) { - char buf[FORMAT_TIMESPAN_MAX]; + /* Now load the policy */ + before_load = now(CLOCK_MONOTONIC); + r = selinux_init_load_policy(&enforce); - n = now(CLOCK_MONOTONIC) - n; - log_info("Successfully loaded SELinux policy in %s, reexecuting.", - format_timespan(buf, sizeof(buf), n)); + if (r == 0) { + char timespan[FORMAT_TIMESPAN_MAX]; + char *label; - /* FIXME: Ideally we'd just call setcon() here instead - * of having to reexecute ourselves here. */ + /* Transition to the new context */ + r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); + if (r < 0) { + log_open(); + log_error("Failed to compute init label, ignoring."); + } else { + r = setcon(label); - execv(SYSTEMD_BINARY_PATH, argv); - log_error("Failed to reexecute: %m"); - return -errno; + log_open(); + if (r < 0) + log_error("Failed to transition into init label '%s', ignoring.", label); - } else { - unlink("/dev/.systemd-relabel-run-dev"); + label_free(label); + } + + after_load = now(CLOCK_MONOTONIC); + log_info("Successfully loaded SELinux policy in %s.", + format_timespan(timespan, sizeof(timespan), after_load - before_load)); + + *loaded_policy = true; + + } else { if (enforce > 0) { - log_full(LOG_ERR, "Failed to load SELinux policy."); + log_error("Failed to load SELinux policy."); return -EIO; - } + } else + log_debug("Unable to load SELinux policy."); } #endif diff --git a/src/selinux-setup.h b/src/selinux-setup.h index 53dbb65f..6b8fe00b 100644 --- a/src/selinux-setup.h +++ b/src/selinux-setup.h @@ -22,6 +22,8 @@ along with systemd; If not, see . ***/ -int selinux_setup(char *const argv[]); +#include + +int selinux_setup(bool *loaded_policy); #endif -- 2.39.5