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(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
56 bool mac_selinux_have(void) {
59 cached_use
= is_selinux_enabled() > 0;
67 bool mac_selinux_use(void) {
68 if (!mac_selinux_have())
71 /* Never try to configure SELinux features if we aren't
77 void mac_selinux_retest(void) {
83 int mac_selinux_init(void) {
87 usec_t before_timestamp
, after_timestamp
;
88 struct mallinfo before_mallinfo
, after_mallinfo
;
93 if (!mac_selinux_use())
96 before_mallinfo
= mallinfo();
97 before_timestamp
= now(CLOCK_MONOTONIC
);
99 label_hnd
= selabel_open(SELABEL_CTX_FILE
, NULL
, 0);
101 log_enforcing("Failed to initialize SELinux context: %m");
102 r
= security_getenforce() == 1 ? -errno
: 0;
104 char timespan
[FORMAT_TIMESPAN_MAX
];
107 after_timestamp
= now(CLOCK_MONOTONIC
);
108 after_mallinfo
= mallinfo();
110 l
= after_mallinfo
.uordblks
> before_mallinfo
.uordblks
? after_mallinfo
.uordblks
- before_mallinfo
.uordblks
: 0;
112 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
113 format_timespan(timespan
, sizeof(timespan
), after_timestamp
- before_timestamp
, 0),
121 void mac_selinux_finish(void) {
127 selabel_close(label_hnd
);
132 int mac_selinux_fix(const char *path
, bool ignore_enoent
, bool ignore_erofs
) {
140 /* if mac_selinux_init() wasn't called before we are a NOOP */
144 r
= lstat(path
, &st
);
146 _cleanup_freecon_
char* fcon
= NULL
;
148 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, st
.st_mode
);
150 /* If there's no label to set, then exit without warning */
151 if (r
< 0 && errno
== ENOENT
)
155 r
= lsetfilecon_raw(path
, fcon
);
157 /* If the FS doesn't support labels, then exit without warning */
158 if (r
< 0 && errno
== EOPNOTSUPP
)
164 /* Ignore ENOENT in some cases */
165 if (ignore_enoent
&& errno
== ENOENT
)
168 if (ignore_erofs
&& errno
== EROFS
)
171 log_enforcing("Unable to fix SELinux security context of %s: %m", path
);
172 if (security_getenforce() == 1)
180 int mac_selinux_apply(const char *path
, const char *label
) {
183 if (!mac_selinux_use())
189 if (setfilecon(path
, label
) < 0) {
190 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label
, path
);
191 if (security_getenforce() > 0)
198 int mac_selinux_get_create_label_from_exe(const char *exe
, char **label
) {
202 _cleanup_freecon_
char *mycon
= NULL
, *fcon
= NULL
;
203 security_class_t sclass
;
208 if (!mac_selinux_have())
211 r
= getcon_raw(&mycon
);
215 r
= getfilecon_raw(exe
, &fcon
);
219 sclass
= string_to_security_class("process");
220 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
228 int mac_selinux_get_our_label(char **label
) {
234 if (!mac_selinux_have())
237 r
= getcon_raw(label
);
245 int mac_selinux_get_child_mls_label(int socket_fd
, const char *exe
, const char *exec_label
, char **label
) {
249 _cleanup_freecon_
char *mycon
= NULL
, *peercon
= NULL
, *fcon
= NULL
;
250 _cleanup_context_free_ context_t pcon
= NULL
, bcon
= NULL
;
251 security_class_t sclass
;
252 const char *range
= NULL
;
254 assert(socket_fd
>= 0);
258 if (!mac_selinux_have())
261 r
= getcon_raw(&mycon
);
265 r
= getpeercon_raw(socket_fd
, &peercon
);
270 /* If there is no context set for next exec let's use context
271 of target executable */
272 r
= getfilecon_raw(exe
, &fcon
);
277 bcon
= context_new(mycon
);
281 pcon
= context_new(peercon
);
285 range
= context_range_get(pcon
);
289 r
= context_range_set(bcon
, range
);
294 mycon
= strdup(context_str(bcon
));
298 sclass
= string_to_security_class("process");
299 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
307 char* mac_selinux_free(char *label
) {
313 if (!mac_selinux_have())
323 int mac_selinux_create_file_prepare(const char *path
, mode_t mode
) {
326 _cleanup_freecon_
char *filecon
= NULL
;
334 if (path_is_absolute(path
))
335 r
= selabel_lookup_raw(label_hnd
, &filecon
, path
, mode
);
337 _cleanup_free_
char *newpath
= NULL
;
339 r
= path_make_absolute_cwd(path
, &newpath
);
343 r
= selabel_lookup_raw(label_hnd
, &filecon
, newpath
, mode
);
347 /* No context specified by the policy? Proceed without setting it. */
351 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
353 if (setfscreatecon_raw(filecon
) >= 0)
354 return 0; /* Success! */
356 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon
, path
);
359 if (security_getenforce() > 0)
366 void mac_selinux_create_file_clear(void) {
371 if (!mac_selinux_use())
374 setfscreatecon_raw(NULL
);
378 int mac_selinux_create_socket_prepare(const char *label
) {
381 if (!mac_selinux_use())
386 if (setsockcreatecon(label
) < 0) {
387 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label
);
389 if (security_getenforce() == 1)
397 void mac_selinux_create_socket_clear(void) {
402 if (!mac_selinux_use())
405 setsockcreatecon_raw(NULL
);
409 int mac_selinux_bind(int fd
, const struct sockaddr
*addr
, socklen_t addrlen
) {
411 /* Binds a socket and label its file system object according to the SELinux policy */
414 _cleanup_freecon_
char *fcon
= NULL
;
415 const struct sockaddr_un
*un
;
416 bool context_changed
= false;
422 assert(addrlen
>= sizeof(sa_family_t
));
427 /* Filter out non-local sockets */
428 if (addr
->sa_family
!= AF_UNIX
)
431 /* Filter out anonymous sockets */
432 if (addrlen
< offsetof(struct sockaddr_un
, sun_path
) + 1)
435 /* Filter out abstract namespace sockets */
436 un
= (const struct sockaddr_un
*) addr
;
437 if (un
->sun_path
[0] == 0)
440 path
= strndupa(un
->sun_path
, addrlen
- offsetof(struct sockaddr_un
, sun_path
));
442 if (path_is_absolute(path
))
443 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, S_IFSOCK
);
445 _cleanup_free_
char *newpath
= NULL
;
447 r
= path_make_absolute_cwd(path
, &newpath
);
451 r
= selabel_lookup_raw(label_hnd
, &fcon
, newpath
, S_IFSOCK
);
455 /* No context specified by the policy? Proceed without setting it */
459 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
460 if (security_getenforce() > 0)
464 if (setfscreatecon_raw(fcon
) < 0) {
465 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon
, path
);
466 if (security_getenforce() > 0)
469 context_changed
= true;
472 r
= bind(fd
, addr
, addrlen
) < 0 ? -errno
: 0;
475 setfscreatecon_raw(NULL
);
481 if (bind(fd
, addr
, addrlen
) < 0)