]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
libselinux: turn into dlopen() dep
authorLennart Poettering <lennart@poettering.net>
Mon, 8 Sep 2025 16:31:49 +0000 (18:31 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 26 Sep 2025 09:12:04 +0000 (11:12 +0200)
20 files changed:
meson.build
src/core/exec-invoke.c
src/core/load-fragment.c
src/core/meson.build
src/core/selinux-access.c
src/core/selinux-setup.c
src/journal/journald-context.c
src/journal/meson.build
src/nspawn/meson.build
src/nspawn/nspawn.c
src/portable/meson.build
src/portable/portable.c
src/shared/meson.build
src/shared/selinux-util.c
src/shared/selinux-util.h
src/systemctl/meson.build
src/test/meson.build
src/test/test-dlopen-so.c
src/udev/meson.build
src/udev/test-udev-rule-runner.c

index 8ec025c8d6ee49dbc8fe8d478b0b0ef57c7a8b6f..1acf9728d492f8a4df65381edae6f818f658196e 100644 (file)
@@ -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',
index 02931b3223d7b2feebbef5131e5281a2ab835ed9..e02d2ddee6969b1de9e4b82a13173648466968b8 100644 (file)
@@ -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;
index c4ebec160115eb23d5740d8cc3fac41d2fcbdb7e..352ee7d677532d098dc959ed995bd2ae9d29f042 100644 (file)
@@ -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);
 
index fc549ce20f4dca0d0e2895df36b3ede255be16d2..92d6c143d083572aee2f77602b52bfe9ffb5ac2f 100644 (file)
@@ -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 + {
index ad1d2f30803e67fd354ca540049a7aa2d6904363..7d1b2791a7c8ac889ad440c44d589a260ea57eb4 100644 (file)
@@ -4,8 +4,6 @@
 
 #if HAVE_SELINUX
 
-#include <selinux/avc.h>
-#include <selinux/selinux.h>
 #include <unistd.h>
 
 #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",
index db14db88ee33a7c9a9bcd201dd9dbb76afa6f24c..891fa3cd8ec26323143b26d08f3783ef934bf3f4 100644 (file)
@@ -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);
index 1be51436130991f2869e1106f494f6ce187acb1c..5889adc2cec6b87aa96eb18a711bcc5d07aae153 100644 (file)
@@ -1,9 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#if HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -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);
                 }
index c09f38dd91cfadc46a157719e43b1cea0fa69329..364c4ce7bf5926d8567df3f6ed354e84e5465aef 100644 (file)
@@ -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 + {
index 35048462edd4bc7044707c5ecd7a055e7117fcab..1fcf6a3bb072c8aab24c4046e222839761a0c851 100644 (file)
@@ -48,7 +48,7 @@ executables += [
                 'extract' : nspawn_extract_sources,
                 'dependencies' : [
                         libseccomp_cflags,
-                        libselinux,
+                        libselinux_cflags,
                 ],
         },
         nspawn_test_template + {
index a790f2d8a337892eed22bfc2741dd3272c131d44..6bcb0a06a7144eaecb98085b52b3980da707f80e 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
-#if HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
 #include "sd-bus.h"
 #include "sd-daemon.h"
 #include "sd-event.h"
 #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
 
index 06ffa6259a1c48fd04de94bdefb95655bef54218..9c9d04c4614896f2527a17907a413c6ef19483c6 100644 (file)
@@ -29,7 +29,7 @@ executables += [
                 'sources' : systemd_portabled_sources,
                 'link_with' : portabled_link_with,
                 'dependencies' : [
-                        libselinux,
+                        libselinux_cflags,
                         threads,
                 ],
         },
index a2da4d2ab33a3c0f8671442dc057acfcf5e5cc17..503b5b08a266b1d208d1ff3a13e5afe675fcfbb7 100644 (file)
@@ -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) {
index 9acb83a47e7859269f231ab779c9de3fbd7ae46f..f3906305c69eb2623e6ba7ff17abb54f8cc1ecf4 100644 (file)
@@ -328,7 +328,7 @@ libshared_deps = [threads,
                   libpam_cflags,
                   librt,
                   libseccomp_cflags,
-                  libselinux,
+                  libselinux_cflags,
                   libxenctrl_cflags,
                   libxz_cflags,
                   libzstd_cflags]
index f7c4c7d2f8dd2e3427c2c4c6bfcdaf5039b7c26b..4fca62b66d32c4c6d3094a5782181c4fe94dd2df 100644 (file)
@@ -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;
 
index e97bc40dcca769db9c6bb790eeb45b93f3af1862..726cbbea08accb701817ba831d819bec8e38d9cd 100644 (file)
@@ -6,10 +6,58 @@
 #include "forward.h"
 
 #if HAVE_SELINUX
+#include <selinux/avc.h>
+#include <selinux/label.h>
+#include <selinux/context.h>
 #include <selinux/selinux.h> /* 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);
 }
index 2e207966da8b109e4caca533d9ee43346fbc61bf..21d57269eba3b6a470ae8686a4e36a82b28225a7 100644 (file)
@@ -58,7 +58,6 @@ executables += [
                 'dependencies' : [
                         libcap,
                         liblz4_cflags,
-                        libselinux,
                         libxz_cflags,
                         libzstd_cflags,
                         threads,
index d95323fc75b88a791f42a826a95ca394575395d5..c6b27178a58b5add291b349c92243d2db57c14e0 100644 (file)
@@ -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'),
index b677e2b2b33ef53e27b727431d4e1d23c6093ced..66efbb0cf7a0a4ef36792a89c781f304d16b2027 100644 (file)
@@ -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;
 }
index 4553f2d03e075e640b67e93a54d2651a492b6e4b..62b0f573f5acad4f246163edcc1862e2c1a66fac 100644 (file)
@@ -232,7 +232,7 @@ executables += [
         udev_test_template + {
                 'sources' : files('test-udev-rule-runner.c'),
                 'dependencies' : udev_dependencies + [
-                        libselinux,
+                        libselinux_cflags,
                 ],
                 'type' : 'manual',
         },
index 97a5b13670027801e8a044afab387210d49d365f..cc870dcdb76c8f9f47671d65efefb3df2c695864 100644 (file)
@@ -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();