From: Lennart Poettering Date: Mon, 8 Sep 2025 15:17:05 +0000 (+0200) Subject: libseccomp: turn into dlopen() dependency X-Git-Tag: v259-rc1~441 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aaca6bd5d97258f29c1b8c991e8617c7272308e0;p=thirdparty%2Fsystemd.git libseccomp: turn into dlopen() dependency --- diff --git a/meson.build b/meson.build index 1cf49b9fe3e..ffeef36f6e4 100644 --- a/meson.build +++ b/meson.build @@ -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', diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c index bdb06dd682c..a26507ff64d 100644 --- a/src/analyze/analyze-security.c +++ b/src/analyze/analyze-security.c @@ -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 } diff --git a/src/analyze/meson.build b/src/analyze/meson.build index b1a5b691ce5..5b247a70888 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -53,7 +53,7 @@ executables += [ libcore, libshared, ], - 'dependencies' : libseccomp, + 'dependencies' : libseccomp_cflags, 'install' : conf.get('ENABLE_ANALYZE') == 1, }, core_test_template + { diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 2c489dfce40..02931b3223d 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -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; diff --git a/src/core/execute.c b/src/core/execute.c index c384e9dd638..6301d51ca24 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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; diff --git a/src/core/meson.build b/src/core/meson.build index 1879af4da41..1d897a0ddc3 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -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, ], }, diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 1cec3252389..ec1ac471d9b 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -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'), diff --git a/src/nspawn/meson.build b/src/nspawn/meson.build index b49d7153384..35048462edd 100644 --- a/src/nspawn/meson.build +++ b/src/nspawn/meson.build @@ -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, ], }, diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index 476dad08eb8..073f0f3ea94 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -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 diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 6956689ab57..cf55c6c7332 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -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) diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 166c420c5d8..e4f4f5ebf11 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -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); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index c392c22916c..adc550ed244 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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); } } diff --git a/src/shared/meson.build b/src/shared/meson.build index 92a5b1ddf2f..2dbf8c961c8 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -327,7 +327,7 @@ libshared_deps = [threads, libp11kit_cflags, libpam_cflags, librt, - libseccomp, + libseccomp_cflags, libselinux, libxenctrl_cflags, libxz_cflags, diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index bfe4ca91698..0f4c692613c 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -32,6 +32,46 @@ #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) diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 54d4aa4d359..b0aa5b2a356 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -1,14 +1,29 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#if HAVE_SECCOMP -#include /* IWYU pragma: export */ -#endif - #include "errno-util.h" #include "forward.h" #if HAVE_SECCOMP +#include /* 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 diff --git a/src/test/meson.build b/src/test/meson.build index 84f5ec2ed3f..ea031701e9a 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -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 + { diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 5d8a75272e3..68975d473cc 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -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; } diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 916ade79606..8de94e34750 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -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)); diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 13c65a93cda..b2e25e5b968 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -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);