2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include <selinux/context.h>
31 #include <selinux/label.h>
32 #include <selinux/selinux.h>
35 #include "alloc-util.h"
38 #include "path-util.h"
39 #include "selinux-util.h"
40 #include "time-util.h"
44 DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
45 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
47 #define _cleanup_security_context_free_ _cleanup_(freeconp)
48 #define _cleanup_context_free_ _cleanup_(context_freep)
50 static int cached_use = -1;
51 static struct selabel_handle *label_hnd = NULL;
53 #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
56 bool mac_selinux_have(void) {
59 cached_use = is_selinux_enabled() > 0;
67 bool mac_selinux_use(void) {
68 if (!mac_selinux_have())
71 /* Never try to configure SELinux features if we aren't
77 #if 0 /// UNNEEDED by elogind
78 void mac_selinux_retest(void) {
85 int mac_selinux_init(const char *prefix) {
89 usec_t before_timestamp, after_timestamp;
90 struct mallinfo before_mallinfo, after_mallinfo;
92 if (!mac_selinux_use())
98 before_mallinfo = mallinfo();
99 before_timestamp = now(CLOCK_MONOTONIC);
102 struct selinux_opt options[] = {
103 { .type = SELABEL_OPT_SUBSET, .value = prefix },
106 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
108 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
111 log_enforcing("Failed to initialize SELinux context: %m");
112 r = security_getenforce() == 1 ? -errno : 0;
114 char timespan[FORMAT_TIMESPAN_MAX];
117 after_timestamp = now(CLOCK_MONOTONIC);
118 after_mallinfo = mallinfo();
120 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
122 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
123 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
131 #if 0 /// UNNEEDED by elogind
132 void mac_selinux_finish(void) {
138 selabel_close(label_hnd);
144 int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
152 /* if mac_selinux_init() wasn't called before we are a NOOP */
156 r = lstat(path, &st);
158 _cleanup_security_context_free_ security_context_t fcon = NULL;
160 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
162 /* If there's no label to set, then exit without warning */
163 if (r < 0 && errno == ENOENT)
167 r = lsetfilecon(path, fcon);
169 /* If the FS doesn't support labels, then exit without warning */
170 if (r < 0 && errno == EOPNOTSUPP)
176 /* Ignore ENOENT in some cases */
177 if (ignore_enoent && errno == ENOENT)
180 if (ignore_erofs && errno == EROFS)
183 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
184 if (security_getenforce() == 1)
192 #if 0 /// UNNEDED by elogind
193 int mac_selinux_apply(const char *path, const char *label) {
196 if (!mac_selinux_use())
202 if (setfilecon(path, (security_context_t) label) < 0) {
203 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
204 if (security_getenforce() > 0)
211 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
215 _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
216 security_class_t sclass;
221 if (!mac_selinux_have())
224 r = getcon_raw(&mycon);
228 r = getfilecon_raw(exe, &fcon);
232 sclass = string_to_security_class("process");
233 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
241 int mac_selinux_get_our_label(char **label) {
247 if (!mac_selinux_have())
250 r = getcon_raw(label);
258 int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
262 _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL;
263 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
264 security_class_t sclass;
265 const char *range = NULL;
267 assert(socket_fd >= 0);
271 if (!mac_selinux_have())
274 r = getcon_raw(&mycon);
278 r = getpeercon(socket_fd, &peercon);
283 /* If there is no context set for next exec let's use context
284 of target executable */
285 r = getfilecon_raw(exe, &fcon);
290 bcon = context_new(mycon);
294 pcon = context_new(peercon);
298 range = context_range_get(pcon);
302 r = context_range_set(bcon, range);
307 mycon = strdup(context_str(bcon));
311 sclass = string_to_security_class("process");
312 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
320 char* mac_selinux_free(char *label) {
326 if (!mac_selinux_have())
330 freecon((security_context_t) label);
337 int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
340 _cleanup_security_context_free_ security_context_t filecon = NULL;
348 if (path_is_absolute(path))
349 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
351 _cleanup_free_ char *newpath = NULL;
353 r = path_make_absolute_cwd(path, &newpath);
357 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
361 /* No context specified by the policy? Proceed without setting it. */
365 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
367 if (setfscreatecon(filecon) >= 0)
368 return 0; /* Success! */
370 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
373 if (security_getenforce() > 0)
380 void mac_selinux_create_file_clear(void) {
385 if (!mac_selinux_use())
388 setfscreatecon(NULL);
392 #if 0 /// UNNEEDED by elogind
393 int mac_selinux_create_socket_prepare(const char *label) {
396 if (!mac_selinux_use())
401 if (setsockcreatecon((security_context_t) label) < 0) {
402 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
404 if (security_getenforce() == 1)
412 void mac_selinux_create_socket_clear(void) {
417 if (!mac_selinux_use())
420 setsockcreatecon(NULL);
424 int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
426 /* Binds a socket and label its file system object according to the SELinux policy */
429 _cleanup_security_context_free_ security_context_t fcon = NULL;
430 const struct sockaddr_un *un;
431 bool context_changed = false;
437 assert(addrlen >= sizeof(sa_family_t));
442 /* Filter out non-local sockets */
443 if (addr->sa_family != AF_UNIX)
446 /* Filter out anonymous sockets */
447 if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
450 /* Filter out abstract namespace sockets */
451 un = (const struct sockaddr_un*) addr;
452 if (un->sun_path[0] == 0)
455 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
457 if (path_is_absolute(path))
458 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
460 _cleanup_free_ char *newpath = NULL;
462 r = path_make_absolute_cwd(path, &newpath);
466 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
470 /* No context specified by the policy? Proceed without setting it */
474 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
475 if (security_getenforce() > 0)
479 if (setfscreatecon(fcon) < 0) {
480 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
481 if (security_getenforce() > 0)
484 context_changed = true;
487 r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
490 setfscreatecon(NULL);
496 if (bind(fd, addr, addrlen) < 0)