2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include <selinux/context.h>
31 #include <selinux/label.h>
32 #include <selinux/selinux.h>
35 #include "alloc-util.h"
38 #include "path-util.h"
39 #include "selinux-util.h"
40 #include "time-util.h"
44 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon
);
45 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t
, context_free
);
47 #define _cleanup_freecon_ _cleanup_(freeconp)
48 #define _cleanup_context_free_ _cleanup_(context_freep)
50 static int cached_use
= -1;
51 static struct selabel_handle
*label_hnd
= NULL
;
53 #define log_enforcing(...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, errno, __VA_ARGS__)
56 bool mac_selinux_use(void) {
59 cached_use
= is_selinux_enabled() > 0;
67 void mac_selinux_retest(void) {
73 int mac_selinux_init(void) {
77 usec_t before_timestamp
, after_timestamp
;
78 struct mallinfo before_mallinfo
, after_mallinfo
;
83 if (!mac_selinux_use())
86 before_mallinfo
= mallinfo();
87 before_timestamp
= now(CLOCK_MONOTONIC
);
89 label_hnd
= selabel_open(SELABEL_CTX_FILE
, NULL
, 0);
91 log_enforcing("Failed to initialize SELinux context: %m");
92 r
= security_getenforce() == 1 ? -errno
: 0;
94 char timespan
[FORMAT_TIMESPAN_MAX
];
97 after_timestamp
= now(CLOCK_MONOTONIC
);
98 after_mallinfo
= mallinfo();
100 l
= after_mallinfo
.uordblks
> before_mallinfo
.uordblks
? after_mallinfo
.uordblks
- before_mallinfo
.uordblks
: 0;
102 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
103 format_timespan(timespan
, sizeof(timespan
), after_timestamp
- before_timestamp
, 0),
111 void mac_selinux_finish(void) {
117 selabel_close(label_hnd
);
122 int mac_selinux_fix(const char *path
, bool ignore_enoent
, bool ignore_erofs
) {
130 /* if mac_selinux_init() wasn't called before we are a NOOP */
134 r
= lstat(path
, &st
);
136 _cleanup_freecon_
char* fcon
= NULL
;
138 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, st
.st_mode
);
140 /* If there's no label to set, then exit without warning */
141 if (r
< 0 && errno
== ENOENT
)
145 r
= lsetfilecon_raw(path
, fcon
);
147 /* If the FS doesn't support labels, then exit without warning */
148 if (r
< 0 && errno
== EOPNOTSUPP
)
154 /* Ignore ENOENT in some cases */
155 if (ignore_enoent
&& errno
== ENOENT
)
158 if (ignore_erofs
&& errno
== EROFS
)
161 log_enforcing("Unable to fix SELinux security context of %s: %m", path
);
162 if (security_getenforce() == 1)
170 int mac_selinux_apply(const char *path
, const char *label
) {
173 if (!mac_selinux_use())
179 if (setfilecon(path
, label
) < 0) {
180 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label
, path
);
181 if (security_getenforce() > 0)
188 int mac_selinux_get_create_label_from_exe(const char *exe
, char **label
) {
192 _cleanup_freecon_
char *mycon
= NULL
, *fcon
= NULL
;
193 security_class_t sclass
;
198 if (!mac_selinux_use())
201 r
= getcon_raw(&mycon
);
205 r
= getfilecon_raw(exe
, &fcon
);
209 sclass
= string_to_security_class("process");
210 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
218 int mac_selinux_get_our_label(char **label
) {
224 if (!mac_selinux_use())
227 r
= getcon_raw(label
);
235 int mac_selinux_get_child_mls_label(int socket_fd
, const char *exe
, const char *exec_label
, char **label
) {
239 _cleanup_freecon_
char *mycon
= NULL
, *peercon
= NULL
, *fcon
= NULL
;
240 _cleanup_context_free_ context_t pcon
= NULL
, bcon
= NULL
;
241 security_class_t sclass
;
242 const char *range
= NULL
;
244 assert(socket_fd
>= 0);
248 if (!mac_selinux_use())
251 r
= getcon_raw(&mycon
);
255 r
= getpeercon_raw(socket_fd
, &peercon
);
260 /* If there is no context set for next exec let's use context
261 of target executable */
262 r
= getfilecon_raw(exe
, &fcon
);
267 bcon
= context_new(mycon
);
271 pcon
= context_new(peercon
);
275 range
= context_range_get(pcon
);
279 r
= context_range_set(bcon
, range
);
284 mycon
= strdup(context_str(bcon
));
288 sclass
= string_to_security_class("process");
289 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
297 char* mac_selinux_free(char *label
) {
303 if (!mac_selinux_use())
313 int mac_selinux_create_file_prepare(const char *path
, mode_t mode
) {
316 _cleanup_freecon_
char *filecon
= NULL
;
324 if (path_is_absolute(path
))
325 r
= selabel_lookup_raw(label_hnd
, &filecon
, path
, mode
);
327 _cleanup_free_
char *newpath
= NULL
;
329 r
= path_make_absolute_cwd(path
, &newpath
);
333 r
= selabel_lookup_raw(label_hnd
, &filecon
, newpath
, mode
);
337 /* No context specified by the policy? Proceed without setting it. */
341 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
343 if (setfscreatecon_raw(filecon
) >= 0)
344 return 0; /* Success! */
346 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon
, path
);
349 if (security_getenforce() > 0)
356 void mac_selinux_create_file_clear(void) {
361 if (!mac_selinux_use())
364 setfscreatecon_raw(NULL
);
368 int mac_selinux_create_socket_prepare(const char *label
) {
371 if (!mac_selinux_use())
376 if (setsockcreatecon(label
) < 0) {
377 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label
);
379 if (security_getenforce() == 1)
387 void mac_selinux_create_socket_clear(void) {
392 if (!mac_selinux_use())
395 setsockcreatecon_raw(NULL
);
399 int mac_selinux_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 _cleanup_freecon_
char *fcon
= NULL
;
405 const struct sockaddr_un
*un
;
406 bool context_changed
= false;
412 assert(addrlen
>= sizeof(sa_family_t
));
417 /* Filter out non-local sockets */
418 if (addr
->sa_family
!= AF_UNIX
)
421 /* Filter out anonymous sockets */
422 if (addrlen
< offsetof(struct sockaddr_un
, sun_path
) + 1)
425 /* Filter out abstract namespace sockets */
426 un
= (const struct sockaddr_un
*) addr
;
427 if (un
->sun_path
[0] == 0)
430 path
= strndupa(un
->sun_path
, addrlen
- offsetof(struct sockaddr_un
, sun_path
));
432 if (path_is_absolute(path
))
433 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, S_IFSOCK
);
435 _cleanup_free_
char *newpath
= NULL
;
437 r
= path_make_absolute_cwd(path
, &newpath
);
441 r
= selabel_lookup_raw(label_hnd
, &fcon
, newpath
, S_IFSOCK
);
445 /* No context specified by the policy? Proceed without setting it */
449 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
450 if (security_getenforce() > 0)
454 if (setfscreatecon_raw(fcon
) < 0) {
455 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon
, path
);
456 if (security_getenforce() > 0)
459 context_changed
= true;
462 r
= bind(fd
, addr
, addrlen
) < 0 ? -errno
: 0;
465 setfscreatecon_raw(NULL
);
471 if (bind(fd
, addr
, addrlen
) < 0)