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>
34 #include "path-util.h"
37 #include "selinux-util.h"
38 #include <selinux/selinux.h>
39 #include <selinux/label.h>
41 static struct selabel_handle *label_hnd = NULL;
45 #include <sys/xattr.h>
47 #define FLOOR_LABEL "_"
48 #define STAR_LABEL "*"
50 static void smack_relabel_in_dev(const char *path) {
56 * Path must be in /dev and must exist
58 if (!path_equal(path, "/dev") &&
59 !path_startswith(path, "/dev"))
67 * Label directories and character devices "*".
69 * Don't change anything else.
71 if (S_ISDIR(sb.st_mode))
73 else if (S_ISLNK(sb.st_mode))
75 else if (S_ISCHR(sb.st_mode))
80 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
82 log_error("Smack relabeling \"%s\" %s", path, strerror(errno));
87 int label_init(const char *prefix) {
91 usec_t before_timestamp, after_timestamp;
92 struct mallinfo before_mallinfo, after_mallinfo;
100 before_mallinfo = mallinfo();
101 before_timestamp = now(CLOCK_MONOTONIC);
104 struct selinux_opt options[] = {
105 { .type = SELABEL_OPT_SUBSET, .value = prefix },
108 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
110 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
113 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
114 "Failed to initialize SELinux context: %m");
115 r = security_getenforce() == 1 ? -errno : 0;
117 char timespan[FORMAT_TIMESPAN_MAX];
120 after_timestamp = now(CLOCK_MONOTONIC);
121 after_mallinfo = mallinfo();
123 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
125 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
126 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
134 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
139 security_context_t fcon;
141 if (!use_selinux() || !label_hnd)
144 r = lstat(path, &st);
146 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
148 /* If there's no label to set, then exit without warning */
149 if (r < 0 && errno == ENOENT)
153 r = lsetfilecon(path, fcon);
156 /* If the FS doesn't support labels, then exit without warning */
157 if (r < 0 && errno == ENOTSUP)
163 /* Ignore ENOENT in some cases */
164 if (ignore_enoent && errno == ENOENT)
167 if (ignore_erofs && errno == EROFS)
170 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
171 "Unable to fix label of %s: %m", path);
172 r = security_getenforce() == 1 ? -errno : 0;
176 smack_relabel_in_dev(path);
182 void label_finish(void) {
189 selabel_close(label_hnd);
193 int label_get_create_label_from_exe(const char *exe, char **label) {
198 security_context_t mycon = NULL, fcon = NULL;
199 security_class_t sclass;
201 if (!use_selinux()) {
210 r = getfilecon(exe, &fcon);
214 sclass = string_to_security_class("process");
215 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
217 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
220 if (r < 0 && security_getenforce() == 1)
230 int label_context_set(const char *path, mode_t mode) {
234 security_context_t filecon = NULL;
236 if (!use_selinux() || !label_hnd)
239 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
240 if (r < 0 && errno != ENOENT)
243 r = setfscreatecon(filecon);
245 log_error("Failed to set SELinux file context on %s: %m", path);
252 if (r < 0 && security_getenforce() == 0)
256 smack_relabel_in_dev(path);
262 int label_socket_set(const char *label) {
268 if (setsockcreatecon((security_context_t) label) < 0) {
269 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
270 "Failed to set SELinux context (%s) on socket: %m", label);
272 if (security_getenforce() == 1)
280 void label_context_clear(void) {
286 setfscreatecon(NULL);
290 void label_socket_clear(void) {
296 setsockcreatecon(NULL);
300 void label_free(const char *label) {
306 freecon((security_context_t) label);
310 int label_mkdir(const char *path, mode_t mode) {
314 /* Creates a directory and labels it according to the SELinux policy */
315 security_context_t fcon = NULL;
317 if (!use_selinux() || !label_hnd)
320 if (path_is_absolute(path))
321 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
323 _cleanup_free_ char *newpath;
325 newpath = path_make_absolute_cwd(path);
329 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
333 r = setfscreatecon(fcon);
335 if (r < 0 && errno != ENOENT) {
336 log_error("Failed to set security context %s for %s: %m", fcon, path);
338 if (security_getenforce() == 1) {
344 r = mkdir(path, mode);
349 setfscreatecon(NULL);
356 r = mkdir(path, mode);
360 smack_relabel_in_dev(path);
365 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
367 /* Binds a socket and label its file system object according to the SELinux policy */
370 security_context_t fcon = NULL;
371 const struct sockaddr_un *un;
377 assert(addrlen >= sizeof(sa_family_t));
379 if (!use_selinux() || !label_hnd)
382 /* Filter out non-local sockets */
383 if (addr->sa_family != AF_UNIX)
386 /* Filter out anonymous sockets */
387 if (addrlen < sizeof(sa_family_t) + 1)
390 /* Filter out abstract namespace sockets */
391 un = (const struct sockaddr_un*) addr;
392 if (un->sun_path[0] == 0)
395 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
397 if (path_is_absolute(path))
398 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
400 _cleanup_free_ char *newpath;
402 newpath = path_make_absolute_cwd(path);
406 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
410 r = setfscreatecon(fcon);
412 if (r < 0 && errno != ENOENT) {
413 log_error("Failed to set security context %s for %s: %m", fcon, path);
415 if (security_getenforce() == 1) {
421 r = bind(fd, addr, addrlen);
426 setfscreatecon(NULL);
433 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
436 int label_apply(const char *path, const char *label) {
443 r = setfilecon(path, (char *)label);