From: Lennart Poettering Date: Mon, 8 Sep 2025 16:31:49 +0000 (+0200) Subject: libselinux: turn into dlopen() dep X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=83b6ef9b62765b11bc602eae906ff13a5464a638;p=thirdparty%2Fsystemd.git libselinux: turn into dlopen() dep --- diff --git a/meson.build b/meson.build index 8ec025c8d6e..1acf9728d49 100644 --- a/meson.build +++ b/meson.build @@ -1154,6 +1154,7 @@ libselinux = dependency('libselinux', version : '>= 2.1.9', required : get_option('selinux')) conf.set10('HAVE_SELINUX', libselinux.found()) +libselinux_cflags = libselinux.partial_dependency(includes: true, compile_args: true) libapparmor = dependency('libapparmor', version : '>= 2.13', diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 02931b3223d..e02d2ddee69 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -6111,7 +6111,7 @@ int exec_invoke( char *exec_context = mac_selinux_context_net ?: context->selinux_context; if (exec_context) { - r = setexeccon(exec_context); + r = sym_setexeccon_raw(exec_context); if (r < 0) { if (!context->selinux_context_ignore) { *exit_status = EXIT_SELINUX_CONTEXT; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index c4ebec16011..352ee7d6775 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -6124,7 +6124,7 @@ int unit_load_fragment(Unit *u) { _cleanup_freecon_ char *selcon = NULL; /* Cache the SELinux context of the unit file here. We'll make use of when checking access permissions to loaded units */ - r = fgetfilecon_raw(fileno(f), &selcon); + r = sym_fgetfilecon_raw(fileno(f), &selcon); if (r < 0) log_unit_warning_errno(u, r, "Failed to read SELinux context of '%s', ignoring: %m", fragment); diff --git a/src/core/meson.build b/src/core/meson.build index fc549ce20f4..92d6c143d08 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -137,7 +137,7 @@ libcore_static = static_library( libmount_cflags, librt, libseccomp_cflags, - libselinux, + libselinux_cflags, threads, userspace], build_by_default : false) @@ -200,7 +200,7 @@ executables += [ libapparmor_cflags, libkmod_cflags, libseccomp_cflags, - libselinux, + libselinux_cflags, ], }, libexec_template + { @@ -213,7 +213,7 @@ executables += [ libapparmor_cflags, libpam_cflags, libseccomp_cflags, - libselinux, + libselinux_cflags, ], }, fuzz_template + { diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index ad1d2f30803..7d1b2791a7c 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -4,8 +4,6 @@ #if HAVE_SELINUX -#include -#include #include #include "sd-bus.h" @@ -153,7 +151,7 @@ static int access_init(sd_bus_error *error) { if (initialized) return 1; - if (avc_open(NULL, 0) != 0) { + if (sym_avc_open(NULL, 0) != 0) { /* Passing errno to save original value for later */ r = log_selinux_enforcing_errno(errno, "Failed to open the SELinux AVC: %m"); if (r == 0) @@ -168,8 +166,8 @@ static int access_init(sd_bus_error *error) { return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %m"); } - selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) { .func_audit = audit_callback }); - selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = log_callback }); + sym_selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) { .func_audit = audit_callback }); + sym_selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = log_callback }); initialized = true; return 1; @@ -196,7 +194,7 @@ static int get_our_contexts(const Unit *unit, const char **ret_acon, const char * does exactly the same - call getcon_raw(). However, it involves * selinux_init() which opens label DB. It was not part of the * original code. I don't want to change it for now. */ - if (getcon_raw(&fcon) < 0) + if (sym_getcon_raw(&fcon) < 0) return log_debug_errno(errno, "SELinux getcon_raw() failed: %m"); if (!fcon) @@ -226,7 +224,7 @@ static int check_access( assert(audit_info); assert(audit_info->function); - r = selinux_check_access(scon, tcon, tclass, permission, audit_info); + r = sym_selinux_check_access(scon, tcon, tclass, permission, audit_info); if (r < 0) { errno = -(r = errno_or_else(EPERM)); @@ -357,7 +355,7 @@ int mac_selinux_access_check_varlink_internal( /* We should call mac_selinux_get_peer_label() here similarly to get_our_contexts(). * See the explanation there why not. */ - if (getpeercon_raw(fd, &scon) < 0) + if (sym_getpeercon_raw(fd, &scon) < 0) return log_selinux_enforcing_errno( errno, "Failed to get peer SELinux context%s: %m", diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index db14db88ee3..891fa3cd8ec 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -18,13 +18,17 @@ int mac_selinux_setup(bool *loaded_policy) { #if HAVE_SELINUX int r; + r = dlopen_libselinux(); + if (r < 0) + return log_debug_errno(r, "No SELinux library available, skipping setup: %m"); + mac_selinux_disable_logging(); /* Don't load policy in the initrd if we don't appear to have it. For the real root, we check below * if we've already loaded policy, and return gracefully. */ - if (in_initrd() && access(selinux_path(), F_OK) < 0) { + if (in_initrd() && access(sym_selinux_path(), F_OK) < 0) { if (errno != ENOENT) - log_warning_errno(errno, "Unable to check if %s exists, assuming it does not: %m", selinux_path()); + log_warning_errno(errno, "Unable to check if %s exists, assuming it does not: %m", sym_selinux_path()); return 0; } @@ -37,7 +41,7 @@ int mac_selinux_setup(bool *loaded_policy) { * empty. SELinux guarantees this won't happen, but that file isn't specific to SELinux, and may be * provided by some other arbitrary LSM with different semantics. */ _cleanup_freecon_ char *con = NULL; - if (getcon_raw(&con) < 0) + if (sym_getcon_raw(&con) < 0) log_debug_errno(errno, "getcon_raw() failed, assuming SELinux is not initialized: %m"); else if (con) { initialized = !streq(con, "kernel"); @@ -50,7 +54,7 @@ int mac_selinux_setup(bool *loaded_policy) { /* Now load the policy */ usec_t before_load = now(CLOCK_MONOTONIC); int enforce = 0; - if (selinux_init_load_policy(&enforce) == 0) { /* NB: Apparently doesn't set useful errno! */ + if (sym_selinux_init_load_policy(&enforce) == 0) { /* NB: Apparently doesn't set useful errno! */ mac_selinux_retest(); /* Transition to the new context */ @@ -60,7 +64,7 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); log_warning_errno(r, "Failed to compute init label, ignoring: %m"); } else { - r = RET_NERRNO(setcon_raw(label)); + r = RET_NERRNO(sym_setcon_raw(label)); log_open(); if (r < 0) log_warning_errno(r, "Failed to transition into init label '%s', ignoring: %m", label); diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c index 1be51436130..5889adc2cec 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#if HAVE_SELINUX -#include -#endif - #include #include @@ -27,6 +23,7 @@ #include "prioq.h" #include "process-util.h" #include "procfs-util.h" +#include "selinux-util.h" #include "set.h" #include "string-util.h" #include "syslog-util.h" @@ -257,6 +254,9 @@ static int client_context_read_label( assert(pid_is_valid(c->pid)); assert(label_size == 0 || label); + if (!mac_selinux_use()) + return 0; + if (label_size > 0) { char *l; @@ -275,7 +275,7 @@ static int client_context_read_label( /* If we got no SELinux label passed in, let's try to acquire one */ - if (getpidcon(c->pid, &con) >= 0 && con) { + if (sym_getpidcon_raw(c->pid, &con) >= 0 && con) { free_and_replace(c->label, con); c->label_size = strlen(c->label); } diff --git a/src/journal/meson.build b/src/journal/meson.build index c09f38dd91c..364c4ce7bf5 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -58,7 +58,7 @@ journal_test_template = test_template + { journal_fuzz_template = fuzz_template + { 'objects' : ['systemd-journald'], - 'dependencies' : libselinux, + 'dependencies' : libselinux_cflags, } executables += [ @@ -69,7 +69,7 @@ executables += [ 'extract' : systemd_journald_extract_sources, 'dependencies' : [ liblz4_cflags, - libselinux, + libselinux_cflags, libxz_cflags, libzstd_cflags, threads, @@ -87,7 +87,7 @@ executables += [ 'public' : true, 'sources' : files('cat.c'), 'objects' : ['systemd-journald'], - 'dependencies' : [libselinux, threads], + 'dependencies' : [threads], }, executable_template + { 'name' : 'journalctl', @@ -106,7 +106,7 @@ executables += [ 'sources' : files('test-journald-config.c'), 'dependencies' : [ liblz4_cflags, - libselinux, + libselinux_cflags, libxz_cflags, ], }, @@ -114,7 +114,7 @@ executables += [ 'sources' : files('test-journald-rate-limit.c'), 'dependencies' : [ liblz4_cflags, - libselinux, + libselinux_cflags, libxz_cflags, ], }, @@ -122,7 +122,7 @@ executables += [ 'sources' : files('test-journald-syslog.c'), 'dependencies' : [ liblz4_cflags, - libselinux, + libselinux_cflags, libxz_cflags, threads, ], @@ -130,7 +130,7 @@ executables += [ journal_test_template + { 'sources' : files('test-journald-tables.c'), 'dependencies' : [ - libselinux, + libselinux_cflags, ], }, journal_fuzz_template + { diff --git a/src/nspawn/meson.build b/src/nspawn/meson.build index 35048462edd..1fcf6a3bb07 100644 --- a/src/nspawn/meson.build +++ b/src/nspawn/meson.build @@ -48,7 +48,7 @@ executables += [ 'extract' : nspawn_extract_sources, 'dependencies' : [ libseccomp_cflags, - libselinux, + libselinux_cflags, ], }, nspawn_test_template + { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a790f2d8a33..6bcb0a06a71 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -13,10 +13,6 @@ #include #include -#if HAVE_SELINUX -#include -#endif - #include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" @@ -104,6 +100,7 @@ #include "rm-rf.h" #include "runtime-scope.h" #include "seccomp-util.h" +#include "selinux-util.h" #include "shift-uid.h" #include "signal-util.h" #include "siphash24.h" @@ -3532,8 +3529,8 @@ static int inner_child( } #if HAVE_SELINUX - if (arg_selinux_context) - if (setexeccon(arg_selinux_context) < 0) + if (arg_selinux_context && mac_selinux_use()) + if (sym_setexeccon_raw(arg_selinux_context) < 0) return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context); #endif diff --git a/src/portable/meson.build b/src/portable/meson.build index 06ffa6259a1..9c9d04c4614 100644 --- a/src/portable/meson.build +++ b/src/portable/meson.build @@ -29,7 +29,7 @@ executables += [ 'sources' : systemd_portabled_sources, 'link_with' : portabled_link_with, 'dependencies' : [ - libselinux, + libselinux_cflags, threads, ], }, diff --git a/src/portable/portable.c b/src/portable/portable.c index a2da4d2ab33..503b5b08a26 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -310,10 +310,11 @@ static int extract_now( #if HAVE_SELINUX /* The units will be copied on the host's filesystem, so if they had a SELinux label * we have to preserve it. Copy it out so that it can be applied later. */ - - r = fgetfilecon_raw(fd, &con); - if (r < 0 && !ERRNO_IS_XATTR_ABSENT(errno)) - log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name); + if (mac_selinux_use()) { + r = sym_fgetfilecon_raw(fd, &con); + if (r < 0 && !ERRNO_IS_XATTR_ABSENT(errno)) + log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name); + } #endif if (socket_fd >= 0) { diff --git a/src/shared/meson.build b/src/shared/meson.build index 9acb83a47e7..f3906305c69 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -328,7 +328,7 @@ libshared_deps = [threads, libpam_cflags, librt, libseccomp_cflags, - libselinux, + libselinux_cflags, libxenctrl_cflags, libxz_cflags, libzstd_cflags] diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index f7c4c7d2f8d..4fca62b66d3 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -27,7 +27,7 @@ #include "time-util.h" #if HAVE_SELINUX -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(context_t, context_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(context_t, sym_context_free, context_freep, NULL); typedef enum Initialized { UNINITIALIZED, @@ -49,12 +49,98 @@ static int mac_selinux_label_post(int dir_fd, const char *path, bool created) { mac_selinux_create_file_clear(); return 0; } + +static void *libselinux_dl = NULL; + +DLSYM_PROTOTYPE(avc_open) = NULL; +DLSYM_PROTOTYPE(context_free) = NULL; +DLSYM_PROTOTYPE(context_new) = NULL; +DLSYM_PROTOTYPE(context_range_get) = NULL; +DLSYM_PROTOTYPE(context_range_set) = NULL; +DLSYM_PROTOTYPE(context_str) = NULL; +DLSYM_PROTOTYPE(fgetfilecon_raw) = NULL; +DLSYM_PROTOTYPE(fini_selinuxmnt) = NULL; +DLSYM_PROTOTYPE(freecon) = NULL; +DLSYM_PROTOTYPE(getcon_raw) = NULL; +DLSYM_PROTOTYPE(getfilecon_raw) = NULL; +DLSYM_PROTOTYPE(getpeercon_raw) = NULL; +DLSYM_PROTOTYPE(getpidcon_raw) = NULL; +DLSYM_PROTOTYPE(is_selinux_enabled) = NULL; +DLSYM_PROTOTYPE(security_compute_create_raw) = NULL; +DLSYM_PROTOTYPE(security_getenforce) = NULL; +DLSYM_PROTOTYPE(selabel_close) = NULL; +DLSYM_PROTOTYPE(selabel_lookup_raw) = NULL; +DLSYM_PROTOTYPE(selabel_open) = NULL; +DLSYM_PROTOTYPE(selinux_check_access) = NULL; +DLSYM_PROTOTYPE(selinux_getenforcemode) = NULL; +DLSYM_PROTOTYPE(selinux_init_load_policy) = NULL; +DLSYM_PROTOTYPE(selinux_path) = NULL; +DLSYM_PROTOTYPE(selinux_set_callback) = NULL; +DLSYM_PROTOTYPE(selinux_status_close) = NULL; +DLSYM_PROTOTYPE(selinux_status_getenforce) = NULL; +DLSYM_PROTOTYPE(selinux_status_open) = NULL; +DLSYM_PROTOTYPE(selinux_status_policyload) = NULL; +DLSYM_PROTOTYPE(setcon_raw) = NULL; +DLSYM_PROTOTYPE(setexeccon_raw) = NULL; +DLSYM_PROTOTYPE(setfilecon_raw) = NULL; +DLSYM_PROTOTYPE(setfscreatecon_raw) = NULL; +DLSYM_PROTOTYPE(setsockcreatecon_raw) = NULL; +DLSYM_PROTOTYPE(string_to_security_class) = NULL; + +int dlopen_libselinux(void) { + ELF_NOTE_DLOPEN("selinux", + "Support for SELinux", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libselinux.so.1"); + + return dlopen_many_sym_or_warn( + &libselinux_dl, + "libselinux.so.1", + LOG_DEBUG, + DLSYM_ARG(avc_open), + DLSYM_ARG(context_free), + DLSYM_ARG(context_new), + DLSYM_ARG(context_range_get), + DLSYM_ARG(context_range_set), + DLSYM_ARG(context_str), + DLSYM_ARG(fgetfilecon_raw), + DLSYM_ARG(fini_selinuxmnt), + DLSYM_ARG(freecon), + DLSYM_ARG(getcon_raw), + DLSYM_ARG(getfilecon_raw), + DLSYM_ARG(getpeercon_raw), + DLSYM_ARG(getpidcon_raw), + DLSYM_ARG(is_selinux_enabled), + DLSYM_ARG(security_compute_create_raw), + DLSYM_ARG(security_getenforce), + DLSYM_ARG(selabel_close), + DLSYM_ARG(selabel_lookup_raw), + DLSYM_ARG(selabel_open), + DLSYM_ARG(selinux_check_access), + DLSYM_ARG(selinux_getenforcemode), + DLSYM_ARG(selinux_init_load_policy), + DLSYM_ARG(selinux_path), + DLSYM_ARG(selinux_set_callback), + DLSYM_ARG(selinux_status_close), + DLSYM_ARG(selinux_status_getenforce), + DLSYM_ARG(selinux_status_open), + DLSYM_ARG(selinux_status_policyload), + DLSYM_ARG(setcon_raw), + DLSYM_ARG(setexeccon_raw), + DLSYM_ARG(setfilecon_raw), + DLSYM_ARG(setfscreatecon_raw), + DLSYM_ARG(setsockcreatecon_raw), + DLSYM_ARG(string_to_security_class)); +} #endif bool mac_selinux_use(void) { #if HAVE_SELINUX if (_unlikely_(cached_use < 0)) { - cached_use = is_selinux_enabled() > 0; + if (dlopen_libselinux() < 0) + return (cached_use = false); + + cached_use = sym_is_selinux_enabled() > 0; log_trace("SELinux enabled state cached to: %s", enabled_disabled(cached_use)); } @@ -71,10 +157,13 @@ bool mac_selinux_enforcing(void) { /* If the SELinux status page has been successfully opened, retrieve the enforcing * status over it to avoid system calls in security_getenforce(). */ + if (dlopen_libselinux() < 0) + return false; + if (have_status_page) - r = selinux_status_getenforce(); + r = sym_selinux_status_getenforce(); else - r = security_getenforce(); + r = sym_security_getenforce(); #endif return r != 0; @@ -92,13 +181,18 @@ static int open_label_db(void) { /* Avoid maybe-uninitialized false positives */ usec_t before_timestamp = USEC_INFINITY, after_timestamp = USEC_INFINITY; struct mallinfo2 before_mallinfo = {}; + int r; + + r = dlopen_libselinux(); + if (r < 0) + return r; if (DEBUG_LOGGING) { before_mallinfo = mallinfo2(); before_timestamp = now(CLOCK_MONOTONIC); } - hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + hnd = sym_selabel_open(SELABEL_CTX_FILE, NULL, 0); if (!hnd) return log_selinux_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m"); @@ -113,7 +207,7 @@ static int open_label_db(void) { /* release memory after measurement */ if (label_hnd) - selabel_close(label_hnd); + sym_selabel_close(label_hnd); label_hnd = TAKE_PTR(hnd); return 0; @@ -142,7 +236,7 @@ static int selinux_init(bool force) { mac_selinux_disable_logging(); - r = selinux_status_open(/* netlink fallback= */ 1); + r = sym_selinux_status_open(/* netlink fallback= */ 1); if (r < 0) { if (!ERRNO_IS_PRIVILEGE(errno)) return log_selinux_enforcing_errno(errno, "Failed to open SELinux status page: %m"); @@ -154,7 +248,7 @@ static int selinux_init(bool force) { r = open_label_db(); if (r < 0) { - selinux_status_close(); + sym_selinux_status_close(); return r; } @@ -164,7 +258,7 @@ static int selinux_init(bool force) { /* Save the current policyload sequence number, so mac_selinux_maybe_reload() does not trigger on * first call without any actual change. */ - last_policyload = selinux_status_policyload(); + last_policyload = sym_selinux_status_policyload(); initialized = INITIALIZED; return 1; @@ -203,6 +297,9 @@ void mac_selinux_maybe_reload(void) { if (!initialized) return; + if (dlopen_libselinux() < 0) + return; + /* Do not use selinux_status_updated(3), cause since libselinux 3.2 selinux_check_access(3), * called in core and user instances, does also use it under the hood. * That can cause changes to be consumed by selinux_check_access(3) and not being visible here. @@ -210,7 +307,7 @@ void mac_selinux_maybe_reload(void) { * invoked since libselinux 3.2 by selinux_status_updated(3). * Relevant libselinux commit: https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503 * Debian Bullseye is going to ship libselinux 3.1, so stay compatible for backports. */ - policyload = selinux_status_policyload(); + policyload = sym_selinux_status_policyload(); if (policyload < 0) { log_debug_errno(errno, "Failed to get SELinux policyload from status page: %m"); return; @@ -227,11 +324,13 @@ void mac_selinux_finish(void) { #if HAVE_SELINUX if (label_hnd) { - selabel_close(label_hnd); + sym_selabel_close(label_hnd); label_hnd = NULL; } - selinux_status_close(); + if (sym_selinux_status_close) + sym_selinux_status_close(); + have_status_page = false; initialized = false; @@ -248,7 +347,10 @@ static int selinux_log_glue(int type, const char *fmt, ...) { void mac_selinux_disable_logging(void) { #if HAVE_SELINUX /* Turn off all of SELinux' own logging, we want to do that ourselves */ - selinux_set_callback(SELINUX_CB_LOG, (const union selinux_callback) { .func_log = selinux_log_glue }); + if (dlopen_libselinux() < 0) + return; + + sym_selinux_set_callback(SELINUX_CB_LOG, (const union selinux_callback) { .func_log = selinux_log_glue }); #endif } @@ -274,7 +376,7 @@ static int selinux_fix_fd( if (!label_hnd) return 0; - if (selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) { + if (sym_selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) { /* If there's no label to set, then exit without warning */ if (errno == ENOENT) return 0; @@ -282,11 +384,8 @@ static int selinux_fix_fd( return log_selinux_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path); } - if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) { - _cleanup_freecon_ char *oldcon = NULL; - - r = -errno; - + r = RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon)); + if (r < 0) { /* If the FS doesn't support labels, then exit without warning */ if (ERRNO_IS_NOT_SUPPORTED(r)) return 0; @@ -296,7 +395,8 @@ static int selinux_fix_fd( return 0; /* If the old label is identical to the new one, suppress any kind of error */ - if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(fcon, oldcon)) + _cleanup_freecon_ char *oldcon = NULL; + if (sym_getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(fcon, oldcon)) return 0; return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path); @@ -371,7 +471,7 @@ int mac_selinux_apply(const char *path, const char *label) { assert(label); - if (setfilecon(path, label) < 0) + if (sym_setfilecon_raw(path, label) < 0) return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path); #endif return 0; @@ -390,7 +490,7 @@ int mac_selinux_apply_fd(int fd, const char *path, const char *label) { assert(label); - if (setfilecon(FORMAT_PROC_FD_PATH(fd), label) < 0) + if (sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), label) < 0) return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path)); #endif return 0; @@ -411,21 +511,21 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **ret_label) { if (r == 0) return -EOPNOTSUPP; - if (getcon_raw(&mycon) < 0) + if (sym_getcon_raw(&mycon) < 0) return -errno; if (!mycon) return -EOPNOTSUPP; - if (getfilecon_raw(exe, &fcon) < 0) + if (sym_getfilecon_raw(exe, &fcon) < 0) return -errno; if (!fcon) return -EOPNOTSUPP; - sclass = string_to_security_class("process"); + sclass = sym_string_to_security_class("process"); if (sclass == 0) return -ENOSYS; - return RET_NERRNO(security_compute_create_raw(mycon, fcon, sclass, ret_label)); + return RET_NERRNO(sym_security_compute_create_raw(mycon, fcon, sclass, ret_label)); #else return -EOPNOTSUPP; #endif @@ -444,7 +544,7 @@ int mac_selinux_get_our_label(char **ret_label) { return -EOPNOTSUPP; _cleanup_freecon_ char *con = NULL; - if (getcon_raw(&con) < 0) + if (sym_getcon_raw(&con) < 0) return -errno; if (!con) return -EOPNOTSUPP; @@ -470,7 +570,7 @@ int mac_selinux_get_peer_label(int socket_fd, char **ret_label) { return -EOPNOTSUPP; _cleanup_freecon_ char *con = NULL; - if (getpeercon_raw(socket_fd, &con) < 0) + if (sym_getpeercon_raw(socket_fd, &con) < 0) return -errno; if (!con) return -EOPNOTSUPP; @@ -500,47 +600,47 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * if (r == 0) return -EOPNOTSUPP; - if (getcon_raw(&mycon) < 0) + if (sym_getcon_raw(&mycon) < 0) return -errno; if (!mycon) return -EOPNOTSUPP; - if (getpeercon_raw(socket_fd, &peercon) < 0) + if (sym_getpeercon_raw(socket_fd, &peercon) < 0) return -errno; if (!peercon) return -EOPNOTSUPP; if (!exec_label) { /* If there is no context set for next exec let's use context of target executable */ - if (getfilecon_raw(exe, &fcon) < 0) + if (sym_getfilecon_raw(exe, &fcon) < 0) return -errno; if (!fcon) return -EOPNOTSUPP; } - bcon = context_new(mycon); + bcon = sym_context_new(mycon); if (!bcon) return -ENOMEM; - pcon = context_new(peercon); + pcon = sym_context_new(peercon); if (!pcon) return -ENOMEM; - range = context_range_get(pcon); + range = sym_context_range_get(pcon); if (!range) return -errno; - if (context_range_set(bcon, range) != 0) + if (sym_context_range_set(bcon, range) != 0) return -errno; - bcon_str = context_str(bcon); + bcon_str = sym_context_str(bcon); if (!bcon_str) return -ENOMEM; - sclass = string_to_security_class("process"); + sclass = sym_string_to_security_class("process"); if (sclass == 0) return -ENOSYS; - return RET_NERRNO(security_compute_create_raw(bcon_str, fcon, sclass, ret_label)); + return RET_NERRNO(sym_security_compute_create_raw(bcon_str, fcon, sclass, ret_label)); #else return -EOPNOTSUPP; #endif @@ -563,7 +663,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) if (!label_hnd) return 0; - r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode); + r = sym_selabel_lookup_raw(label_hnd, &filecon, abspath, mode); if (r < 0) { /* No context specified by the policy? Proceed without setting it. */ if (errno == ENOENT) @@ -572,7 +672,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) return log_selinux_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath); } - if (setfscreatecon_raw(filecon) < 0) + if (sym_setfscreatecon_raw(filecon) < 0) return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath); return 0; @@ -625,7 +725,7 @@ int mac_selinux_create_file_prepare_label(const char *path, const char *label) { if (r <= 0) return r; - if (setfscreatecon_raw(label) < 0) + if (sym_setfscreatecon_raw(label) < 0) return log_selinux_enforcing_errno(errno, "Failed to set specified SELinux security context '%s' for '%s': %m", label, strna(path)); #endif return 0; @@ -639,7 +739,7 @@ void mac_selinux_create_file_clear(void) { if (selinux_init(/* force= */ false) <= 0) return; - setfscreatecon_raw(NULL); + (void) sym_setfscreatecon_raw(NULL); #endif } @@ -654,7 +754,7 @@ int mac_selinux_create_socket_prepare(const char *label) { if (r <= 0) return r; - if (setsockcreatecon(label) < 0) + if (sym_setsockcreatecon_raw(label) < 0) return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label); #endif @@ -669,7 +769,7 @@ void mac_selinux_create_socket_clear(void) { if (selinux_init(/* force= */ false) <= 0) return; - setsockcreatecon_raw(NULL); + (void) sym_setsockcreatecon_raw(NULL); #endif } @@ -719,7 +819,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { goto skipped; if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); + r = sym_selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); else { _cleanup_free_ char *newpath = NULL; @@ -727,7 +827,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (r < 0) return r; - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); + r = sym_selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); } if (r < 0) { @@ -739,7 +839,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (r < 0) return r; } else { - if (setfscreatecon_raw(fcon) < 0) { + if (sym_setfscreatecon_raw(fcon) < 0) { r = log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path); if (r < 0) return r; @@ -750,7 +850,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { r = RET_NERRNO(bind(fd, addr, addrlen)); if (context_changed) - (void) setfscreatecon_raw(NULL); + (void) sym_setfscreatecon_raw(NULL); return r; diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h index e97bc40dcca..726cbbea08a 100644 --- a/src/shared/selinux-util.h +++ b/src/shared/selinux-util.h @@ -6,10 +6,58 @@ #include "forward.h" #if HAVE_SELINUX +#include +#include +#include #include /* IWYU pragma: export */ -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, freecon, NULL); +#include "dlfcn-util.h" + +int dlopen_libselinux(void); + +extern DLSYM_PROTOTYPE(avc_open); +extern DLSYM_PROTOTYPE(context_free); +extern DLSYM_PROTOTYPE(context_new); +extern DLSYM_PROTOTYPE(context_range_get); +extern DLSYM_PROTOTYPE(context_range_set); +extern DLSYM_PROTOTYPE(context_str); +extern DLSYM_PROTOTYPE(fgetfilecon_raw); +extern DLSYM_PROTOTYPE(fini_selinuxmnt); +extern DLSYM_PROTOTYPE(freecon); +extern DLSYM_PROTOTYPE(getcon_raw); +extern DLSYM_PROTOTYPE(getfilecon_raw); +extern DLSYM_PROTOTYPE(getpeercon_raw); +extern DLSYM_PROTOTYPE(getpidcon_raw); +extern DLSYM_PROTOTYPE(is_selinux_enabled); +extern DLSYM_PROTOTYPE(security_compute_create_raw); +extern DLSYM_PROTOTYPE(security_getenforce); +extern DLSYM_PROTOTYPE(selabel_close); +extern DLSYM_PROTOTYPE(selabel_lookup_raw); +extern DLSYM_PROTOTYPE(selabel_open); +extern DLSYM_PROTOTYPE(selinux_check_access); +extern DLSYM_PROTOTYPE(selinux_getenforcemode); +extern DLSYM_PROTOTYPE(selinux_init_load_policy); +extern DLSYM_PROTOTYPE(selinux_path); +extern DLSYM_PROTOTYPE(selinux_set_callback); +extern DLSYM_PROTOTYPE(selinux_status_close); +extern DLSYM_PROTOTYPE(selinux_status_getenforce); +extern DLSYM_PROTOTYPE(selinux_status_open); +extern DLSYM_PROTOTYPE(selinux_status_policyload); +extern DLSYM_PROTOTYPE(setcon_raw); +extern DLSYM_PROTOTYPE(setexeccon_raw); +extern DLSYM_PROTOTYPE(setfilecon_raw); +extern DLSYM_PROTOTYPE(setfscreatecon_raw); +extern DLSYM_PROTOTYPE(setsockcreatecon_raw); +extern DLSYM_PROTOTYPE(string_to_security_class); + +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(char*, sym_freecon, freeconp, NULL); + #else + +static inline int dlopen_libselinux(void) { + return -EOPNOTSUPP; +} + static inline void freeconp(char **p) { assert(*p == NULL); } diff --git a/src/systemctl/meson.build b/src/systemctl/meson.build index 2e207966da8..21d57269eba 100644 --- a/src/systemctl/meson.build +++ b/src/systemctl/meson.build @@ -58,7 +58,6 @@ executables += [ 'dependencies' : [ libcap, liblz4_cflags, - libselinux, libxz_cflags, libzstd_cflags, threads, diff --git a/src/test/meson.build b/src/test/meson.build index d95323fc75b..c6b27178a58 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -218,7 +218,7 @@ common_test_dependencies = [ libmount_cflags, librt, libseccomp_cflags, - libselinux, + libselinux_cflags, threads, ] @@ -432,7 +432,7 @@ executables += [ }, test_template + { 'sources' : files('test-selinux.c'), - 'dependencies' : libselinux, + 'dependencies' : libselinux_cflags, }, test_template + { 'sources' : files('test-set-disable-mempool.c'), diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index b677e2b2b33..66efbb0cf7a 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -22,6 +22,7 @@ #include "pkcs11-util.h" #include "qrcode-util.h" #include "seccomp-util.h" +#include "selinux-util.h" #include "tests.h" #include "tpm2-util.h" @@ -60,6 +61,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID); ASSERT_DLOPEN(dlopen_libseccomp, HAVE_SECCOMP); ASSERT_DLOPEN(dlopen_libmount, true); + ASSERT_DLOPEN(dlopen_libselinux, HAVE_SELINUX); return 0; } diff --git a/src/udev/meson.build b/src/udev/meson.build index 4553f2d03e0..62b0f573f5a 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -232,7 +232,7 @@ executables += [ udev_test_template + { 'sources' : files('test-udev-rule-runner.c'), 'dependencies' : udev_dependencies + [ - libselinux, + libselinux_cflags, ], 'type' : 'manual', }, diff --git a/src/udev/test-udev-rule-runner.c b/src/udev/test-udev-rule-runner.c index 97a5b136700..cc870dcdb76 100644 --- a/src/udev/test-udev-rule-runner.c +++ b/src/udev/test-udev-rule-runner.c @@ -103,7 +103,8 @@ static int run(int argc, char *argv[]) { /* Let's make sure the test runs with selinux assumed disabled. */ #if HAVE_SELINUX - fini_selinuxmnt(); + if (dlopen_libselinux() >= 0) + sym_fini_selinuxmnt(); #endif mac_selinux_retest();