]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <unistd.h> | |
4 | ||
5 | #include "sd-messages.h" | |
6 | ||
7 | #include "errno-util.h" | |
8 | #include "initrd-util.h" | |
9 | #include "log.h" | |
10 | #include "selinux-setup.h" | |
11 | #include "selinux-util.h" | |
12 | #include "string-util.h" | |
13 | #include "time-util.h" | |
14 | ||
15 | int mac_selinux_setup(bool *loaded_policy) { | |
16 | assert(loaded_policy); | |
17 | ||
18 | #if HAVE_SELINUX | |
19 | int r; | |
20 | ||
21 | mac_selinux_disable_logging(); | |
22 | ||
23 | /* Don't load policy in the initrd if we don't appear to have it. For the real root, we check below | |
24 | * if we've already loaded policy, and return gracefully. */ | |
25 | if (in_initrd() && access(selinux_path(), F_OK) < 0) { | |
26 | if (errno != ENOENT) | |
27 | log_warning_errno(errno, "Unable to check if %s exists, assuming it does not: %m", selinux_path()); | |
28 | ||
29 | return 0; | |
30 | } | |
31 | ||
32 | bool initialized = false; | |
33 | ||
34 | /* Already initialized by somebody else? | |
35 | * | |
36 | * Note: getcon_raw() can return 0, and still give us a NULL pointer if /proc/self/attr/current is | |
37 | * empty. SELinux guarantees this won't happen, but that file isn't specific to SELinux, and may be | |
38 | * provided by some other arbitrary LSM with different semantics. */ | |
39 | _cleanup_freecon_ char *con = NULL; | |
40 | if (getcon_raw(&con) < 0) | |
41 | log_debug_errno(errno, "getcon_raw() failed, assuming SELinux is not initialized: %m"); | |
42 | else if (con) { | |
43 | initialized = !streq(con, "kernel"); | |
44 | log_debug("SELinux already initialized: %s", yes_no(initialized)); | |
45 | } | |
46 | ||
47 | /* Make sure we have no fds open while loading the policy and transitioning */ | |
48 | log_close(); | |
49 | ||
50 | /* Now load the policy */ | |
51 | usec_t before_load = now(CLOCK_MONOTONIC); | |
52 | int enforce = 0; | |
53 | if (selinux_init_load_policy(&enforce) == 0) { /* NB: Apparently doesn't set useful errno! */ | |
54 | mac_selinux_retest(); | |
55 | ||
56 | /* Transition to the new context */ | |
57 | _cleanup_freecon_ char *label = NULL; | |
58 | r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); | |
59 | if (r < 0) { | |
60 | log_open(); | |
61 | log_warning_errno(r, "Failed to compute init label, ignoring: %m"); | |
62 | } else { | |
63 | r = RET_NERRNO(setcon_raw(label)); | |
64 | log_open(); | |
65 | if (r < 0) | |
66 | log_warning_errno(r, "Failed to transition into init label '%s', ignoring: %m", label); | |
67 | else | |
68 | log_debug("Successfully switched to calculated init label '%s'.", label); | |
69 | } | |
70 | ||
71 | usec_t after_load = now(CLOCK_MONOTONIC); | |
72 | log_info("Successfully loaded SELinux policy in %s.", | |
73 | FORMAT_TIMESPAN(after_load - before_load, 0)); | |
74 | ||
75 | *loaded_policy = true; | |
76 | } else { | |
77 | log_open(); | |
78 | ||
79 | if (enforce > 0) { | |
80 | if (!initialized) | |
81 | return log_struct_errno(LOG_EMERG, SYNTHETIC_ERRNO(EIO), | |
82 | LOG_MESSAGE("Failed to load SELinux policy :%m"), | |
83 | LOG_MESSAGE_ID(SD_MESSAGE_SELINUX_FAILED_STR)); | |
84 | ||
85 | log_notice("Failed to load new SELinux policy. Continuing with old policy."); | |
86 | } else | |
87 | log_debug("Unable to load SELinux policy. Ignoring."); | |
88 | } | |
89 | #endif | |
90 | ||
91 | return 0; | |
92 | } |