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/>.
27 #include <selinux/context.h>
28 #include <selinux/label.h>
29 #include <selinux/selinux.h>
32 #include "alloc-util.h"
33 #include "path-util.h"
34 #include "selinux-util.h"
38 DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t
, freecon
);
39 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t
, context_free
);
41 #define _cleanup_security_context_free_ _cleanup_(freeconp)
42 #define _cleanup_context_free_ _cleanup_(context_freep)
44 static int cached_use
= -1;
45 static struct selabel_handle
*label_hnd
= NULL
;
47 #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
50 bool mac_selinux_have(void) {
53 cached_use
= is_selinux_enabled() > 0;
61 bool mac_selinux_use(void) {
62 if (!mac_selinux_have())
65 /* Never try to configure SELinux features if we aren't
71 void mac_selinux_retest(void) {
77 int mac_selinux_init(const char *prefix
) {
81 usec_t before_timestamp
, after_timestamp
;
82 struct mallinfo before_mallinfo
, after_mallinfo
;
84 if (!mac_selinux_use())
90 before_mallinfo
= mallinfo();
91 before_timestamp
= now(CLOCK_MONOTONIC
);
94 struct selinux_opt options
[] = {
95 { .type
= SELABEL_OPT_SUBSET
, .value
= prefix
},
98 label_hnd
= selabel_open(SELABEL_CTX_FILE
, options
, ELEMENTSOF(options
));
100 label_hnd
= selabel_open(SELABEL_CTX_FILE
, NULL
, 0);
103 log_enforcing("Failed to initialize SELinux context: %m");
104 r
= security_getenforce() == 1 ? -errno
: 0;
106 char timespan
[FORMAT_TIMESPAN_MAX
];
109 after_timestamp
= now(CLOCK_MONOTONIC
);
110 after_mallinfo
= mallinfo();
112 l
= after_mallinfo
.uordblks
> before_mallinfo
.uordblks
? after_mallinfo
.uordblks
- before_mallinfo
.uordblks
: 0;
114 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
115 format_timespan(timespan
, sizeof(timespan
), after_timestamp
- before_timestamp
, 0),
123 void mac_selinux_finish(void) {
129 selabel_close(label_hnd
);
134 int mac_selinux_fix(const char *path
, bool ignore_enoent
, bool ignore_erofs
) {
142 /* if mac_selinux_init() wasn't called before we are a NOOP */
146 r
= lstat(path
, &st
);
148 _cleanup_security_context_free_ security_context_t fcon
= NULL
;
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
);
159 /* If the FS doesn't support labels, then exit without warning */
160 if (r
< 0 && errno
== EOPNOTSUPP
)
166 /* Ignore ENOENT in some cases */
167 if (ignore_enoent
&& errno
== ENOENT
)
170 if (ignore_erofs
&& errno
== EROFS
)
173 log_enforcing("Unable to fix SELinux security context of %s: %m", path
);
174 if (security_getenforce() == 1)
182 int mac_selinux_apply(const char *path
, const char *label
) {
185 if (!mac_selinux_use())
191 if (setfilecon(path
, (security_context_t
) label
) < 0) {
192 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label
, path
);
193 if (security_getenforce() > 0)
200 int mac_selinux_get_create_label_from_exe(const char *exe
, char **label
) {
204 _cleanup_security_context_free_ security_context_t mycon
= NULL
, fcon
= NULL
;
205 security_class_t sclass
;
210 if (!mac_selinux_have())
213 r
= getcon_raw(&mycon
);
217 r
= getfilecon_raw(exe
, &fcon
);
221 sclass
= string_to_security_class("process");
222 r
= security_compute_create(mycon
, fcon
, sclass
, (security_context_t
*) label
);
230 int mac_selinux_get_our_label(char **label
) {
236 if (!mac_selinux_have())
239 r
= getcon_raw(label
);
247 int mac_selinux_get_child_mls_label(int socket_fd
, const char *exe
, const char *exec_label
, char **label
) {
251 _cleanup_security_context_free_ security_context_t mycon
= NULL
, peercon
= NULL
, fcon
= NULL
;
252 _cleanup_context_free_ context_t pcon
= NULL
, bcon
= NULL
;
253 security_class_t sclass
;
254 const char *range
= NULL
;
256 assert(socket_fd
>= 0);
260 if (!mac_selinux_have())
263 r
= getcon_raw(&mycon
);
267 r
= getpeercon(socket_fd
, &peercon
);
272 /* If there is no context set for next exec let's use context
273 of target executable */
274 r
= getfilecon_raw(exe
, &fcon
);
279 bcon
= context_new(mycon
);
283 pcon
= context_new(peercon
);
287 range
= context_range_get(pcon
);
291 r
= context_range_set(bcon
, range
);
296 mycon
= strdup(context_str(bcon
));
300 sclass
= string_to_security_class("process");
301 r
= security_compute_create(mycon
, fcon
, sclass
, (security_context_t
*) label
);
309 char* mac_selinux_free(char *label
) {
315 if (!mac_selinux_have())
319 freecon((security_context_t
) label
);
325 int mac_selinux_create_file_prepare(const char *path
, mode_t mode
) {
328 _cleanup_security_context_free_ security_context_t filecon
= NULL
;
336 if (path_is_absolute(path
))
337 r
= selabel_lookup_raw(label_hnd
, &filecon
, path
, mode
);
339 _cleanup_free_
char *newpath
= NULL
;
341 r
= path_make_absolute_cwd(path
, &newpath
);
345 r
= selabel_lookup_raw(label_hnd
, &filecon
, newpath
, mode
);
349 /* No context specified by the policy? Proceed without setting it. */
353 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
355 if (setfscreatecon(filecon
) >= 0)
356 return 0; /* Success! */
358 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon
, path
);
361 if (security_getenforce() > 0)
368 void mac_selinux_create_file_clear(void) {
373 if (!mac_selinux_use())
376 setfscreatecon(NULL
);
380 int mac_selinux_create_socket_prepare(const char *label
) {
383 if (!mac_selinux_use())
388 if (setsockcreatecon((security_context_t
) label
) < 0) {
389 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label
);
391 if (security_getenforce() == 1)
399 void mac_selinux_create_socket_clear(void) {
404 if (!mac_selinux_use())
407 setsockcreatecon(NULL
);
411 int mac_selinux_bind(int fd
, const struct sockaddr
*addr
, socklen_t addrlen
) {
413 /* Binds a socket and label its file system object according to the SELinux policy */
416 _cleanup_security_context_free_ security_context_t fcon
= NULL
;
417 const struct sockaddr_un
*un
;
418 bool context_changed
= false;
424 assert(addrlen
>= sizeof(sa_family_t
));
429 /* Filter out non-local sockets */
430 if (addr
->sa_family
!= AF_UNIX
)
433 /* Filter out anonymous sockets */
434 if (addrlen
< offsetof(struct sockaddr_un
, sun_path
) + 1)
437 /* Filter out abstract namespace sockets */
438 un
= (const struct sockaddr_un
*) addr
;
439 if (un
->sun_path
[0] == 0)
442 path
= strndupa(un
->sun_path
, addrlen
- offsetof(struct sockaddr_un
, sun_path
));
444 if (path_is_absolute(path
))
445 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, S_IFSOCK
);
447 _cleanup_free_
char *newpath
= NULL
;
449 r
= path_make_absolute_cwd(path
, &newpath
);
453 r
= selabel_lookup_raw(label_hnd
, &fcon
, newpath
, S_IFSOCK
);
457 /* No context specified by the policy? Proceed without setting it */
461 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
462 if (security_getenforce() > 0)
466 if (setfscreatecon(fcon
) < 0) {
467 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon
, path
);
468 if (security_getenforce() > 0)
471 context_changed
= true;
474 r
= bind(fd
, addr
, addrlen
) < 0 ? -errno
: 0;
477 setfscreatecon(NULL
);
483 if (bind(fd
, addr
, addrlen
) < 0)