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 static struct selabel_handle *label_hnd = NULL;
48 static int smack_relabel_in_dev(const char *path) {
56 * Path must be in /dev and must exist
58 if (!path_startswith(path, "/dev"))
66 * Label directories and character devices "*".
68 * Don't change anything else.
70 if (S_ISDIR(sb.st_mode))
71 label = SMACK_STAR_LABEL;
72 else if (S_ISLNK(sb.st_mode))
73 label = SMACK_FLOOR_LABEL;
74 else if (S_ISCHR(sb.st_mode))
75 label = SMACK_STAR_LABEL;
79 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
81 log_error("Smack relabeling \"%s\" %m", path);
89 int label_init(const char *prefix) {
93 usec_t before_timestamp, after_timestamp;
94 struct mallinfo before_mallinfo, after_mallinfo;
102 before_mallinfo = mallinfo();
103 before_timestamp = now(CLOCK_MONOTONIC);
106 struct selinux_opt options[] = {
107 { .type = SELABEL_OPT_SUBSET, .value = prefix },
110 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
112 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
115 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
116 "Failed to initialize SELinux context: %m");
117 r = security_getenforce() == 1 ? -errno : 0;
119 char timespan[FORMAT_TIMESPAN_MAX];
122 after_timestamp = now(CLOCK_MONOTONIC);
123 after_mallinfo = mallinfo();
125 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
127 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
128 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
136 static int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs) {
141 security_context_t fcon;
146 r = lstat(path, &st);
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(path, fcon);
158 /* If the FS doesn't support labels, then exit without warning */
159 if (r < 0 && errno == ENOTSUP)
165 /* Ignore ENOENT in some cases */
166 if (ignore_enoent && errno == ENOENT)
169 if (ignore_erofs && errno == EROFS)
172 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
173 "Unable to fix label of %s: %m", path);
174 r = security_getenforce() == 1 ? -errno : 0;
181 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
185 r = label_fix_selinux(path, ignore_enoent, ignore_erofs);
191 r = smack_relabel_in_dev(path);
199 void label_finish(void) {
206 selabel_close(label_hnd);
210 int label_get_create_label_from_exe(const char *exe, char **label) {
215 security_context_t mycon = NULL, fcon = NULL;
216 security_class_t sclass;
218 if (!use_selinux()) {
227 r = getfilecon(exe, &fcon);
231 sclass = string_to_security_class("process");
232 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
234 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
237 if (r < 0 && security_getenforce() == 1)
247 int label_get_child_label(int socket_fd, const char *exe, char **label) {
252 security_context_t mycon = NULL, peercon = NULL, fcon = NULL, ret = NULL;
253 security_class_t sclass;
254 context_t pcon = NULL, bcon = NULL;
255 const char *range = NULL;
257 assert(socket_fd >= 0);
265 r = getpeercon(socket_fd, &peercon);
269 r = getfilecon(exe, &fcon);
273 bcon = context_new(mycon);
277 pcon = context_new(peercon);
281 range = context_range_get(pcon);
285 r = context_range_set(bcon, range);
290 mycon = context_str(bcon);
294 sclass = string_to_security_class("process");
295 r = security_compute_create(mycon, fcon, sclass, &ret);
302 if (r && security_getenforce() == 1)
315 int label_context_set(const char *path, mode_t mode) {
319 security_context_t filecon = NULL;
321 if (!use_selinux() || !label_hnd)
324 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
325 if (r < 0 && errno != ENOENT)
328 r = setfscreatecon(filecon);
330 log_error("Failed to set SELinux file context on %s: %m", path);
337 if (r < 0 && security_getenforce() == 0)
344 int label_socket_set(const char *label) {
350 if (setsockcreatecon((security_context_t) label) < 0) {
351 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
352 "Failed to set SELinux context (%s) on socket: %m", label);
354 if (security_getenforce() == 1)
362 void label_context_clear(void) {
370 setfscreatecon(NULL);
374 void label_socket_clear(void) {
382 setsockcreatecon(NULL);
386 void label_free(const char *label) {
392 freecon((security_context_t) label);
396 static int label_mkdir_selinux(const char *path, mode_t mode) {
400 /* Creates a directory and labels it according to the SELinux policy */
401 security_context_t fcon = NULL;
406 if (path_is_absolute(path))
407 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
409 _cleanup_free_ char *newpath;
411 newpath = path_make_absolute_cwd(path);
415 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
419 r = setfscreatecon(fcon);
421 if (r < 0 && errno != ENOENT) {
422 log_error("Failed to set security context %s for %s: %m", fcon, path);
424 if (security_getenforce() == 1) {
430 r = mkdir(path, mode);
435 setfscreatecon(NULL);
442 int label_mkdir(const char *path, mode_t mode) {
446 r = label_mkdir_selinux(path, mode);
452 r = mkdir(path, mode);
453 if (r < 0 && errno != EEXIST)
456 r = smack_relabel_in_dev(path);
461 r = mkdir(path, mode);
462 if (r < 0 && errno != EEXIST)
468 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
470 /* Binds a socket and label its file system object according to the SELinux policy */
473 security_context_t fcon = NULL;
474 const struct sockaddr_un *un;
480 assert(addrlen >= sizeof(sa_family_t));
482 if (!use_selinux() || !label_hnd)
485 /* Filter out non-local sockets */
486 if (addr->sa_family != AF_UNIX)
489 /* Filter out anonymous sockets */
490 if (addrlen < sizeof(sa_family_t) + 1)
493 /* Filter out abstract namespace sockets */
494 un = (const struct sockaddr_un*) addr;
495 if (un->sun_path[0] == 0)
498 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
500 if (path_is_absolute(path))
501 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
503 _cleanup_free_ char *newpath;
505 newpath = path_make_absolute_cwd(path);
509 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
513 r = setfscreatecon(fcon);
515 if (r < 0 && errno != ENOENT) {
516 log_error("Failed to set security context %s for %s: %m", fcon, path);
518 if (security_getenforce() == 1) {
524 r = bind(fd, addr, addrlen);
529 setfscreatecon(NULL);
536 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
539 int label_apply(const char *path, const char *label) {
546 r = setfilecon(path, (char *)label);