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>
39 #include "path-util.h"
40 #include "selinux-util.h"
41 #include "smack-util.h"
44 static struct selabel_handle *label_hnd = NULL;
47 static int smack_relabel_in_dev(const char *path) {
55 * Path must be in /dev and must exist
57 if (!path_startswith(path, "/dev"))
65 * Label directories and character devices "*".
67 * Don't change anything else.
69 if (S_ISDIR(sb.st_mode))
70 label = SMACK_STAR_LABEL;
71 else if (S_ISLNK(sb.st_mode))
72 label = SMACK_FLOOR_LABEL;
73 else if (S_ISCHR(sb.st_mode))
74 label = SMACK_STAR_LABEL;
78 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
80 log_error("Smack relabeling \"%s\" %m", path);
88 int label_init(const char *prefix) {
92 usec_t before_timestamp, after_timestamp;
93 struct mallinfo before_mallinfo, after_mallinfo;
101 before_mallinfo = mallinfo();
102 before_timestamp = now(CLOCK_MONOTONIC);
105 struct selinux_opt options[] = {
106 { .type = SELABEL_OPT_SUBSET, .value = prefix },
109 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
111 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
114 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
115 "Failed to initialize SELinux context: %m");
116 r = security_getenforce() == 1 ? -errno : 0;
118 char timespan[FORMAT_TIMESPAN_MAX];
121 after_timestamp = now(CLOCK_MONOTONIC);
122 after_mallinfo = mallinfo();
124 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
126 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
127 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
135 static int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs) {
140 security_context_t fcon;
145 r = lstat(path, &st);
147 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
149 /* If there's no label to set, then exit without warning */
150 if (r < 0 && errno == ENOENT)
154 r = lsetfilecon(path, fcon);
157 /* If the FS doesn't support labels, then exit without warning */
158 if (r < 0 && errno == ENOTSUP)
164 /* Ignore ENOENT in some cases */
165 if (ignore_enoent && errno == ENOENT)
168 if (ignore_erofs && errno == EROFS)
171 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
172 "Unable to fix label of %s: %m", path);
173 r = security_getenforce() == 1 ? -errno : 0;
180 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
184 r = label_fix_selinux(path, ignore_enoent, ignore_erofs);
190 r = smack_relabel_in_dev(path);
198 void label_finish(void) {
205 selabel_close(label_hnd);
209 int label_get_create_label_from_exe(const char *exe, char **label) {
214 security_context_t mycon = NULL, fcon = NULL;
215 security_class_t sclass;
217 if (!use_selinux()) {
226 r = getfilecon(exe, &fcon);
230 sclass = string_to_security_class("process");
231 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
233 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
236 if (r < 0 && security_getenforce() == 1)
246 int label_context_set(const char *path, mode_t mode) {
250 security_context_t filecon = NULL;
252 if (!use_selinux() || !label_hnd)
255 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
256 if (r < 0 && errno != ENOENT)
259 r = setfscreatecon(filecon);
261 log_error("Failed to set SELinux file context on %s: %m", path);
268 if (r < 0 && security_getenforce() == 0)
275 int label_socket_set(const char *label) {
281 if (setsockcreatecon((security_context_t) label) < 0) {
282 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
283 "Failed to set SELinux context (%s) on socket: %m", label);
285 if (security_getenforce() == 1)
293 void label_context_clear(void) {
301 setfscreatecon(NULL);
305 void label_socket_clear(void) {
313 setsockcreatecon(NULL);
317 void label_free(const char *label) {
323 freecon((security_context_t) label);
327 static int label_mkdir_selinux(const char *path, mode_t mode) {
331 /* Creates a directory and labels it according to the SELinux policy */
332 security_context_t fcon = NULL;
337 if (path_is_absolute(path))
338 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
340 _cleanup_free_ char *newpath;
342 newpath = path_make_absolute_cwd(path);
346 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
350 r = setfscreatecon(fcon);
352 if (r < 0 && errno != ENOENT) {
353 log_error("Failed to set security context %s for %s: %m", fcon, path);
355 if (security_getenforce() == 1) {
361 r = mkdir(path, mode);
366 setfscreatecon(NULL);
373 int label_mkdir(const char *path, mode_t mode) {
377 r = label_mkdir_selinux(path, mode);
383 r = mkdir(path, mode);
384 if (r < 0 && errno != EEXIST)
387 r = smack_relabel_in_dev(path);
392 r = mkdir(path, mode);
393 if (r < 0 && errno != EEXIST)
399 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
401 /* Binds a socket and label its file system object according to the SELinux policy */
404 security_context_t fcon = NULL;
405 const struct sockaddr_un *un;
411 assert(addrlen >= sizeof(sa_family_t));
413 if (!use_selinux() || !label_hnd)
416 /* Filter out non-local sockets */
417 if (addr->sa_family != AF_UNIX)
420 /* Filter out anonymous sockets */
421 if (addrlen < sizeof(sa_family_t) + 1)
424 /* Filter out abstract namespace sockets */
425 un = (const struct sockaddr_un*) addr;
426 if (un->sun_path[0] == 0)
429 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
431 if (path_is_absolute(path))
432 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
434 _cleanup_free_ char *newpath;
436 newpath = path_make_absolute_cwd(path);
440 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
444 r = setfscreatecon(fcon);
446 if (r < 0 && errno != ENOENT) {
447 log_error("Failed to set security context %s for %s: %m", fcon, path);
449 if (security_getenforce() == 1) {
455 r = bind(fd, addr, addrlen);
460 setfscreatecon(NULL);
467 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
470 int label_apply(const char *path, const char *label) {
477 r = setfilecon(path, (char *)label);