1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 
7 #if HAVE_SELINUX
8 #include <selinux/selinux.h>
9 #endif
10 
11 #include "log.h"
12 #include "macro.h"
13 #include "selinux-setup.h"
14 #include "selinux-util.h"
15 #include "string-util.h"
16 #include "time-util.h"
17 #include "util.h"
18 
19 #if HAVE_SELINUX
20 _printf_(2,3)
null_log(int type,const char * fmt,...)21 static int null_log(int type, const char *fmt, ...) {
22         return 0;
23 }
24 #endif
25 
mac_selinux_setup(bool * loaded_policy)26 int mac_selinux_setup(bool *loaded_policy) {
27 
28 #if HAVE_SELINUX
29         int enforce = 0;
30         usec_t before_load, after_load;
31         char *con;
32         int r;
33         bool initialized = false;
34 
35         assert(loaded_policy);
36 
37         /* Turn off all of SELinux' own logging, we want to do that */
38         selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = null_log });
39 
40         /* Don't load policy in the initrd if we don't appear to have
41          * it.  For the real root, we check below if we've already
42          * loaded policy, and return gracefully.
43          */
44         if (in_initrd() && access(selinux_path(), F_OK) < 0)
45                 return 0;
46 
47         /* Already initialized by somebody else? */
48         r = getcon_raw(&con);
49         /* getcon_raw can return 0, and still give us a NULL pointer if
50          * /proc/self/attr/current is empty. SELinux guarantees this won't
51          * happen, but that file isn't specific to SELinux, and may be provided
52          * by some other arbitrary LSM with different semantics. */
53         if (r == 0 && con) {
54                 initialized = !streq(con, "kernel");
55                 freecon(con);
56         }
57 
58         /* Make sure we have no fds open while loading the policy and
59          * transitioning */
60         log_close();
61 
62         /* Now load the policy */
63         before_load = now(CLOCK_MONOTONIC);
64         r = selinux_init_load_policy(&enforce);
65         if (r == 0) {
66                 _cleanup_(mac_selinux_freep) char *label = NULL;
67 
68                 mac_selinux_retest();
69 
70                 /* Transition to the new context */
71                 r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
72                 if (r < 0 || !label) {
73                         log_open();
74                         log_error("Failed to compute init label, ignoring.");
75                 } else {
76                         r = setcon_raw(label);
77 
78                         log_open();
79                         if (r < 0)
80                                 log_error("Failed to transition into init label '%s', ignoring.", label);
81                 }
82 
83                 after_load = now(CLOCK_MONOTONIC);
84 
85                 log_info("Successfully loaded SELinux policy in %s.",
86                          FORMAT_TIMESPAN(after_load - before_load, 0));
87 
88                 *loaded_policy = true;
89 
90         } else {
91                 log_open();
92 
93                 if (enforce > 0) {
94                         if (!initialized)
95                                 return log_emergency_errno(SYNTHETIC_ERRNO(EIO),
96                                                            "Failed to load SELinux policy.");
97 
98                         log_warning("Failed to load new SELinux policy. Continuing with old policy.");
99                 } else
100                         log_debug("Unable to load SELinux policy. Ignoring.");
101         }
102 #endif
103 
104         return 0;
105 }
106