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(security_context_t
, freecon
);
45 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t
, context_free
);
47 #define _cleanup_security_context_free_ _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(const char *prefix
) {
87 usec_t before_timestamp
, after_timestamp
;
88 struct mallinfo before_mallinfo
, after_mallinfo
;
90 if (!mac_selinux_use())
96 before_mallinfo
= mallinfo();
97 before_timestamp
= now(CLOCK_MONOTONIC
);
100 struct selinux_opt options
[] = {
101 { .type
= SELABEL_OPT_SUBSET
, .value
= prefix
},
104 label_hnd
= selabel_open(SELABEL_CTX_FILE
, options
, ELEMENTSOF(options
));
106 label_hnd
= selabel_open(SELABEL_CTX_FILE
, NULL
, 0);
109 log_enforcing("Failed to initialize SELinux context: %m");
110 r
= security_getenforce() == 1 ? -errno
: 0;
112 char timespan
[FORMAT_TIMESPAN_MAX
];
115 after_timestamp
= now(CLOCK_MONOTONIC
);
116 after_mallinfo
= mallinfo();
118 l
= after_mallinfo
.uordblks
> before_mallinfo
.uordblks
? after_mallinfo
.uordblks
- before_mallinfo
.uordblks
: 0;
120 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
121 format_timespan(timespan
, sizeof(timespan
), after_timestamp
- before_timestamp
, 0),
129 void mac_selinux_finish(void) {
135 selabel_close(label_hnd
);
140 int mac_selinux_fix(const char *path
, bool ignore_enoent
, bool ignore_erofs
) {
148 /* if mac_selinux_init() wasn't called before we are a NOOP */
152 r
= lstat(path
, &st
);
154 _cleanup_security_context_free_ security_context_t fcon
= NULL
;
156 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, st
.st_mode
);
158 /* If there's no label to set, then exit without warning */
159 if (r
< 0 && errno
== ENOENT
)
163 r
= lsetfilecon(path
, fcon
);
165 /* If the FS doesn't support labels, then exit without warning */
166 if (r
< 0 && errno
== EOPNOTSUPP
)
172 /* Ignore ENOENT in some cases */
173 if (ignore_enoent
&& errno
== ENOENT
)
176 if (ignore_erofs
&& errno
== EROFS
)
179 log_enforcing("Unable to fix SELinux security context of %s: %m", path
);
180 if (security_getenforce() == 1)
188 int mac_selinux_apply(const char *path
, const char *label
) {
191 if (!mac_selinux_use())
197 if (setfilecon(path
, (security_context_t
) label
) < 0) {
198 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label
, path
);
199 if (security_getenforce() > 0)
206 int mac_selinux_get_create_label_from_exe(const char *exe
, char **label
) {
210 _cleanup_security_context_free_ security_context_t mycon
= NULL
, fcon
= NULL
;
211 security_class_t sclass
;
216 if (!mac_selinux_have())
219 r
= getcon_raw(&mycon
);
223 r
= getfilecon_raw(exe
, &fcon
);
227 sclass
= string_to_security_class("process");
228 r
= security_compute_create(mycon
, fcon
, sclass
, (security_context_t
*) label
);
236 int mac_selinux_get_our_label(char **label
) {
242 if (!mac_selinux_have())
245 r
= getcon_raw(label
);
253 int mac_selinux_get_child_mls_label(int socket_fd
, const char *exe
, const char *exec_label
, char **label
) {
257 _cleanup_security_context_free_ security_context_t mycon
= NULL
, peercon
= NULL
, fcon
= NULL
;
258 _cleanup_context_free_ context_t pcon
= NULL
, bcon
= NULL
;
259 security_class_t sclass
;
260 const char *range
= NULL
;
262 assert(socket_fd
>= 0);
266 if (!mac_selinux_have())
269 r
= getcon_raw(&mycon
);
273 r
= getpeercon(socket_fd
, &peercon
);
278 /* If there is no context set for next exec let's use context
279 of target executable */
280 r
= getfilecon_raw(exe
, &fcon
);
285 bcon
= context_new(mycon
);
289 pcon
= context_new(peercon
);
293 range
= context_range_get(pcon
);
297 r
= context_range_set(bcon
, range
);
302 mycon
= strdup(context_str(bcon
));
306 sclass
= string_to_security_class("process");
307 r
= security_compute_create(mycon
, fcon
, sclass
, (security_context_t
*) label
);
315 char* mac_selinux_free(char *label
) {
321 if (!mac_selinux_have())
325 freecon((security_context_t
) label
);
331 int mac_selinux_create_file_prepare(const char *path
, mode_t mode
) {
334 _cleanup_security_context_free_ security_context_t filecon
= NULL
;
342 if (path_is_absolute(path
))
343 r
= selabel_lookup_raw(label_hnd
, &filecon
, path
, mode
);
345 _cleanup_free_
char *newpath
= NULL
;
347 r
= path_make_absolute_cwd(path
, &newpath
);
351 r
= selabel_lookup_raw(label_hnd
, &filecon
, newpath
, mode
);
355 /* No context specified by the policy? Proceed without setting it. */
359 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
361 if (setfscreatecon(filecon
) >= 0)
362 return 0; /* Success! */
364 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon
, path
);
367 if (security_getenforce() > 0)
374 void mac_selinux_create_file_clear(void) {
379 if (!mac_selinux_use())
382 setfscreatecon(NULL
);
386 int mac_selinux_create_socket_prepare(const char *label
) {
389 if (!mac_selinux_use())
394 if (setsockcreatecon((security_context_t
) label
) < 0) {
395 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label
);
397 if (security_getenforce() == 1)
405 void mac_selinux_create_socket_clear(void) {
410 if (!mac_selinux_use())
413 setsockcreatecon(NULL
);
417 int mac_selinux_bind(int fd
, const struct sockaddr
*addr
, socklen_t addrlen
) {
419 /* Binds a socket and label its file system object according to the SELinux policy */
422 _cleanup_security_context_free_ security_context_t fcon
= NULL
;
423 const struct sockaddr_un
*un
;
424 bool context_changed
= false;
430 assert(addrlen
>= sizeof(sa_family_t
));
435 /* Filter out non-local sockets */
436 if (addr
->sa_family
!= AF_UNIX
)
439 /* Filter out anonymous sockets */
440 if (addrlen
< offsetof(struct sockaddr_un
, sun_path
) + 1)
443 /* Filter out abstract namespace sockets */
444 un
= (const struct sockaddr_un
*) addr
;
445 if (un
->sun_path
[0] == 0)
448 path
= strndupa(un
->sun_path
, addrlen
- offsetof(struct sockaddr_un
, sun_path
));
450 if (path_is_absolute(path
))
451 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, S_IFSOCK
);
453 _cleanup_free_
char *newpath
= NULL
;
455 r
= path_make_absolute_cwd(path
, &newpath
);
459 r
= selabel_lookup_raw(label_hnd
, &fcon
, newpath
, S_IFSOCK
);
463 /* No context specified by the policy? Proceed without setting it */
467 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
468 if (security_getenforce() > 0)
472 if (setfscreatecon(fcon
) < 0) {
473 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon
, path
);
474 if (security_getenforce() > 0)
477 context_changed
= true;
480 r
= bind(fd
, addr
, addrlen
) < 0 ? -errno
: 0;
483 setfscreatecon(NULL
);
489 if (bind(fd
, addr
, addrlen
) < 0)