]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
libseccomp: turn into dlopen() dependency
authorLennart Poettering <lennart@poettering.net>
Mon, 8 Sep 2025 15:17:05 +0000 (17:17 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 25 Sep 2025 18:30:11 +0000 (03:30 +0900)
19 files changed:
meson.build
src/analyze/analyze-security.c
src/analyze/meson.build
src/core/exec-invoke.c
src/core/execute.c
src/core/meson.build
src/libsystemd/meson.build
src/nspawn/meson.build
src/nspawn/nspawn-oci.c
src/nspawn/nspawn-seccomp.c
src/nspawn/nspawn-settings.c
src/nspawn/nspawn.c
src/shared/meson.build
src/shared/seccomp-util.c
src/shared/seccomp-util.h
src/test/meson.build
src/test/test-dlopen-so.c
src/test/test-execute.c
src/test/test-seccomp.c

index 1cf49b9fe3ebcebb8b6bd9dcef3b882ecc0c2f2d..ffeef36f6e498a26c68fdf46f4c996b849ffbc13 100644 (file)
@@ -1147,6 +1147,7 @@ libseccomp = dependency('libseccomp',
                         version : '>= 2.3.1',
                         required : get_option('seccomp'))
 conf.set10('HAVE_SECCOMP', libseccomp.found())
+libseccomp_cflags = libseccomp.partial_dependency(includes: true, compile_args: true)
 
 libselinux = dependency('libselinux',
                         version : '>= 2.1.9',
index bdb06dd682c111d7c8903702d3323b4c72f50cc2..a26507ff64db3b00cfc01818ca2430f9c907984c 100644 (file)
@@ -568,7 +568,7 @@ static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilter
                 }
 
                 /* Let's see if the system call actually exists on this platform, before complaining */
-                if (seccomp_syscall_resolve_name(syscall) < 0)
+                if (sym_seccomp_syscall_resolve_name(syscall) < 0)
                         continue;
 
                 if (set_contains(s, syscall) == allow_list) {
@@ -602,6 +602,13 @@ static int assess_system_call_filter(
         uint64_t b;
         int r;
 
+        r = dlopen_libseccomp();
+        if (r < 0) {
+                *ret_badness = UINT64_MAX;
+                *ret_description = NULL;
+                return r;
+        }
+
         if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
                 r = strdup_to(&d, "Service does not filter system calls");
                 b = 10;
@@ -2439,6 +2446,8 @@ static int analyze_security_one(sd_bus *bus,
 
 /* Refactoring SecurityInfo so that it can make use of existing struct variables instead of reading from dbus */
 static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, SecurityInfo **ret_info) {
+        int r;
+
         assert(ret_info);
 
         _cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
@@ -2568,32 +2577,35 @@ static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, Security
                 info->_umask = c->umask;
 
 #if HAVE_SECCOMP
-                SET_FOREACH(key, c->syscall_archs) {
-                        const char *name;
+                r = dlopen_libseccomp();
+                if (r >= 0) {
+                        SET_FOREACH(key, c->syscall_archs) {
+                                const char *name;
 
-                        name = seccomp_arch_to_string(PTR_TO_UINT32(key) - 1);
-                        if (!name)
-                                continue;
+                                name = seccomp_arch_to_string(PTR_TO_UINT32(key) - 1);
+                                if (!name)
+                                        continue;
 
-                        if (set_put_strdup(&info->system_call_architectures, name) < 0)
-                                return log_oom();
-                }
+                                if (set_put_strdup(&info->system_call_architectures, name) < 0)
+                                        return log_oom();
+                        }
 
-                info->system_call_filter_allow_list = c->syscall_allow_list;
+                        info->system_call_filter_allow_list = c->syscall_allow_list;
 
-                void *id, *num;
-                HASHMAP_FOREACH_KEY(num, id, c->syscall_filter) {
-                        _cleanup_free_ char *name = NULL;
+                        void *id, *num;
+                        HASHMAP_FOREACH_KEY(num, id, c->syscall_filter) {
+                                _cleanup_free_ char *name = NULL;
 
-                        if (info->system_call_filter_allow_list && PTR_TO_INT(num) >= 0)
-                                continue;
+                                if (info->system_call_filter_allow_list && PTR_TO_INT(num) >= 0)
+                                        continue;
 
-                        name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
-                        if (!name)
-                                continue;
+                                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                                if (!name)
+                                        continue;
 
-                        if (set_ensure_consume(&info->system_call_filter, &string_hash_ops_free, TAKE_PTR(name)) < 0)
-                                return log_oom();
+                                if (set_ensure_consume(&info->system_call_filter, &string_hash_ops_free, TAKE_PTR(name)) < 0)
+                                        return log_oom();
+                        }
                 }
 #endif
         }
index b1a5b691ce5c4dede74ceacb91ce51e2f11c1978..5b247a70888fe6e31706096ed450fe174a6dc316 100644 (file)
@@ -53,7 +53,7 @@ executables += [
                         libcore,
                         libshared,
                 ],
-                'dependencies' : libseccomp,
+                'dependencies' : libseccomp_cflags,
                 'install' : conf.get('ENABLE_ANALYZE') == 1,
         },
         core_test_template + {
index 2c489dfce40a763538fa9699315037ad530b1572..02931b3223d7b2feebbef5131e5281a2ab835ed9 100644 (file)
@@ -1577,6 +1577,10 @@ static bool seccomp_allows_drop_privileges(const ExecContext *c) {
 
         assert(c);
 
+        /* No libseccomp, all is fine */
+        if (dlopen_libseccomp() < 0)
+                return true;
+
         /* No syscall filter, we are allowed to drop privileges */
         if (hashmap_isempty(c->syscall_filter))
                 return true;
@@ -1584,7 +1588,7 @@ static bool seccomp_allows_drop_privileges(const ExecContext *c) {
         HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
                 _cleanup_free_ char *name = NULL;
 
-                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
 
                 if (streq(name, "capget"))
                         have_capget = true;
index c384e9dd638b81fbff37091a55bfbcb8821ea1d5..6301d51ca2437e0ba8da4de72cdb91bf43b8cd7a 100644 (file)
@@ -1489,27 +1489,29 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                         fputc('~', f);
 
 #if HAVE_SECCOMP
-                void *id, *val;
-                bool first = true;
-                HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
-                        _cleanup_free_ char *name = NULL;
-                        const char *errno_name = NULL;
-                        int num = PTR_TO_INT(val);
-
-                        if (first)
-                                first = false;
-                        else
-                                fputc(' ', f);
-
-                        name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
-                        fputs(strna(name), f);
-
-                        if (num >= 0) {
-                                errno_name = seccomp_errno_or_action_to_string(num);
-                                if (errno_name)
-                                        fprintf(f, ":%s", errno_name);
+                if (dlopen_libseccomp() >= 0) {
+                        void *id, *val;
+                        bool first = true;
+                        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
+                                _cleanup_free_ char *name = NULL;
+                                const char *errno_name = NULL;
+                                int num = PTR_TO_INT(val);
+
+                                if (first)
+                                        first = false;
                                 else
-                                        fprintf(f, ":%d", num);
+                                        fputc(' ', f);
+
+                                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                                fputs(strna(name), f);
+
+                                if (num >= 0) {
+                                        errno_name = seccomp_errno_or_action_to_string(num);
+                                        if (errno_name)
+                                                fprintf(f, ":%s", errno_name);
+                                        else
+                                                fprintf(f, ":%d", num);
+                                }
                         }
                 }
 #endif
@@ -1897,6 +1899,9 @@ char** exec_context_get_syscall_filter(const ExecContext *c) {
         assert(c);
 
 #if HAVE_SECCOMP
+        if (dlopen_libseccomp() < 0)
+                return strv_new(NULL);
+
         void *id, *val;
         HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
                 _cleanup_free_ char *name = NULL;
@@ -1908,7 +1913,7 @@ char** exec_context_get_syscall_filter(const ExecContext *c) {
                         /* syscall with num >= 0 in allow-list is denied. */
                         continue;
 
-                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
                 if (!name)
                         continue;
 
@@ -1965,11 +1970,14 @@ char** exec_context_get_syscall_log(const ExecContext *c) {
         assert(c);
 
 #if HAVE_SECCOMP
+        if (dlopen_libseccomp() < 0)
+                return strv_new(NULL);
+
         void *id, *val;
         HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
                 char *name = NULL;
 
-                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
                 if (!name)
                         continue;
 
index 1879af4da41c91e152ff3625c559dd5385a8d7a5..1d897a0ddc3551bed2887503e5aad3d43d69c954 100644 (file)
@@ -136,7 +136,7 @@ libcore_static = static_library(
                         libm,
                         libmount,
                         librt,
-                        libseccomp,
+                        libseccomp_cflags,
                         libselinux,
                         threads,
                         userspace],
@@ -199,7 +199,7 @@ executables += [
                 'dependencies' : [
                         libapparmor_cflags,
                         libkmod_cflags,
-                        libseccomp,
+                        libseccomp_cflags,
                         libselinux,
                 ],
         },
@@ -212,7 +212,7 @@ executables += [
                 'dependencies' : [
                         libapparmor_cflags,
                         libpam_cflags,
-                        libseccomp,
+                        libseccomp_cflags,
                         libselinux,
                 ],
         },
index 1cec32523896609e0cff02919664bb531f26f91e..ec1ac471d9b1e0066681ccd79ebfd7eac96dfbe3 100644 (file)
@@ -229,7 +229,7 @@ libsystemd_tests += [
         },
         {
                 'sources' : files('sd-bus/test-bus-cleanup.c'),
-                'dependencies' : [threads, libseccomp],
+                'dependencies' : [threads, libseccomp_cflags],
         },
         {
                 'sources' : files('sd-bus/test-bus-marshal.c'),
@@ -264,7 +264,7 @@ libsystemd_tests += [
         },
         {
                 'sources' : files('sd-bus/test-bus-track.c'),
-                'dependencies' : libseccomp,
+                'dependencies' : libseccomp_cflags,
         },
         {
                 'sources' : files('sd-bus/test-bus-watch-bind.c'),
index b49d7153384b23b0874f806fe0eb15f8504946f1..35048462edd4bc7044707c5ecd7a055e7117fcab 100644 (file)
@@ -30,7 +30,7 @@ generated_sources += nspawn_gperf_c
 nspawn_extract_sources += nspawn_gperf_c
 
 nspawn_common_template = {
-        'dependencies' : libseccomp,
+        'dependencies' : libseccomp_cflags,
         'objects' : ['systemd-nspawn'],
 }
 nspawn_test_template = test_template + nspawn_common_template
@@ -47,7 +47,7 @@ executables += [
                 ],
                 'extract' : nspawn_extract_sources,
                 'dependencies' : [
-                        libseccomp,
+                        libseccomp_cflags,
                         libselinux,
                 ],
         },
index 476dad08eb8491452729aa9c51adb297a7b2a76c..073f0f3ea944ec312471a0f5c56e83cd38c9f092 100644 (file)
@@ -1691,7 +1691,7 @@ static int oci_seccomp_archs(const char *name, sd_json_variant *v, sd_json_dispa
                 if (r < 0)
                         return json_log(e, flags, r, "Unknown architecture: %s", sd_json_variant_string(e));
 
-                r = seccomp_arch_add(sc, a);
+                r = sym_seccomp_arch_add(sc, a);
                 if (r == -EEXIST)
                         continue;
                 if (r < 0)
@@ -1810,13 +1810,13 @@ static int oci_seccomp_syscalls(const char *name, sd_json_variant *v, sd_json_di
                 STRV_FOREACH(i, rule.names) {
                         int nr;
 
-                        nr = seccomp_syscall_resolve_name(*i);
+                        nr = sym_seccomp_syscall_resolve_name(*i);
                         if (nr == __NR_SCMP_ERROR) {
                                 log_debug("Unknown syscall %s, skipping.", *i);
                                 continue;
                         }
 
-                        r = seccomp_rule_add_array(sc, rule.action, nr, rule.n_arguments, rule.arguments);
+                        r = sym_seccomp_rule_add_array(sc, rule.action, nr, rule.n_arguments, rule.arguments);
                         if (r < 0)
                                 return r;
                 }
@@ -1853,7 +1853,11 @@ static int oci_seccomp(const char *name, sd_json_variant *v, sd_json_dispatch_fl
         if (r < 0)
                 return json_log(def, flags, r, "Unknown default action: %s", sd_json_variant_string(def));
 
-        sc = seccomp_init(d);
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return json_log(def, flags, r, "No support for libseccomp: %m");
+
+        sc = sym_seccomp_init(d);
         if (!sc)
                 return json_log(v, flags, SYNTHETIC_ERRNO(ENOMEM), "Couldn't allocate seccomp object.");
 
@@ -1861,7 +1865,7 @@ static int oci_seccomp(const char *name, sd_json_variant *v, sd_json_dispatch_fl
         if (r < 0)
                 return r;
 
-        seccomp_release(s->seccomp);
+        sym_seccomp_release(s->seccomp);
         s->seccomp = TAKE_PTR(sc);
         return 0;
 #else
index 6956689ab5701f6ab0d4e547c0b15cff633e6426..cf55c6c7332851acdea0f674833061c45096f470 100644 (file)
@@ -163,7 +163,7 @@ static int add_syscall_filters(
 
 #if (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 5) || SCMP_VER_MAJOR > 2
         /* We have a large filter here, so let's turn on the binary tree mode if possible. */
-        r = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_OPTIMIZE, 2);
+        r = sym_seccomp_attr_set(ctx, SCMP_FLTATR_CTL_OPTIMIZE, 2);
         if (r < 0)
                 log_warning_errno(r, "Failed to set SCMP_FLTATR_CTL_OPTIMIZE, ignoring: %m");
 #endif
@@ -195,7 +195,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_list, char **sy
                 if (r < 0)
                         return r;
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return log_error_errno(r, "Failed to install seccomp filter: %m");
                 if (r < 0)
@@ -220,7 +220,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_list, char **sy
                   as indication that audit is disabled in the kernel.
                 */
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                 SCMP_SYS(socket),
@@ -232,7 +232,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_list, char **sy
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return log_error_errno(r, "Failed to install seccomp audit filter: %m");
                 if (r < 0)
index 166c420c5d87ee24a9458b3031d3cd7bd6daa3e6..e4f4f5ebf114ce7c1a9b0d122dc81e9229e4f8fa 100644 (file)
@@ -167,7 +167,8 @@ Settings* settings_free(Settings *s) {
         strv_free(s->sysctl);
 
 #if HAVE_SECCOMP
-        seccomp_release(s->seccomp);
+        if (s->seccomp)
+                sym_seccomp_release(s->seccomp);
 #endif
 
         return mfree(s);
index c392c22916c6f64188c44b3322abd62a3eb8bc8a..adc550ed2447514b4ba8d433ab17758230824a6f 100644 (file)
@@ -3507,7 +3507,7 @@ static int inner_child(
         if (arg_seccomp) {
 
                 if (is_seccomp_available()) {
-                        r = seccomp_load(arg_seccomp);
+                        r = sym_seccomp_load(arg_seccomp);
                         if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                                 return log_error_errno(r, "Failed to install seccomp filter: %m");
                         if (r < 0)
@@ -4835,7 +4835,7 @@ static int merge_settings(Settings *settings, const char *path) {
                         if (!arg_settings_trusted)
                                 log_warning("Ignoring SECCOMP filter, file %s is not trusted.", path);
                         else {
-                                seccomp_release(arg_seccomp);
+                                sym_seccomp_release(arg_seccomp);
                                 arg_seccomp = TAKE_PTR(settings->seccomp);
                         }
                 }
index 92a5b1ddf2f9d62380d9e2bfcd04eb100b69c0de..2dbf8c961c8afb80ff99c79e6b125d1c03dba00f 100644 (file)
@@ -327,7 +327,7 @@ libshared_deps = [threads,
                   libp11kit_cflags,
                   libpam_cflags,
                   librt,
-                  libseccomp,
+                  libseccomp_cflags,
                   libselinux,
                   libxenctrl_cflags,
                   libxz_cflags,
index bfe4ca91698e8ef26dbf7d9396f615123aba9bbb..0f4c692613cfc7f159dac30777d9ae27e55a4f58 100644 (file)
 #include "strv.h"
 
 #if HAVE_SECCOMP
+static void *libseccomp_dl = NULL;
+
+DLSYM_PROTOTYPE(seccomp_api_get) = NULL;
+DLSYM_PROTOTYPE(seccomp_arch_add) = NULL;
+DLSYM_PROTOTYPE(seccomp_arch_exist) = NULL;
+DLSYM_PROTOTYPE(seccomp_arch_native) = NULL;
+DLSYM_PROTOTYPE(seccomp_arch_remove) = NULL;
+DLSYM_PROTOTYPE(seccomp_attr_set) = NULL;
+DLSYM_PROTOTYPE(seccomp_init) = NULL;
+DLSYM_PROTOTYPE(seccomp_load) = NULL;
+DLSYM_PROTOTYPE(seccomp_release) = NULL;
+DLSYM_PROTOTYPE(seccomp_rule_add_array) = NULL;
+DLSYM_PROTOTYPE(seccomp_rule_add_exact) = NULL;
+DLSYM_PROTOTYPE(seccomp_syscall_resolve_name) = NULL;
+DLSYM_PROTOTYPE(seccomp_syscall_resolve_num_arch) = NULL;
+
+int dlopen_libseccomp(void) {
+        ELF_NOTE_DLOPEN("seccomp",
+                        "Support for Seccomp Sandboxes",
+                        ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+                        "libseccomp.so.2");
+
+        return dlopen_many_sym_or_warn(
+                        &libseccomp_dl,
+                        "libseccomp.so.2",
+                        LOG_DEBUG,
+                        DLSYM_ARG(seccomp_api_get),
+                        DLSYM_ARG(seccomp_arch_add),
+                        DLSYM_ARG(seccomp_arch_exist),
+                        DLSYM_ARG(seccomp_arch_native),
+                        DLSYM_ARG(seccomp_arch_remove),
+                        DLSYM_ARG(seccomp_attr_set),
+                        DLSYM_ARG(seccomp_init),
+                        DLSYM_ARG(seccomp_load),
+                        DLSYM_ARG(seccomp_release),
+                        DLSYM_ARG(seccomp_rule_add_array),
+                        DLSYM_ARG(seccomp_rule_add_exact),
+                        DLSYM_ARG(seccomp_syscall_resolve_name),
+                        DLSYM_ARG(seccomp_syscall_resolve_num_arch));
+}
 
 /* This array will be modified at runtime as seccomp_restrict_archs is called. */
 uint32_t seccomp_local_archs[] = {
@@ -246,40 +286,44 @@ int seccomp_init_for_arch(scmp_filter_ctx *ret, uint32_t arch, uint32_t default_
         /* Much like seccomp_init(), but initializes the filter for one specific architecture only, without affecting
          * any others. Also, turns off the NNP fiddling. */
 
-        seccomp = seccomp_init(default_action);
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
+        seccomp = sym_seccomp_init(default_action);
         if (!seccomp)
                 return -ENOMEM;
 
         if (arch != SCMP_ARCH_NATIVE &&
-            arch != seccomp_arch_native()) {
+            arch != sym_seccomp_arch_native()) {
 
-                r = seccomp_arch_remove(seccomp, seccomp_arch_native());
+                r = sym_seccomp_arch_remove(seccomp, sym_seccomp_arch_native());
                 if (r < 0)
                         return r;
 
-                r = seccomp_arch_add(seccomp, arch);
+                r = sym_seccomp_arch_add(seccomp, arch);
                 if (r < 0)
                         return r;
 
-                assert(seccomp_arch_exist(seccomp, arch) >= 0);
-                assert(seccomp_arch_exist(seccomp, SCMP_ARCH_NATIVE) == -EEXIST);
-                assert(seccomp_arch_exist(seccomp, seccomp_arch_native()) == -EEXIST);
+                assert(sym_seccomp_arch_exist(seccomp, arch) >= 0);
+                assert(sym_seccomp_arch_exist(seccomp, SCMP_ARCH_NATIVE) == -EEXIST);
+                assert(sym_seccomp_arch_exist(seccomp, sym_seccomp_arch_native()) == -EEXIST);
         } else {
-                assert(seccomp_arch_exist(seccomp, SCMP_ARCH_NATIVE) >= 0);
-                assert(seccomp_arch_exist(seccomp, seccomp_arch_native()) >= 0);
+                assert(sym_seccomp_arch_exist(seccomp, SCMP_ARCH_NATIVE) >= 0);
+                assert(sym_seccomp_arch_exist(seccomp, sym_seccomp_arch_native()) >= 0);
         }
 
-        r = seccomp_attr_set(seccomp, SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_ALLOW);
+        r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_ALLOW);
         if (r < 0)
                 return r;
 
-        r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
+        r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
         if (r < 0)
                 return r;
 
 #if SCMP_VER_MAJOR >= 3 || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 4)
         if (getenv_bool("SYSTEMD_LOG_SECCOMP") > 0) {
-                r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_LOG, 1);
+                r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_LOG, 1);
                 if (r < 0)
                         log_debug_errno(r, "Failed to enable seccomp event logging: %m");
         }
@@ -302,9 +346,10 @@ bool is_seccomp_available(void) {
         static int cached_enabled = -1;
 
         if (cached_enabled < 0) {
-                int b;
+                if (dlopen_libseccomp() < 0)
+                        return (cached_enabled = false);
 
-                b = secure_getenv_bool("SYSTEMD_SECCOMP");
+                int b = secure_getenv_bool("SYSTEMD_SECCOMP");
                 if (b != 0) {
                         if (b < 0 && b != -ENXIO) /* ENXIO: env var unset */
                                 log_debug_errno(b, "Failed to parse $SYSTEMD_SECCOMP value, ignoring.");
@@ -1049,14 +1094,18 @@ int seccomp_add_syscall_filter_item(
         } else {
                 int id, r;
 
-                id = seccomp_syscall_resolve_name(name);
+                r = dlopen_libseccomp();
+                if (r < 0)
+                        return r;
+
+                id = sym_seccomp_syscall_resolve_name(name);
                 if (id == __NR_SCMP_ERROR) {
                         if (log_missing)
                                 log_debug("System call %s is not known, ignoring.", name);
                         return 0;
                 }
 
-                r = seccomp_rule_add_exact(seccomp, action, id, 0);
+                r = sym_seccomp_rule_add_exact(seccomp, action, id, 0);
                 if (r < 0) {
                         /* If the system call is not known on this architecture, then that's fine, let's ignore it */
                         bool ignore = r == -EDOM;
@@ -1127,6 +1176,10 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
         /* The one-stop solution: allocate a seccomp object, add the specified filter to it, and apply it. Once for
          * each local arch. */
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         default_action_override = override_default_action(default_action);
 
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
@@ -1147,7 +1200,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
                         NULSTR_FOREACH(name, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value) {
                                 int id;
 
-                                id = seccomp_syscall_resolve_name(name);
+                                id = sym_seccomp_syscall_resolve_name(name);
                                 if (id < 0)
                                         continue;
 
@@ -1155,7 +1208,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
                                 if (strv_contains(added, name))
                                         continue;
 
-                                r = seccomp_rule_add_exact(seccomp, default_action, id, 0);
+                                r = sym_seccomp_rule_add_exact(seccomp, default_action, id, 0);
                                 if (r < 0 && r != -EDOM)  /* EDOM means that the syscall is not available for arch */
                                         return log_debug_errno(r, "Failed to add rule for system call %s() / %d: %m",
                                                                name, id);
@@ -1163,12 +1216,12 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
 
 #if (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 5) || SCMP_VER_MAJOR > 2
                 /* We have a large filter here, so let's turn on the binary tree mode if possible. */
-                r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_OPTIMIZE, 2);
+                r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_OPTIMIZE, 2);
                 if (r < 0)
                         log_warning_errno(r, "Failed to set SCMP_FLTATR_CTL_OPTIMIZE, ignoring: %m");
 #endif
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1189,6 +1242,10 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
         if (hashmap_isempty(filter) && default_action == SCMP_ACT_ALLOW)
                 return 0;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         default_action_override = override_default_action(default_action);
 
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
@@ -1215,14 +1272,14 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
                         else if (error >= 0)
                                 a = SCMP_ACT_ERRNO(error);
 
-                        r = seccomp_rule_add_exact(seccomp, a, id, 0);
+                        r = sym_seccomp_rule_add_exact(seccomp, a, id, 0);
                         if (r < 0) {
                                 /* If the system call is not known on this architecture, then that's
                                  * fine, let's ignore it */
                                 _cleanup_free_ char *n = NULL;
                                 bool ignore;
 
-                                n = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, id);
+                                n = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, id);
                                 ignore = r == -EDOM;
                                 if (!ignore || log_missing)
                                         log_debug_errno(r, "Failed to add rule for system call %s() / %d%s: %m",
@@ -1236,7 +1293,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
                         NULSTR_FOREACH(name, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value) {
                                 int id;
 
-                                id = seccomp_syscall_resolve_name(name);
+                                id = sym_seccomp_syscall_resolve_name(name);
                                 if (id < 0)
                                         continue;
 
@@ -1244,7 +1301,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
                                 if (hashmap_contains(filter, INT_TO_PTR(id + 1)))
                                         continue;
 
-                                r = seccomp_rule_add_exact(seccomp, default_action, id, 0);
+                                r = sym_seccomp_rule_add_exact(seccomp, default_action, id, 0);
                                 if (r < 0 && r != -EDOM)  /* EDOM means that the syscall is not available for arch */
                                         return log_debug_errno(r, "Failed to add rule for system call %s() / %d: %m",
                                                                name, id);
@@ -1252,12 +1309,12 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
 
 #if (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 5) || SCMP_VER_MAJOR > 2
                 /* We have a large filter here, so let's turn on the binary tree mode if possible. */
-                r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_OPTIMIZE, 2);
+                r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_OPTIMIZE, 2);
                 if (r < 0)
                         log_warning_errno(r, "Failed to set SCMP_FLTATR_CTL_OPTIMIZE, ignoring: %m");
 #endif
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1310,7 +1367,17 @@ int seccomp_parse_syscall_filter(
         } else {
                 int id;
 
-                id = seccomp_syscall_resolve_name(name);
+                r = dlopen_libseccomp();
+                if (r < 0) {
+                        if (!FLAGS_SET(flags, SECCOMP_PARSE_PERMISSIVE))
+                                return r;
+
+                        log_syntax(unit, FLAGS_SET(flags, SECCOMP_PARSE_LOG) ? LOG_WARNING : LOG_DEBUG, filename, line, r,
+                                   "System call %s cannot be resolved as libseccomp is not available, ignoring: %m", name);
+                        return 0;
+                }
+
+                id = sym_seccomp_syscall_resolve_name(name);
                 if (id == __NR_SCMP_ERROR) {
                         if (!FLAGS_SET(flags, SECCOMP_PARSE_PERMISSIVE))
                                 return -EINVAL;
@@ -1358,6 +1425,10 @@ int seccomp_restrict_namespaces(unsigned long retain) {
         if (FLAGS_SET(retain, NAMESPACE_FLAGS_ALL))
                 return 0;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -1374,7 +1445,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                  * C.f. https://github.com/flatpak/flatpak/commit/a10f52a7565c549612c92b8e736a6698a53db330,
                  * https://github.com/moby/moby/issues/42680. */
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(ENOSYS),
                                 SCMP_SYS(clone3),
@@ -1386,7 +1457,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                 if ((retain & NAMESPACE_FLAGS_ALL) == 0)
                         /* If every single kind of namespace shall be prohibited, then let's block the whole
                          * setns() syscall altogether. */
-                        r = seccomp_rule_add_exact(
+                        r = sym_seccomp_rule_add_exact(
                                         seccomp,
                                         SCMP_ACT_ERRNO(EPERM),
                                         SCMP_SYS(setns),
@@ -1394,7 +1465,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                 else
                         /* Otherwise, block only the invocations with the appropriate flags in the loop
                          * below, but also the special invocation with a zero flags argument, right here. */
-                        r = seccomp_rule_add_exact(
+                        r = sym_seccomp_rule_add_exact(
                                         seccomp,
                                         SCMP_ACT_ERRNO(EPERM),
                                         SCMP_SYS(setns),
@@ -1417,7 +1488,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
 
                         log_trace("Blocking %s.", namespace_info[i].proc_name);
 
-                        r = seccomp_rule_add_exact(
+                        r = sym_seccomp_rule_add_exact(
                                         seccomp,
                                         SCMP_ACT_ERRNO(EPERM),
                                         SCMP_SYS(unshare),
@@ -1431,14 +1502,14 @@ int seccomp_restrict_namespaces(unsigned long retain) {
 
                         /* On s390/s390x the first two parameters to clone are switched */
                         if (!IN_SET(arch, SCMP_ARCH_S390, SCMP_ARCH_S390X))
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EPERM),
                                                 SCMP_SYS(clone),
                                                 1,
                                                 SCMP_A0(SCMP_CMP_MASKED_EQ, f, f));
                         else
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EPERM),
                                                 SCMP_SYS(clone),
@@ -1451,7 +1522,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                         }
 
                         if ((retain & NAMESPACE_FLAGS_ALL) != 0) {
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EPERM),
                                                 SCMP_SYS(setns),
@@ -1467,7 +1538,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
                 if (r < 0)
                         continue;
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1482,6 +1553,10 @@ int seccomp_protect_sysctl(void) {
         uint32_t arch;
         int r;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -1504,7 +1579,7 @@ int seccomp_protect_sysctl(void) {
                 if (r < 0)
                         return r;
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EPERM),
                                 SCMP_SYS(_sysctl),
@@ -1515,7 +1590,7 @@ int seccomp_protect_sysctl(void) {
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1530,6 +1605,10 @@ int seccomp_protect_syslog(void) {
         uint32_t arch;
         int r;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -1537,7 +1616,7 @@ int seccomp_protect_syslog(void) {
                 if (r < 0)
                         return r;
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EPERM),
                                 SCMP_SYS(syslog),
@@ -1548,7 +1627,7 @@ int seccomp_protect_syslog(void) {
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1563,6 +1642,10 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
         uint32_t arch;
         int r;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
                 bool supported;
@@ -1642,7 +1725,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                         if (first == 0) {
 
                                 /* No entries in the valid range, block everything */
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                                 SCMP_SYS(socket),
@@ -1656,7 +1739,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                         } else {
 
                                 /* Block everything below the first entry */
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                                 SCMP_SYS(socket),
@@ -1669,7 +1752,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                                 }
 
                                 /* Block everything above the last entry */
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                                 SCMP_SYS(socket),
@@ -1687,7 +1770,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                                         if (set_contains(address_families, INT_TO_PTR(af)))
                                                 continue;
 
-                                        r = seccomp_rule_add_exact(
+                                        r = sym_seccomp_rule_add_exact(
                                                         seccomp,
                                                         SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                                         SCMP_SYS(socket),
@@ -1710,7 +1793,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                          * then combined in OR checks. */
 
                         SET_FOREACH(af, address_families) {
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(EAFNOSUPPORT),
                                                 SCMP_SYS(socket),
@@ -1726,7 +1809,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
                         }
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1749,6 +1832,10 @@ int seccomp_restrict_realtime_full(int error_code) {
 
         assert(error_code > 0);
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         /* Determine the highest policy constant we want to allow */
         FOREACH_ELEMENT(policy, permitted_policies)
                 if (*policy > max_policy)
@@ -1780,7 +1867,7 @@ int seccomp_restrict_realtime_full(int error_code) {
                                 continue;
 
                         /* Deny this policy */
-                        r = seccomp_rule_add_exact(
+                        r = sym_seccomp_rule_add_exact(
                                         seccomp,
                                         SCMP_ACT_ERRNO(error_code),
                                         SCMP_SYS(sched_setscheduler),
@@ -1795,7 +1882,7 @@ int seccomp_restrict_realtime_full(int error_code) {
 
                 /* Deny-list all other policies, i.e. the ones with higher values. Note that all comparisons
                  * are unsigned here, hence no need no check for < 0 values. */
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(error_code),
                                 SCMP_SYS(sched_setscheduler),
@@ -1807,7 +1894,7 @@ int seccomp_restrict_realtime_full(int error_code) {
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1825,11 +1912,11 @@ static int add_seccomp_syscall_filter(scmp_filter_ctx seccomp,
                                       const struct scmp_arg_cmp arg) {
         int r;
 
-        r = seccomp_rule_add_exact(seccomp, SCMP_ACT_ERRNO(EPERM), nr, arg_cnt, arg);
+        r = sym_seccomp_rule_add_exact(seccomp, SCMP_ACT_ERRNO(EPERM), nr, arg_cnt, arg);
         if (r < 0) {
                 _cleanup_free_ char *n = NULL;
 
-                n = seccomp_syscall_resolve_num_arch(arch, nr);
+                n = sym_seccomp_syscall_resolve_num_arch(arch, nr);
                 log_debug_errno(r, "Failed to add %s() rule for architecture %s, skipping: %m",
                                 strna(n),
                                 seccomp_arch_to_string(arch));
@@ -1848,10 +1935,15 @@ assert_cc(SCMP_SYS(shmdt) > 0);
 int seccomp_memory_deny_write_execute(void) {
         uint32_t arch;
         unsigned loaded = 0;
+        int r;
+
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
 
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
-                int filter_syscall = 0, block_syscall = 0, shmat_syscall = 0, r;
+                int filter_syscall = 0, block_syscall = 0, shmat_syscall = 0;
 
                 log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch));
 
@@ -1945,7 +2037,7 @@ int seccomp_memory_deny_write_execute(void) {
                                 continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -1965,6 +2057,10 @@ int seccomp_restrict_archs(Set *archs) {
         int r;
         bool blocked_new = false;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         /* This installs a filter with no rules, but that restricts the system call architectures to the specified
          * list.
          *
@@ -1975,7 +2071,7 @@ int seccomp_restrict_archs(Set *archs) {
         /* Note libseccomp includes our "native" (current) architecture in the filter by default.
          * We do not remove it. For example, our callers expect to be able to call execve() afterwards
          * to run a program with the restrictions applied. */
-        seccomp = seccomp_init(SCMP_ACT_ALLOW);
+        seccomp = sym_seccomp_init(SCMP_ACT_ALLOW);
         if (!seccomp)
                 return -ENOMEM;
 
@@ -1983,7 +2079,7 @@ int seccomp_restrict_archs(Set *archs) {
                 uint32_t arch = seccomp_local_archs[i];
 
                 /* See above comment, our "native" architecture is never blocked. */
-                if (arch == seccomp_arch_native())
+                if (arch == sym_seccomp_arch_native())
                         continue;
 
                 /* That architecture might have already been blocked by a previous call to seccomp_restrict_archs. */
@@ -1996,14 +2092,14 @@ int seccomp_restrict_archs(Set *archs) {
                  * x32 syscalls should basically match x86-64 for everything except the pointer type.
                  * The important thing is that you can block the old 32-bit x86 syscalls.
                  * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */
-                if (block && arch == SCMP_ARCH_X86_64 && seccomp_arch_native() == SCMP_ARCH_X32)
+                if (block && arch == SCMP_ARCH_X86_64 && sym_seccomp_arch_native() == SCMP_ARCH_X32)
                         block = !set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1));
 
                 if (block) {
                         seccomp_local_archs[i] = SECCOMP_LOCAL_ARCH_BLOCKED;
                         blocked_new = true;
                 } else {
-                        r = seccomp_arch_add(seccomp, arch);
+                        r = sym_seccomp_arch_add(seccomp, arch);
                         if (r < 0 && r != -EEXIST)
                                 return r;
                 }
@@ -2014,11 +2110,11 @@ int seccomp_restrict_archs(Set *archs) {
         if (!blocked_new)
                 return 0;
 
-        r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
+        r = sym_seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
         if (r < 0)
                 return r;
 
-        r = seccomp_load(seccomp);
+        r = sym_seccomp_load(seccomp);
         if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                 return r;
         if (r < 0)
@@ -2049,9 +2145,15 @@ int parse_syscall_archs(char **l, Set **archs) {
 }
 
 int seccomp_filter_set_add_by_name(Hashmap *filter, bool add, const char *name) {
+        int r;
+
         assert(filter);
         assert(name);
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         if (name[0] == '@') {
                 const SyscallFilterSet *more;
 
@@ -2062,7 +2164,7 @@ int seccomp_filter_set_add_by_name(Hashmap *filter, bool add, const char *name)
                 return seccomp_filter_set_add(filter, add, more);
         }
 
-        int id = seccomp_syscall_resolve_name(name);
+        int id = sym_seccomp_syscall_resolve_name(name);
         if (id == __NR_SCMP_ERROR) {
                 log_debug("System call %s is not known, ignoring.", name);
                 return 0;
@@ -2097,6 +2199,10 @@ int seccomp_lock_personality(unsigned long personality) {
         if (personality >= PERSONALITY_INVALID)
                 return -EINVAL;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -2104,7 +2210,7 @@ int seccomp_lock_personality(unsigned long personality) {
                 if (r < 0)
                         return r;
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EPERM),
                                 SCMP_SYS(personality),
@@ -2116,7 +2222,7 @@ int seccomp_lock_personality(unsigned long personality) {
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -2131,6 +2237,10 @@ int seccomp_protect_hostname(void) {
         uint32_t arch;
         int r;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -2138,7 +2248,7 @@ int seccomp_protect_hostname(void) {
                 if (r < 0)
                         return r;
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EPERM),
                                 SCMP_SYS(sethostname),
@@ -2149,7 +2259,7 @@ int seccomp_protect_hostname(void) {
                         continue;
                 }
 
-                r = seccomp_rule_add_exact(
+                r = sym_seccomp_rule_add_exact(
                                 seccomp,
                                 SCMP_ACT_ERRNO(EPERM),
                                 SCMP_SYS(setdomainname),
@@ -2160,7 +2270,7 @@ int seccomp_protect_hostname(void) {
                         continue;
                 }
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -2184,7 +2294,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         int r;
         bool any = false;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(chmod),
@@ -2195,7 +2305,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(fchmod),
@@ -2206,7 +2316,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(fchmodat),
@@ -2218,7 +2328,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
                 any = true;
 
 #if defined(__SNR_fchmodat2)
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(fchmodat2),
@@ -2228,7 +2338,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         /* It looks like this libseccomp does not know about fchmodat2().
          * Pretend the fchmodat2() system call is not supported at all,
          * regardless of the kernel version. */
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(ENOSYS),
                         __NR_fchmodat2,
@@ -2239,7 +2349,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(mkdir),
@@ -2250,7 +2360,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(mkdirat),
@@ -2261,7 +2371,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(mknod),
@@ -2272,7 +2382,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(mknodat),
@@ -2283,7 +2393,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(open),
@@ -2295,7 +2405,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(openat),
@@ -2314,7 +2424,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
          * compatible with kernels that are not absolutely recent. We would normally return EPERM for a
          * policy check, but this isn't strictly a policy check. Instead, we return ENOSYS to force programs
          * to call open() or openat() instead. We can properly enforce policy for those functions. */
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(ENOSYS),
                         SCMP_SYS(openat2),
@@ -2325,7 +2435,7 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
                 any = true;
 #endif
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EPERM),
                         SCMP_SYS(creat),
@@ -2343,6 +2453,10 @@ int seccomp_restrict_suid_sgid(void) {
         uint32_t arch;
         int r, k;
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -2363,7 +2477,7 @@ int seccomp_restrict_suid_sgid(void) {
                 if (r < 0 && k < 0)
                         continue;
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
@@ -2382,7 +2496,7 @@ uint32_t scmp_act_kill_process(void) {
          * for single-threaded apps does the right thing. */
 
 #ifdef SCMP_ACT_KILL_PROCESS
-        if (seccomp_api_get() >= 3)
+        if (dlopen_libseccomp() >= 0 && sym_seccomp_api_get() >= 3)
                 return SCMP_ACT_KILL_PROCESS;
 #endif
 
@@ -2434,7 +2548,7 @@ static int block_open_flag(scmp_filter_ctx seccomp, int flag) {
         /* Blocks open() with the specified flag, where flag is O_SYNC or so. This makes these calls return
          * EINVAL, in the hope the client code will retry without O_SYNC then.  */
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EINVAL),
                         SCMP_SYS(open),
@@ -2445,7 +2559,7 @@ static int block_open_flag(scmp_filter_ctx seccomp, int flag) {
         else
                 any = true;
 
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(EINVAL),
                         SCMP_SYS(openat),
@@ -2458,7 +2572,7 @@ static int block_open_flag(scmp_filter_ctx seccomp, int flag) {
 
 #if defined(__SNR_openat2)
         /* The new openat2() system call can't be filtered sensibly, see above. */
-        r = seccomp_rule_add_exact(
+        r = sym_seccomp_rule_add_exact(
                         seccomp,
                         SCMP_ACT_ERRNO(ENOSYS),
                         SCMP_SYS(openat2),
@@ -2481,6 +2595,10 @@ int seccomp_suppress_sync(void) {
          *
          * Additionally, O_SYNC/O_DSYNC are masked. */
 
+        r = dlopen_libseccomp();
+        if (r < 0)
+                return r;
+
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
 
@@ -2491,14 +2609,14 @@ int seccomp_suppress_sync(void) {
                 NULSTR_FOREACH(c, syscall_filter_sets[SYSCALL_FILTER_SET_SYNC].value) {
                         int id;
 
-                        id = seccomp_syscall_resolve_name(c);
+                        id = sym_seccomp_syscall_resolve_name(c);
                         if (id == __NR_SCMP_ERROR) {
                                 log_debug("System call %s is not known, ignoring.", c);
                                 continue;
                         }
 
                         if (STR_IN_SET(c, "fdatasync", "fsync", "sync_file_range", "sync_file_range2", "syncfs"))
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
                                                 id,
@@ -2507,7 +2625,7 @@ int seccomp_suppress_sync(void) {
                                                                                  * means non-negative fd matches the rule, and the negative
                                                                                  * fd passed to the syscall (then it fails with EBADF). */
                         else
-                                r = seccomp_rule_add_exact(
+                                r = sym_seccomp_rule_add_exact(
                                                 seccomp,
                                                 SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
                                                 id,
@@ -2521,7 +2639,7 @@ int seccomp_suppress_sync(void) {
                 (void) block_open_flag(seccomp, O_DSYNC);
 #endif
 
-                r = seccomp_load(seccomp);
+                r = sym_seccomp_load(seccomp);
                 if (ERRNO_IS_NEG_SECCOMP_FATAL(r))
                         return r;
                 if (r < 0)
index 54d4aa4d3598f1890022a80afd4446a3b47cb0c9..b0aa5b2a3565a8334ffffe7cda367227034fc966 100644 (file)
@@ -1,14 +1,29 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#if HAVE_SECCOMP
-#include <seccomp.h> /* IWYU pragma: export */
-#endif
-
 #include "errno-util.h"
 #include "forward.h"
 
 #if HAVE_SECCOMP
+#include <seccomp.h> /* IWYU pragma: export */
+
+#include "dlfcn-util.h"
+
+extern DLSYM_PROTOTYPE(seccomp_api_get);
+extern DLSYM_PROTOTYPE(seccomp_arch_add);
+extern DLSYM_PROTOTYPE(seccomp_arch_exist);
+extern DLSYM_PROTOTYPE(seccomp_arch_native);
+extern DLSYM_PROTOTYPE(seccomp_arch_remove);
+extern DLSYM_PROTOTYPE(seccomp_attr_set);
+extern DLSYM_PROTOTYPE(seccomp_init);
+extern DLSYM_PROTOTYPE(seccomp_load);
+extern DLSYM_PROTOTYPE(seccomp_release);
+extern DLSYM_PROTOTYPE(seccomp_rule_add_array);
+extern DLSYM_PROTOTYPE(seccomp_rule_add_exact);
+extern DLSYM_PROTOTYPE(seccomp_syscall_resolve_name);
+extern DLSYM_PROTOTYPE(seccomp_syscall_resolve_num_arch);
+
+int dlopen_libseccomp(void);
 
 const char* seccomp_arch_to_string(uint32_t c);
 int seccomp_arch_from_string(const char *n, uint32_t *ret);
@@ -135,7 +150,7 @@ static inline bool ERRNO_IS_NEG_SECCOMP_FATAL(intmax_t r) {
 }
 _DEFINE_ABS_WRAPPER(SECCOMP_FATAL);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(scmp_filter_ctx, seccomp_release, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(scmp_filter_ctx, sym_seccomp_release, seccomp_releasep, NULL);
 
 int parse_syscall_archs(char **l, Set **ret_archs);
 
@@ -151,6 +166,10 @@ static inline bool is_seccomp_available(void) {
         return false;
 }
 
+static inline int dlopen_libseccomp(void) {
+        return -EOPNOTSUPP;
+}
+
 #endif
 
 /* This is a special value to be used where syscall filters otherwise expect errno numbers, will be
index 84f5ec2ed3fbd2672cd256d79aa4cc96d8090070..ea031701e9a4672f6ca5ff0a6fd6a9b182332495 100644 (file)
@@ -217,7 +217,7 @@ simple_tests += files(
 common_test_dependencies = [
         libmount,
         librt,
-        libseccomp,
+        libseccomp_cflags,
         libselinux,
         threads,
 ]
@@ -290,6 +290,7 @@ executables += [
                         libblkid_cflags,
                         libkmod_cflags,
                         libp11kit_cflags,
+                        libseccomp_cflags,
                 ],
         },
         test_template + {
@@ -310,7 +311,7 @@ executables += [
         },
         test_template + {
                 'sources' : files('test-fd-util.c'),
-                'dependencies' : libseccomp,
+                'dependencies' : libseccomp_cflags,
         },
         test_template + {
                 'sources' : files(
@@ -378,7 +379,7 @@ executables += [
                 'extract' : files('nss-test-util.c'),
                 'dependencies' : [
                         libdl,
-                        libseccomp,
+                        libseccomp_cflags,
                 ],
                 'conditions' : ['ENABLE_NSS'],
                 'timeout' : 120,
@@ -425,7 +426,7 @@ executables += [
         },
         test_template + {
                 'sources' : files('test-seccomp.c'),
-                'dependencies' : libseccomp,
+                'dependencies' : libseccomp_cflags,
                 'conditions' : ['HAVE_SECCOMP'],
         },
         test_template + {
index 5d8a75272e38957a1566b4e14c3e61752b248304..68975d473ccc6363eb294b1f6525994fdf3666e9 100644 (file)
@@ -20,6 +20,7 @@
 #include "pcre2-util.h"
 #include "pkcs11-util.h"
 #include "qrcode-util.h"
+#include "seccomp-util.h"
 #include "tests.h"
 #include "tpm2-util.h"
 
@@ -56,6 +57,7 @@ static int run(int argc, char **argv) {
         ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM);
         ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL);
         ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
+        ASSERT_DLOPEN(dlopen_libseccomp, HAVE_SECCOMP);
 
         return 0;
 }
index 916ade79606cf72f0d04b434e5d664b0213f0a1a..8de94e34750150902c17f91383e9c8dea7c585ce 100644 (file)
@@ -1569,7 +1569,7 @@ TEST(run_tests_without_unshare) {
         if (prepare_ns("(test-execute-without-unshare)") == 0) {
                 _cleanup_hashmap_free_ Hashmap *s = NULL;
 
-                r = seccomp_syscall_resolve_name("unshare");
+                r = sym_seccomp_syscall_resolve_name("unshare");
                 ASSERT_NE(r, __NR_SCMP_ERROR);
                 ASSERT_OK(hashmap_ensure_put(&s, NULL, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)));
                 ASSERT_OK(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true));
index 13c65a93cda9a8c662e51307f6e93357ac3c0bba..b2e25e5b96828c9e7641a8d220143ef0525e3a4b 100644 (file)
@@ -54,6 +54,8 @@ TEST(parse_syscall_and_errno) {
         _cleanup_free_ char *n = NULL;
         int e;
 
+        CHECK_SECCOMP(/* refuse_container= */ false);
+
         assert_se(parse_syscall_and_errno("uname:EILSEQ", &n, &e) >= 0);
         ASSERT_STREQ(n, "uname");
         assert_se(e == errno_from_name("EILSEQ") && e >= 0);
@@ -112,7 +114,9 @@ TEST(seccomp_arch_to_string) {
         uint32_t a, b;
         const char *name;
 
-        a = seccomp_arch_native();
+        CHECK_SECCOMP(/* refuse_container= */ false);
+
+        a = sym_seccomp_arch_native();
         assert_se(a > 0);
         name = seccomp_arch_to_string(a);
         assert_se(name);