1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/socket.h>
27 #include <sys/types.h>
30 #include <sys/xattr.h>
32 #include <selinux/selinux.h>
33 #include <selinux/label.h>
34 #include <selinux/context.h>
40 #include "path-util.h"
41 #include "selinux-util.h"
42 #include "smack-util.h"
45 DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
46 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
48 #define _cleanup_security_context_free_ _cleanup_(freeconp)
49 #define _cleanup_context_free_ _cleanup_(context_freep)
51 static struct selabel_handle *label_hnd = NULL;
54 static int smack_relabel_in_dev(const char *path) {
62 * Path must be in /dev and must exist
64 if (!path_startswith(path, "/dev"))
72 * Label directories and character devices "*".
74 * Don't change anything else.
76 if (S_ISDIR(sb.st_mode))
77 label = SMACK_STAR_LABEL;
78 else if (S_ISLNK(sb.st_mode))
79 label = SMACK_FLOOR_LABEL;
80 else if (S_ISCHR(sb.st_mode))
81 label = SMACK_STAR_LABEL;
85 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
87 log_error("Smack relabeling \"%s\" %m", path);
95 int label_init(const char *prefix) {
99 usec_t before_timestamp, after_timestamp;
100 struct mallinfo before_mallinfo, after_mallinfo;
108 before_mallinfo = mallinfo();
109 before_timestamp = now(CLOCK_MONOTONIC);
112 struct selinux_opt options[] = {
113 { .type = SELABEL_OPT_SUBSET, .value = prefix },
116 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
118 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
121 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
122 "Failed to initialize SELinux context: %m");
123 r = security_getenforce() == 1 ? -errno : 0;
125 char timespan[FORMAT_TIMESPAN_MAX];
128 after_timestamp = now(CLOCK_MONOTONIC);
129 after_mallinfo = mallinfo();
131 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
133 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
134 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
142 static int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs) {
147 security_context_t fcon;
152 r = lstat(path, &st);
154 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
156 /* If there's no label to set, then exit without warning */
157 if (r < 0 && errno == ENOENT)
161 r = lsetfilecon(path, fcon);
164 /* If the FS doesn't support labels, then exit without warning */
165 if (r < 0 && errno == ENOTSUP)
171 /* Ignore ENOENT in some cases */
172 if (ignore_enoent && errno == ENOENT)
175 if (ignore_erofs && errno == EROFS)
178 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
179 "Unable to fix label of %s: %m", path);
180 r = security_getenforce() == 1 ? -errno : 0;
187 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
191 r = label_fix_selinux(path, ignore_enoent, ignore_erofs);
197 r = smack_relabel_in_dev(path);
205 void label_finish(void) {
212 selabel_close(label_hnd);
216 int label_get_create_label_from_exe(const char *exe, char **label) {
221 security_context_t mycon = NULL, fcon = NULL;
222 security_class_t sclass;
224 if (!use_selinux()) {
233 r = getfilecon(exe, &fcon);
237 sclass = string_to_security_class("process");
238 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
240 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
243 if (r < 0 && security_getenforce() == 1)
253 int label_get_our_label(char **label) {
269 int label_get_child_mls_label(int socket_fd, const char *exe, char **label) {
274 _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL, ret = NULL;
275 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
276 security_class_t sclass;
278 const char *range = NULL;
280 assert(socket_fd >= 0);
290 r = getpeercon(socket_fd, &peercon);
296 r = getexeccon(&fcon);
303 /* If there is no context set for next exec let's use context
304 of target executable */
305 r = getfilecon(exe, &fcon);
312 bcon = context_new(mycon);
318 pcon = context_new(peercon);
324 range = context_range_get(pcon);
330 r = context_range_set(bcon, range);
337 mycon = strdup(context_str(bcon));
343 sclass = string_to_security_class("process");
344 r = security_compute_create(mycon, fcon, sclass, &ret);
355 if (r < 0 && security_getenforce() == 1)
361 int label_context_set(const char *path, mode_t mode) {
365 security_context_t filecon = NULL;
367 if (!use_selinux() || !label_hnd)
370 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
371 if (r < 0 && errno != ENOENT)
374 r = setfscreatecon(filecon);
376 log_error("Failed to set SELinux file context on %s: %m", path);
383 if (r < 0 && security_getenforce() == 0)
390 int label_socket_set(const char *label) {
396 if (setsockcreatecon((security_context_t) label) < 0) {
397 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
398 "Failed to set SELinux context (%s) on socket: %m", label);
400 if (security_getenforce() == 1)
408 void label_context_clear(void) {
416 setfscreatecon(NULL);
420 void label_socket_clear(void) {
428 setsockcreatecon(NULL);
432 void label_free(const char *label) {
438 freecon((security_context_t) label);
442 static int label_mkdir_selinux(const char *path, mode_t mode) {
446 /* Creates a directory and labels it according to the SELinux policy */
447 security_context_t fcon = NULL;
452 if (path_is_absolute(path))
453 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
455 _cleanup_free_ char *newpath;
457 newpath = path_make_absolute_cwd(path);
461 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
465 r = setfscreatecon(fcon);
467 if (r < 0 && errno != ENOENT) {
468 log_error("Failed to set security context %s for %s: %m", fcon, path);
470 if (security_getenforce() == 1) {
476 r = mkdir(path, mode);
481 setfscreatecon(NULL);
488 int label_mkdir(const char *path, mode_t mode) {
492 r = label_mkdir_selinux(path, mode);
498 r = mkdir(path, mode);
499 if (r < 0 && errno != EEXIST)
502 r = smack_relabel_in_dev(path);
507 r = mkdir(path, mode);
508 if (r < 0 && errno != EEXIST)
514 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
516 /* Binds a socket and label its file system object according to the SELinux policy */
519 security_context_t fcon = NULL;
520 const struct sockaddr_un *un;
526 assert(addrlen >= sizeof(sa_family_t));
528 if (!use_selinux() || !label_hnd)
531 /* Filter out non-local sockets */
532 if (addr->sa_family != AF_UNIX)
535 /* Filter out anonymous sockets */
536 if (addrlen < sizeof(sa_family_t) + 1)
539 /* Filter out abstract namespace sockets */
540 un = (const struct sockaddr_un*) addr;
541 if (un->sun_path[0] == 0)
544 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
546 if (path_is_absolute(path))
547 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
549 _cleanup_free_ char *newpath;
551 newpath = path_make_absolute_cwd(path);
555 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
559 r = setfscreatecon(fcon);
561 if (r < 0 && errno != ENOENT) {
562 log_error("Failed to set security context %s for %s: %m", fcon, path);
564 if (security_getenforce() == 1) {
570 r = bind(fd, addr, addrlen);
575 setfscreatecon(NULL);
582 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
585 int label_apply(const char *path, const char *label) {
592 r = setfilecon(path, (char *)label);