1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include <selinux/context.h>
32 #include <selinux/label.h>
33 #include <selinux/selinux.h>
36 #include "alloc-util.h"
39 #include "path-util.h"
40 #include "selinux-util.h"
41 #include "time-util.h"
45 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
46 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
48 #define _cleanup_freecon_ _cleanup_(freeconp)
49 #define _cleanup_context_free_ _cleanup_(context_freep)
51 static int cached_use = -1;
52 static struct selabel_handle *label_hnd = NULL;
54 #define log_enforcing(...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, errno, __VA_ARGS__)
57 bool mac_selinux_use(void) {
60 cached_use = is_selinux_enabled() > 0;
68 void mac_selinux_retest(void) {
74 int mac_selinux_init(void) {
78 usec_t before_timestamp, after_timestamp;
79 struct mallinfo before_mallinfo, after_mallinfo;
84 if (!mac_selinux_use())
87 before_mallinfo = mallinfo();
88 before_timestamp = now(CLOCK_MONOTONIC);
90 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
92 log_enforcing("Failed to initialize SELinux context: %m");
93 r = security_getenforce() == 1 ? -errno : 0;
95 char timespan[FORMAT_TIMESPAN_MAX];
98 after_timestamp = now(CLOCK_MONOTONIC);
99 after_mallinfo = mallinfo();
101 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
103 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
104 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
112 void mac_selinux_finish(void) {
118 selabel_close(label_hnd);
123 int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
131 /* if mac_selinux_init() wasn't called before we are a NOOP */
135 r = lstat(path, &st);
137 _cleanup_freecon_ char* fcon = NULL;
139 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
141 /* If there's no label to set, then exit without warning */
142 if (r < 0 && errno == ENOENT)
146 r = lsetfilecon_raw(path, fcon);
148 /* If the FS doesn't support labels, then exit without warning */
149 if (r < 0 && errno == EOPNOTSUPP)
155 /* Ignore ENOENT in some cases */
156 if (ignore_enoent && errno == ENOENT)
159 if (ignore_erofs && errno == EROFS)
162 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
163 if (security_getenforce() == 1)
171 #if 0 /// UNNEDED by elogind
172 int mac_selinux_apply(const char *path, const char *label) {
175 if (!mac_selinux_use())
181 if (setfilecon(path, label) < 0) {
182 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
183 if (security_getenforce() > 0)
190 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
194 _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
195 security_class_t sclass;
200 if (!mac_selinux_use())
203 r = getcon_raw(&mycon);
207 r = getfilecon_raw(exe, &fcon);
211 sclass = string_to_security_class("process");
212 r = security_compute_create_raw(mycon, fcon, sclass, label);
220 int mac_selinux_get_our_label(char **label) {
226 if (!mac_selinux_use())
229 r = getcon_raw(label);
237 int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
241 _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
242 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
243 security_class_t sclass;
244 const char *range = NULL;
246 assert(socket_fd >= 0);
250 if (!mac_selinux_use())
253 r = getcon_raw(&mycon);
257 r = getpeercon_raw(socket_fd, &peercon);
262 /* If there is no context set for next exec let's use context
263 of target executable */
264 r = getfilecon_raw(exe, &fcon);
269 bcon = context_new(mycon);
273 pcon = context_new(peercon);
277 range = context_range_get(pcon);
281 r = context_range_set(bcon, range);
286 mycon = strdup(context_str(bcon));
290 sclass = string_to_security_class("process");
291 r = security_compute_create_raw(mycon, fcon, sclass, label);
299 char* mac_selinux_free(char *label) {
305 if (!mac_selinux_use())
316 int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
319 _cleanup_freecon_ char *filecon = NULL;
327 if (path_is_absolute(path))
328 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
330 _cleanup_free_ char *newpath = NULL;
332 r = path_make_absolute_cwd(path, &newpath);
336 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
340 /* No context specified by the policy? Proceed without setting it. */
344 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
346 if (setfscreatecon_raw(filecon) >= 0)
347 return 0; /* Success! */
349 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
352 if (security_getenforce() > 0)
359 void mac_selinux_create_file_clear(void) {
364 if (!mac_selinux_use())
367 setfscreatecon_raw(NULL);
371 #if 0 /// UNNEEDED by elogind
372 int mac_selinux_create_socket_prepare(const char *label) {
375 if (!mac_selinux_use())
380 if (setsockcreatecon(label) < 0) {
381 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
383 if (security_getenforce() == 1)
391 void mac_selinux_create_socket_clear(void) {
396 if (!mac_selinux_use())
399 setsockcreatecon_raw(NULL);
403 int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
405 /* Binds a socket and label its file system object according to the SELinux policy */
408 _cleanup_freecon_ char *fcon = NULL;
409 const struct sockaddr_un *un;
410 bool context_changed = false;
416 assert(addrlen >= sizeof(sa_family_t));
421 /* Filter out non-local sockets */
422 if (addr->sa_family != AF_UNIX)
425 /* Filter out anonymous sockets */
426 if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
429 /* Filter out abstract namespace sockets */
430 un = (const struct sockaddr_un*) addr;
431 if (un->sun_path[0] == 0)
434 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
436 if (path_is_absolute(path))
437 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
439 _cleanup_free_ char *newpath = NULL;
441 r = path_make_absolute_cwd(path, &newpath);
445 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
449 /* No context specified by the policy? Proceed without setting it */
453 log_enforcing("Failed to determine SELinux security context for %s: %m", path);
454 if (security_getenforce() > 0)
458 if (setfscreatecon_raw(fcon) < 0) {
459 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
460 if (security_getenforce() > 0)
463 context_changed = true;
466 r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
469 setfscreatecon_raw(NULL);
475 if (bind(fd, addr, addrlen) < 0)