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/>.
26 #include <sys/socket.h>
28 #include <sys/types.h>
35 #include "path-util.h"
38 #include "selinux-util.h"
39 #include <selinux/selinux.h>
40 #include <selinux/label.h>
42 static struct selabel_handle *label_hnd = NULL;
46 #include <sys/xattr.h>
48 #define DEV_DIR "/dev"
49 #define DEV_PATH "/dev/"
50 #define DEV_PATH_LEN 5
51 #define FLOOR_LABEL "_"
52 #define STAR_LABEL "*"
54 static void smack_relabel_in_dev(const char *path) {
60 * Path must be in /dev and must exist
62 if (strcmp(path, DEV_DIR) &&
63 strncmp(path, DEV_PATH, DEV_PATH_LEN))
71 * Label directories and character devices "*".
73 * Don't change anything else.
75 if (S_ISDIR(sb.st_mode))
77 else if (S_ISLNK(sb.st_mode))
79 else if (S_ISCHR(sb.st_mode))
84 r = setxattr(path, "security.SMACK64", label, strlen(label), 0);
86 log_error("Smack relabeling \"%s\" %s", path, strerror(errno));
91 int label_init(const char *prefix) {
95 usec_t before_timestamp, after_timestamp;
96 struct mallinfo before_mallinfo, after_mallinfo;
104 before_mallinfo = mallinfo();
105 before_timestamp = now(CLOCK_MONOTONIC);
108 struct selinux_opt options[] = {
109 { .type = SELABEL_OPT_SUBSET, .value = prefix },
112 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
114 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
117 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
118 "Failed to initialize SELinux context: %m");
119 r = security_getenforce() == 1 ? -errno : 0;
121 char timespan[FORMAT_TIMESPAN_MAX];
124 after_timestamp = now(CLOCK_MONOTONIC);
125 after_mallinfo = mallinfo();
127 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
129 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
130 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
138 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
143 security_context_t fcon;
145 if (!use_selinux() || !label_hnd)
148 r = lstat(path, &st);
150 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
152 /* If there's no label to set, then exit without warning */
153 if (r < 0 && errno == ENOENT)
157 r = lsetfilecon(path, fcon);
160 /* If the FS doesn't support labels, then exit without warning */
161 if (r < 0 && errno == ENOTSUP)
167 /* Ignore ENOENT in some cases */
168 if (ignore_enoent && errno == ENOENT)
171 if (ignore_erofs && errno == EROFS)
174 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
175 "Unable to fix label of %s: %m", path);
176 r = security_getenforce() == 1 ? -errno : 0;
180 smack_relabel_in_dev(path);
186 void label_finish(void) {
189 if (use_selinux() && label_hnd)
190 selabel_close(label_hnd);
194 int label_get_create_label_from_exe(const char *exe, char **label) {
199 security_context_t mycon = NULL, fcon = NULL;
200 security_class_t sclass;
202 if (!use_selinux()) {
211 r = getfilecon(exe, &fcon);
215 sclass = string_to_security_class("process");
216 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
218 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
221 if (r < 0 && security_getenforce() == 1)
231 int label_context_set(const char *path, mode_t mode) {
235 security_context_t filecon = NULL;
237 if (!use_selinux() || !label_hnd)
240 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
241 if (r < 0 && errno != ENOENT)
244 r = setfscreatecon(filecon);
246 log_error("Failed to set SELinux file context on %s: %m", path);
253 if (r < 0 && security_getenforce() == 0)
257 smack_relabel_in_dev(path);
263 int label_socket_set(const char *label) {
269 if (setsockcreatecon((security_context_t) label) < 0) {
270 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
271 "Failed to set SELinux context (%s) on socket: %m", label);
273 if (security_getenforce() == 1)
281 void label_context_clear(void) {
287 setfscreatecon(NULL);
291 void label_socket_clear(void) {
297 setsockcreatecon(NULL);
301 void label_free(const char *label) {
307 freecon((security_context_t) label);
311 int label_mkdir(const char *path, mode_t mode) {
315 /* Creates a directory and labels it according to the SELinux policy */
316 security_context_t fcon = NULL;
318 if (!use_selinux() || !label_hnd)
321 if (path_is_absolute(path))
322 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
326 newpath = path_make_absolute_cwd(path);
330 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
335 r = setfscreatecon(fcon);
337 if (r < 0 && errno != ENOENT) {
338 log_error("Failed to set security context %s for %s: %m", fcon, path);
340 if (security_getenforce() == 1) {
346 r = mkdir(path, mode);
351 setfscreatecon(NULL);
358 r = mkdir(path, mode);
362 smack_relabel_in_dev(path);
367 int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
369 /* Binds a socket and label its file system object according to the SELinux policy */
373 security_context_t fcon = NULL;
374 const struct sockaddr_un *un;
379 assert(addrlen >= sizeof(sa_family_t));
381 if (!use_selinux() || !label_hnd)
384 /* Filter out non-local sockets */
385 if (addr->sa_family != AF_UNIX)
388 /* Filter out anonymous sockets */
389 if (addrlen < sizeof(sa_family_t) + 1)
392 /* Filter out abstract namespace sockets */
393 un = (const struct sockaddr_un*) addr;
394 if (un->sun_path[0] == 0)
397 path = strndup(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
401 if (path_is_absolute(path))
402 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
406 newpath = path_make_absolute_cwd(path);
413 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
418 r = setfscreatecon(fcon);
420 if (r < 0 && errno != ENOENT) {
421 log_error("Failed to set security context %s for %s: %m", fcon, path);
423 if (security_getenforce() == 1) {
429 r = bind(fd, addr, addrlen);
434 setfscreatecon(NULL);
442 return bind(fd, addr, addrlen) < 0 ? -errno : 0;