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(char*, freecon);
45 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
47 #define _cleanup_freecon_ _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_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, errno, __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 void mac_selinux_retest(void) {
83 int mac_selinux_init(void) {
87 usec_t before_timestamp, after_timestamp;
88 struct mallinfo before_mallinfo, after_mallinfo;
93 if (!mac_selinux_use())
96 before_mallinfo = mallinfo();
97 before_timestamp = now(CLOCK_MONOTONIC);
99 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
101 log_enforcing("Failed to initialize SELinux context: %m");
102 r = security_getenforce() == 1 ? -errno : 0;
104 char timespan[FORMAT_TIMESPAN_MAX];
107 after_timestamp = now(CLOCK_MONOTONIC);
108 after_mallinfo = mallinfo();
110 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
112 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
113 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
121 void mac_selinux_finish(void) {
127 selabel_close(label_hnd);
132 int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
140 /* if mac_selinux_init() wasn't called before we are a NOOP */
144 r = lstat(path, &st);
146 _cleanup_freecon_ char* fcon = NULL;
148 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
150 /* If there's no label to set, then exit without warning */
151 if (r < 0 && errno == ENOENT)
155 r = lsetfilecon_raw(path, fcon);
157 /* If the FS doesn't support labels, then exit without warning */
158 if (r < 0 && errno == EOPNOTSUPP)
164 /* Ignore ENOENT in some cases */
165 if (ignore_enoent && errno == ENOENT)
168 if (ignore_erofs && errno == EROFS)
171 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
172 if (security_getenforce() == 1)
180 #if 0 /// UNNEDED by elogind
181 int mac_selinux_apply(const char *path, const char *label) {
184 if (!mac_selinux_use())
190 if (setfilecon(path, label) < 0) {
191 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
192 if (security_getenforce() > 0)
199 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
203 _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
204 security_class_t sclass;
209 if (!mac_selinux_have())
212 r = getcon_raw(&mycon);
216 r = getfilecon_raw(exe, &fcon);
220 sclass = string_to_security_class("process");
221 r = security_compute_create_raw(mycon, fcon, sclass, label);
229 int mac_selinux_get_our_label(char **label) {
235 if (!mac_selinux_have())
238 r = getcon_raw(label);
246 int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
250 _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
251 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
252 security_class_t sclass;
253 const char *range = NULL;
255 assert(socket_fd >= 0);
259 if (!mac_selinux_have())
262 r = getcon_raw(&mycon);
266 r = getpeercon_raw(socket_fd, &peercon);
271 /* If there is no context set for next exec let's use context
272 of target executable */
273 r = getfilecon_raw(exe, &fcon);
278 bcon = context_new(mycon);
282 pcon = context_new(peercon);
286 range = context_range_get(pcon);
290 r = context_range_set(bcon, range);
295 mycon = strdup(context_str(bcon));
299 sclass = string_to_security_class("process");
300 r = security_compute_create_raw(mycon, fcon, sclass, label);
308 char* mac_selinux_free(char *label) {
314 if (!mac_selinux_have())
325 int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
328 _cleanup_freecon_ char *filecon = NULL;
336 if (path_is_absolute(path))
337 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
339 _cleanup_free_ char *newpath = NULL;
341 r = path_make_absolute_cwd(path, &newpath);
345 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
349 /* No context specified by the policy? Proceed without setting it. */
353 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
355 if (setfscreatecon_raw(filecon) >= 0)
356 return 0; /* Success! */
358 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
361 if (security_getenforce() > 0)
368 void mac_selinux_create_file_clear(void) {
373 if (!mac_selinux_use())
376 setfscreatecon_raw(NULL);
380 #if 0 /// UNNEEDED by elogind
381 int mac_selinux_create_socket_prepare(const char *label) {
384 if (!mac_selinux_use())
389 if (setsockcreatecon(label) < 0) {
390 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
392 if (security_getenforce() == 1)
400 void mac_selinux_create_socket_clear(void) {
405 if (!mac_selinux_use())
408 setsockcreatecon_raw(NULL);
412 int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
414 /* Binds a socket and label its file system object according to the SELinux policy */
417 _cleanup_freecon_ char *fcon = NULL;
418 const struct sockaddr_un *un;
419 bool context_changed = false;
425 assert(addrlen >= sizeof(sa_family_t));
430 /* Filter out non-local sockets */
431 if (addr->sa_family != AF_UNIX)
434 /* Filter out anonymous sockets */
435 if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
438 /* Filter out abstract namespace sockets */
439 un = (const struct sockaddr_un*) addr;
440 if (un->sun_path[0] == 0)
443 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
445 if (path_is_absolute(path))
446 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
448 _cleanup_free_ char *newpath = NULL;
450 r = path_make_absolute_cwd(path, &newpath);
454 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
458 /* No context specified by the policy? Proceed without setting it */
462 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
463 if (security_getenforce() > 0)
467 if (setfscreatecon_raw(fcon) < 0) {
468 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
469 if (security_getenforce() > 0)
472 context_changed = true;
475 r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
478 setfscreatecon_raw(NULL);
484 if (bind(fd, addr, addrlen) < 0)