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>
31 #include <sys/xattr.h>
34 #include <selinux/selinux.h>
35 #include <selinux/label.h>
41 #include "path-util.h"
42 #include "selinux-util.h"
43 #include "smack-util.h"
46 static struct selabel_handle *label_hnd = NULL;
49 static int smack_relabel_in_dev(const char *path) {
57 * Path must be in /dev and must exist
59 if (!path_startswith(path, "/dev"))
67 * Label directories and character devices "*".
69 * Don't change anything else.
71 if (S_ISDIR(sb.st_mode))
72 label = SMACK_STAR_LABEL;
73 else if (S_ISLNK(sb.st_mode))
74 label = SMACK_FLOOR_LABEL;
75 else if (S_ISCHR(sb.st_mode))
76 label = SMACK_STAR_LABEL;
80 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
82 log_error("Smack relabeling \"%s\" %s", path, strerror(errno));
90 int label_init(const char *prefix) {
94 usec_t before_timestamp, after_timestamp;
95 struct mallinfo before_mallinfo, after_mallinfo;
103 before_mallinfo = mallinfo();
104 before_timestamp = now(CLOCK_MONOTONIC);
107 struct selinux_opt options[] = {
108 { .type = SELABEL_OPT_SUBSET, .value = prefix },
111 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
113 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
116 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
117 "Failed to initialize SELinux context: %m");
118 r = security_getenforce() == 1 ? -errno : 0;
120 char timespan[FORMAT_TIMESPAN_MAX];
123 after_timestamp = now(CLOCK_MONOTONIC);
124 after_mallinfo = mallinfo();
126 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
128 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
129 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
137 static int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs) {
142 security_context_t fcon;
147 r = lstat(path, &st);
149 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
151 /* If there's no label to set, then exit without warning */
152 if (r < 0 && errno == ENOENT)
156 r = lsetfilecon(path, fcon);
159 /* If the FS doesn't support labels, then exit without warning */
160 if (r < 0 && errno == ENOTSUP)
166 /* Ignore ENOENT in some cases */
167 if (ignore_enoent && errno == ENOENT)
170 if (ignore_erofs && errno == EROFS)
173 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
174 "Unable to fix label of %s: %m", path);
175 r = security_getenforce() == 1 ? -errno : 0;
182 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
186 r = label_fix_selinux(path, ignore_enoent, ignore_erofs);
192 r = smack_relabel_in_dev(path);
200 void label_finish(void) {
207 selabel_close(label_hnd);
211 int label_get_create_label_from_exe(const char *exe, char **label) {
216 security_context_t mycon = NULL, fcon = NULL;
217 security_class_t sclass;
219 if (!use_selinux()) {
228 r = getfilecon(exe, &fcon);
232 sclass = string_to_security_class("process");
233 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
235 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
238 if (r < 0 && security_getenforce() == 1)
248 int label_context_set(const char *path, mode_t mode) {
252 security_context_t filecon = NULL;
254 if (!use_selinux() || !label_hnd)
257 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
258 if (r < 0 && errno != ENOENT)
261 r = setfscreatecon(filecon);
263 log_error("Failed to set SELinux file context on %s: %m", path);
270 if (r < 0 && security_getenforce() == 0)
277 int label_socket_set(const char *label) {
283 if (setsockcreatecon((security_context_t) label) < 0) {
284 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
285 "Failed to set SELinux context (%s) on socket: %m", label);
287 if (security_getenforce() == 1)
295 void label_context_clear(void) {
301 setfscreatecon(NULL);
305 void label_socket_clear(void) {
311 setsockcreatecon(NULL);
315 void label_free(const char *label) {
321 freecon((security_context_t) label);
325 static int label_mkdir_selinux(const char *path, mode_t mode) {
329 /* Creates a directory and labels it according to the SELinux policy */
330 security_context_t fcon = NULL;
335 if (path_is_absolute(path))
336 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
338 _cleanup_free_ char *newpath;
340 newpath = path_make_absolute_cwd(path);
344 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
348 r = setfscreatecon(fcon);
350 if (r < 0 && errno != ENOENT) {
351 log_error("Failed to set security context %s for %s: %m", fcon, path);
353 if (security_getenforce() == 1) {
359 r = mkdir(path, mode);
364 setfscreatecon(NULL);
371 int label_mkdir(const char *path, mode_t mode) {
375 r = label_mkdir_selinux(path, mode);
381 r = mkdir(path, mode);
382 if (r < 0 && errno != EEXIST)
385 r = smack_relabel_in_dev(path);
390 r = mkdir(path, mode);
391 if (r < 0 && errno != EEXIST)
397 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
399 /* Binds a socket and label its file system object according to the SELinux policy */
402 security_context_t fcon = NULL;
403 const struct sockaddr_un *un;
409 assert(addrlen >= sizeof(sa_family_t));
411 if (!use_selinux() || !label_hnd)
414 /* Filter out non-local sockets */
415 if (addr->sa_family != AF_UNIX)
418 /* Filter out anonymous sockets */
419 if (addrlen < sizeof(sa_family_t) + 1)
422 /* Filter out abstract namespace sockets */
423 un = (const struct sockaddr_un*) addr;
424 if (un->sun_path[0] == 0)
427 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
429 if (path_is_absolute(path))
430 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
432 _cleanup_free_ char *newpath;
434 newpath = path_make_absolute_cwd(path);
438 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
442 r = setfscreatecon(fcon);
444 if (r < 0 && errno != ENOENT) {
445 log_error("Failed to set security context %s for %s: %m", fcon, path);
447 if (security_getenforce() == 1) {
453 r = bind(fd, addr, addrlen);
458 setfscreatecon(NULL);
465 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
468 int label_apply(const char *path, const char *label) {
475 r = setfilecon(path, (char *)label);