1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include <selinux/context.h>
32 #include <selinux/label.h>
33 #include <selinux/selinux.h>
36 #include "alloc-util.h"
40 #include "path-util.h"
41 #include "selinux-util.h"
42 #include "stdio-util.h"
43 #include "time-util.h"
47 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon
);
48 DEFINE_TRIVIAL_CLEANUP_FUNC(context_t
, context_free
);
50 #define _cleanup_freecon_ _cleanup_(freeconp)
51 #define _cleanup_context_free_ _cleanup_(context_freep)
53 static int cached_use
= -1;
54 static struct selabel_handle
*label_hnd
= NULL
;
56 #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
57 #define log_enforcing_errno(r, ...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, r, __VA_ARGS__)
60 bool mac_selinux_use(void) {
63 cached_use
= is_selinux_enabled() > 0;
71 void mac_selinux_retest(void) {
77 int mac_selinux_init(void) {
81 usec_t before_timestamp
, after_timestamp
;
82 struct mallinfo before_mallinfo
, after_mallinfo
;
87 if (!mac_selinux_use())
90 before_mallinfo
= mallinfo();
91 before_timestamp
= now(CLOCK_MONOTONIC
);
93 label_hnd
= selabel_open(SELABEL_CTX_FILE
, NULL
, 0);
95 log_enforcing("Failed to initialize SELinux context: %m");
96 r
= security_getenforce() == 1 ? -errno
: 0;
98 char timespan
[FORMAT_TIMESPAN_MAX
];
101 after_timestamp
= now(CLOCK_MONOTONIC
);
102 after_mallinfo
= mallinfo();
104 l
= after_mallinfo
.uordblks
> before_mallinfo
.uordblks
? after_mallinfo
.uordblks
- before_mallinfo
.uordblks
: 0;
106 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
107 format_timespan(timespan
, sizeof(timespan
), after_timestamp
- before_timestamp
, 0),
115 void mac_selinux_finish(void) {
121 selabel_close(label_hnd
);
126 int mac_selinux_fix(const char *path
, LabelFixFlags flags
) {
129 char procfs_path
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
130 _cleanup_freecon_
char* fcon
= NULL
;
131 _cleanup_close_
int fd
= -1;
137 /* if mac_selinux_init() wasn't called before we are a NOOP */
141 /* Open the file as O_PATH, to pin it while we determine and adjust the label */
142 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
144 if ((flags
& LABEL_IGNORE_ENOENT
) && errno
== ENOENT
)
150 if (fstat(fd
, &st
) < 0)
153 if (selabel_lookup_raw(label_hnd
, &fcon
, path
, st
.st_mode
) < 0) {
156 /* If there's no label to set, then exit without warning */
163 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
164 if (setfilecon_raw(procfs_path
, fcon
) < 0) {
165 _cleanup_freecon_
char *oldcon
= NULL
;
169 /* If the FS doesn't support labels, then exit without warning */
170 if (r
== -EOPNOTSUPP
)
173 /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
174 if (r
== -EROFS
&& (flags
& LABEL_IGNORE_EROFS
))
177 /* If the old label is identical to the new one, suppress any kind of error */
178 if (getfilecon_raw(procfs_path
, &oldcon
) >= 0 && streq(fcon
, oldcon
))
187 log_enforcing_errno(r
, "Unable to fix SELinux security context of %s: %m", path
);
188 if (security_getenforce() == 1)
195 int mac_selinux_apply(const char *path
, const char *label
) {
198 if (!mac_selinux_use())
204 if (setfilecon(path
, label
) < 0) {
205 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label
, path
);
206 if (security_getenforce() > 0)
213 int mac_selinux_get_create_label_from_exe(const char *exe
, char **label
) {
217 _cleanup_freecon_
char *mycon
= NULL
, *fcon
= NULL
;
218 security_class_t sclass
;
223 if (!mac_selinux_use())
226 r
= getcon_raw(&mycon
);
230 r
= getfilecon_raw(exe
, &fcon
);
234 sclass
= string_to_security_class("process");
235 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
243 int mac_selinux_get_our_label(char **label
) {
249 if (!mac_selinux_use())
252 r
= getcon_raw(label
);
260 int mac_selinux_get_child_mls_label(int socket_fd
, const char *exe
, const char *exec_label
, char **label
) {
264 _cleanup_freecon_
char *mycon
= NULL
, *peercon
= NULL
, *fcon
= NULL
;
265 _cleanup_context_free_ context_t pcon
= NULL
, bcon
= NULL
;
266 security_class_t sclass
;
267 const char *range
= NULL
;
269 assert(socket_fd
>= 0);
273 if (!mac_selinux_use())
276 r
= getcon_raw(&mycon
);
280 r
= getpeercon_raw(socket_fd
, &peercon
);
285 /* If there is no context set for next exec let's use context
286 of target executable */
287 r
= getfilecon_raw(exe
, &fcon
);
292 bcon
= context_new(mycon
);
296 pcon
= context_new(peercon
);
300 range
= context_range_get(pcon
);
304 r
= context_range_set(bcon
, range
);
309 mycon
= strdup(context_str(bcon
));
313 sclass
= string_to_security_class("process");
314 r
= security_compute_create_raw(mycon
, fcon
, sclass
, label
);
322 char* mac_selinux_free(char *label
) {
328 if (!mac_selinux_use())
338 int mac_selinux_create_file_prepare(const char *path
, mode_t mode
) {
341 _cleanup_freecon_
char *filecon
= NULL
;
349 if (path_is_absolute(path
))
350 r
= selabel_lookup_raw(label_hnd
, &filecon
, path
, mode
);
352 _cleanup_free_
char *newpath
= NULL
;
354 r
= path_make_absolute_cwd(path
, &newpath
);
358 r
= selabel_lookup_raw(label_hnd
, &filecon
, newpath
, mode
);
362 /* No context specified by the policy? Proceed without setting it. */
366 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
368 if (setfscreatecon_raw(filecon
) >= 0)
369 return 0; /* Success! */
371 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon
, path
);
374 if (security_getenforce() > 0)
381 void mac_selinux_create_file_clear(void) {
386 if (!mac_selinux_use())
389 setfscreatecon_raw(NULL
);
393 int mac_selinux_create_socket_prepare(const char *label
) {
396 if (!mac_selinux_use())
401 if (setsockcreatecon(label
) < 0) {
402 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label
);
404 if (security_getenforce() == 1)
412 void mac_selinux_create_socket_clear(void) {
417 if (!mac_selinux_use())
420 setsockcreatecon_raw(NULL
);
424 int mac_selinux_bind(int fd
, const struct sockaddr
*addr
, socklen_t addrlen
) {
426 /* Binds a socket and label its file system object according to the SELinux policy */
429 _cleanup_freecon_
char *fcon
= NULL
;
430 const struct sockaddr_un
*un
;
431 bool context_changed
= false;
437 assert(addrlen
>= sizeof(sa_family_t
));
442 /* Filter out non-local sockets */
443 if (addr
->sa_family
!= AF_UNIX
)
446 /* Filter out anonymous sockets */
447 if (addrlen
< offsetof(struct sockaddr_un
, sun_path
) + 1)
450 /* Filter out abstract namespace sockets */
451 un
= (const struct sockaddr_un
*) addr
;
452 if (un
->sun_path
[0] == 0)
455 path
= strndupa(un
->sun_path
, addrlen
- offsetof(struct sockaddr_un
, sun_path
));
457 if (path_is_absolute(path
))
458 r
= selabel_lookup_raw(label_hnd
, &fcon
, path
, S_IFSOCK
);
460 _cleanup_free_
char *newpath
= NULL
;
462 r
= path_make_absolute_cwd(path
, &newpath
);
466 r
= selabel_lookup_raw(label_hnd
, &fcon
, newpath
, S_IFSOCK
);
470 /* No context specified by the policy? Proceed without setting it */
474 log_enforcing("Failed to determine SELinux security context for %s: %m", path
);
475 if (security_getenforce() > 0)
479 if (setfscreatecon_raw(fcon
) < 0) {
480 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon
, path
);
481 if (security_getenforce() > 0)
484 context_changed
= true;
487 r
= bind(fd
, addr
, addrlen
) < 0 ? -errno
: 0;
490 setfscreatecon_raw(NULL
);
496 if (bind(fd
, addr
, addrlen
) < 0)