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_use(void) {
59 cached_use = is_selinux_enabled() > 0;
67 void mac_selinux_retest(void) {
73 int mac_selinux_init(void) {
77 usec_t before_timestamp, after_timestamp;
78 struct mallinfo before_mallinfo, after_mallinfo;
83 if (!mac_selinux_use())
86 before_mallinfo = mallinfo();
87 before_timestamp = now(CLOCK_MONOTONIC);
89 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
91 log_enforcing("Failed to initialize SELinux context: %m");
92 r = security_getenforce() == 1 ? -errno : 0;
94 char timespan[FORMAT_TIMESPAN_MAX];
97 after_timestamp = now(CLOCK_MONOTONIC);
98 after_mallinfo = mallinfo();
100 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
102 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
103 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
111 void mac_selinux_finish(void) {
117 selabel_close(label_hnd);
122 int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
130 /* if mac_selinux_init() wasn't called before we are a NOOP */
134 r = lstat(path, &st);
136 _cleanup_freecon_ char* fcon = NULL;
138 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
140 /* If there's no label to set, then exit without warning */
141 if (r < 0 && errno == ENOENT)
145 r = lsetfilecon_raw(path, fcon);
147 /* If the FS doesn't support labels, then exit without warning */
148 if (r < 0 && errno == EOPNOTSUPP)
154 /* Ignore ENOENT in some cases */
155 if (ignore_enoent && errno == ENOENT)
158 if (ignore_erofs && errno == EROFS)
161 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
162 if (security_getenforce() == 1)
170 #if 0 /// UNNEDED by elogind
171 int mac_selinux_apply(const char *path, const char *label) {
174 if (!mac_selinux_use())
180 if (setfilecon(path, label) < 0) {
181 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
182 if (security_getenforce() > 0)
189 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
193 _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
194 security_class_t sclass;
199 if (!mac_selinux_use())
202 r = getcon_raw(&mycon);
206 r = getfilecon_raw(exe, &fcon);
210 sclass = string_to_security_class("process");
211 r = security_compute_create_raw(mycon, fcon, sclass, label);
219 int mac_selinux_get_our_label(char **label) {
225 if (!mac_selinux_use())
228 r = getcon_raw(label);
236 int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
240 _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
241 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
242 security_class_t sclass;
243 const char *range = NULL;
245 assert(socket_fd >= 0);
249 if (!mac_selinux_use())
252 r = getcon_raw(&mycon);
256 r = getpeercon_raw(socket_fd, &peercon);
261 /* If there is no context set for next exec let's use context
262 of target executable */
263 r = getfilecon_raw(exe, &fcon);
268 bcon = context_new(mycon);
272 pcon = context_new(peercon);
276 range = context_range_get(pcon);
280 r = context_range_set(bcon, range);
285 mycon = strdup(context_str(bcon));
289 sclass = string_to_security_class("process");
290 r = security_compute_create_raw(mycon, fcon, sclass, label);
298 char* mac_selinux_free(char *label) {
304 if (!mac_selinux_use())
315 int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
318 _cleanup_freecon_ char *filecon = NULL;
326 if (path_is_absolute(path))
327 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
329 _cleanup_free_ char *newpath = NULL;
331 r = path_make_absolute_cwd(path, &newpath);
335 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
339 /* No context specified by the policy? Proceed without setting it. */
343 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
345 if (setfscreatecon_raw(filecon) >= 0)
346 return 0; /* Success! */
348 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
351 if (security_getenforce() > 0)
358 void mac_selinux_create_file_clear(void) {
363 if (!mac_selinux_use())
366 setfscreatecon_raw(NULL);
370 #if 0 /// UNNEEDED by elogind
371 int mac_selinux_create_socket_prepare(const char *label) {
374 if (!mac_selinux_use())
379 if (setsockcreatecon(label) < 0) {
380 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
382 if (security_getenforce() == 1)
390 void mac_selinux_create_socket_clear(void) {
395 if (!mac_selinux_use())
398 setsockcreatecon_raw(NULL);
402 int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
404 /* Binds a socket and label its file system object according to the SELinux policy */
407 _cleanup_freecon_ char *fcon = NULL;
408 const struct sockaddr_un *un;
409 bool context_changed = false;
415 assert(addrlen >= sizeof(sa_family_t));
420 /* Filter out non-local sockets */
421 if (addr->sa_family != AF_UNIX)
424 /* Filter out anonymous sockets */
425 if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
428 /* Filter out abstract namespace sockets */
429 un = (const struct sockaddr_un*) addr;
430 if (un->sun_path[0] == 0)
433 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
435 if (path_is_absolute(path))
436 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
438 _cleanup_free_ char *newpath = NULL;
440 r = path_make_absolute_cwd(path, &newpath);
444 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
448 /* No context specified by the policy? Proceed without setting it */
452 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
453 if (security_getenforce() > 0)
457 if (setfscreatecon_raw(fcon) < 0) {
458 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
459 if (security_getenforce() > 0)
462 context_changed = true;
465 r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
468 setfscreatecon_raw(NULL);
474 if (bind(fd, addr, addrlen) < 0)