diff --git a/meson.build b/meson.build index dc4e83204e..c76471e1fe 100644 --- a/meson.build +++ b/meson.build @@ -978,25 +978,13 @@ endif ##################################################################### -threads = dependency('threads') -librt = cc.find_library('rt') libm = cc.find_library('m') -libdl = cc.find_library('dl') -# On some distributions that use musl (e.g. Alpine), libintl.h may be provided by gettext rather than musl. -# In that case, we need to explicitly link with libintl.so. -if cc.has_function('dgettext', - prefix : '''#include ''', - args : '-D_GNU_SOURCE') - libintl = [] -else - libintl = cc.find_library('intl') - if not cc.has_function('dgettext', - prefix : '''#include ''', - args : '-D_GNU_SOURCE', - dependencies : libintl) - error('dgettext() not found') - endif +# Header presence check only — dgettext itself is resolved via dlopen_libintl() at runtime, so we never +# link against libintl. On glibc dgettext lives in libc; on musl gettext-dev provides libintl.h alongside +# libintl.so.8 which we dlopen() if present. +if not cc.has_header('libintl.h') + error('libintl.h not found (install gettext / gettext-dev)') endif # On some architectures, libatomic is required. But on some installations, @@ -1133,12 +1121,7 @@ if not libpam.found() # Debian older than bookworm and Ubuntu older than 22.10 do not provide the .pc file. libpam = cc.find_library('pam', required : feature) endif -libpam_misc = dependency('pam_misc', - required : feature.disabled() ? feature : false) -if not libpam_misc.found() - libpam_misc = cc.find_library('pam_misc', required : feature) -endif -conf.set10('HAVE_PAM', libpam.found() and libpam_misc.found()) +conf.set10('HAVE_PAM', libpam.found()) libpam_cflags = libpam.partial_dependency(includes: true, compile_args: true) libmicrohttpd = dependency('libmicrohttpd', @@ -1324,11 +1307,15 @@ libgobject = dependency('gobject-2.0', libgio = dependency('gio-2.0', required : get_option('glib')) conf.set10('HAVE_GLIB', libglib.found() and libgobject.found() and libgio.found()) +libglib_cflags = libglib.partial_dependency(includes: true, compile_args: true) +libgobject_cflags = libgobject.partial_dependency(includes: true, compile_args: true) +libgio_cflags = libgio.partial_dependency(includes: true, compile_args: true) libdbus = dependency('dbus-1', version : '>= 1.3.2', required : get_option('dbus')) conf.set10('HAVE_DBUS', libdbus.found()) +libdbus_cflags = libdbus.partial_dependency(includes: true, compile_args: true) dbusdatadir = libdbus.get_variable(pkgconfig: 'datadir', default_value: datadir) / 'dbus-1' @@ -1704,14 +1691,13 @@ system_includes = [ ), ] -if get_option('libc') == 'musl' - system_include_args = [ - '-isystem', meson.project_build_root() / 'src/include/musl', - '-isystem', meson.project_source_root() / 'src/include/musl', - ] + system_include_args +libc_include_dir = 'src/include' / get_option('libc') +system_include_args = [ + '-isystem', meson.project_build_root() / libc_include_dir, + '-isystem', meson.project_source_root() / libc_include_dir, +] + system_include_args - system_includes += include_directories('src/include/musl', is_system : true) -endif +system_includes += include_directories(libc_include_dir, is_system : true) basic_includes = [ include_directories( @@ -1768,9 +1754,7 @@ libsystemd = shared_library( link_with : [libc_wrapper_static, libbasic_static], link_whole : [libsystemd_static], - dependencies : [librt, - threads, - userspace], + dependencies : [userspace], link_depends : libsystemd_sym, install : true, install_tag: 'libsystemd', @@ -1789,14 +1773,11 @@ if static_libsystemd != 'false' install_tag: 'libsystemd', install_dir : libdir, pic : static_libsystemd_pic, - dependencies : [libdl, - libgcrypt_cflags, + dependencies : [libgcrypt_cflags, liblz4_cflags, libm, - librt, libxz_cflags, libzstd_cflags, - threads, userspace], c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC'])) @@ -1814,8 +1795,7 @@ libudev = shared_library( '-Wl,--version-script=' + libudev_sym_path], link_with : [libsystemd_static], link_whole : libudev_basic, - dependencies : [threads, - userspace], + dependencies : [userspace], link_depends : libudev_sym, install : true, install_tag: 'libudev', @@ -1932,10 +1912,6 @@ nss_template = { libshared_static, libbasic_static, ], - 'dependencies' : [ - librt, - threads, - ], 'install' : true, 'install_tag' : 'nss', 'install_dir' : libdir, @@ -1948,24 +1924,7 @@ pam_template = { libsystemd_static, libshared_static, ], - 'dependencies' : [ - # Note: our PAM modules also call dlopen_libpam() and use - # symbols acquired through that, hence the explicit dep here is - # strictly speaking unnecessary. We put it in place anyway, - # since for the PAM modules we cannot avoid libpam anyway, - # after all they are loaded *by* libpam, and hence there's no - # loss in having explicit deps here, but there's a win: it - # makes the deps more visible. - # - # (In case you wonder why we do dlopen_libpam() from the PAM - # modules in the first place: that's mostly so that all our PAM - # code (regardless if our PAM modules or our PAM consuming - # programs) can use the same helpers, which hence go via - # dlopen_libpam(). - libpam_misc, - libpam, - threads, - ], + 'dependencies' : libpam_cflags, 'install' : true, 'install_tag' : 'pam', 'install_dir' : pamlibdir, diff --git a/mkosi/mkosi.initrd.conf/mkosi.conf.d/centos-fedora.conf b/mkosi/mkosi.initrd.conf/mkosi.conf.d/centos-fedora.conf index e753749dc4..ab64813060 100644 --- a/mkosi/mkosi.initrd.conf/mkosi.conf.d/centos-fedora.conf +++ b/mkosi/mkosi.initrd.conf/mkosi.conf.d/centos-fedora.conf @@ -8,6 +8,7 @@ Distribution=|fedora PrepareScripts=%D/mkosi/mkosi.conf.d/centos-fedora/systemd.prepare Packages= coreutils + cryptsetup-libs policycoreutils swtpm-tools tpm2-tools diff --git a/mkosi/mkosi.initrd.conf/mkosi.conf.d/opensuse.conf b/mkosi/mkosi.initrd.conf/mkosi.conf.d/opensuse.conf index c30d970c85..b863f7b2d1 100644 --- a/mkosi/mkosi.initrd.conf/mkosi.conf.d/opensuse.conf +++ b/mkosi/mkosi.initrd.conf/mkosi.conf.d/opensuse.conf @@ -9,6 +9,7 @@ Packages= btrfs-progs coreutils kmod + libcryptsetup12 policycoreutils tpm2.0-tools diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 3b869d70f9..6d4493c0bb 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -7,7 +7,12 @@ #include #include +#ifndef __GLIBC__ +#include "sd-dlopen.h" +#endif + #include "dirent-util.h" +#include "dlfcn-util.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" @@ -22,6 +27,32 @@ #include "strv.h" #include "utf8.h" +#ifdef __GLIBC__ +DLSYM_PROTOTYPE(dgettext) = dgettext; +#else +DLSYM_PROTOTYPE(dgettext) = NULL; +#endif + +int dlopen_libintl(int log_level) { +#ifdef __GLIBC__ + return 1; +#else + static void *libintl_dl = NULL; + + SD_ELF_NOTE_DLOPEN( + "intl", + "Support for message translation via gettext", + SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libintl.so.8"); + + return dlopen_many_sym_or_warn( + &libintl_dl, + "libintl.so.8", + log_level, + DLSYM_ARG(dgettext)); +#endif +} + static char* normalize_locale(const char *name) { const char *e; diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index bf5cbcb439..fb22953f16 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -1,9 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include "basic-forward.h" +#include "dlfcn-util.h" + +/* format_arg(2) propagates the format-string nature of the second argument to the return value, so that + * printf(_("Hello %s"), name) still gets checked. It survives both DLSYM_PROTOTYPE's typeof() and the + * ternary in _() below — verified on gcc and clang. */ +extern DLSYM_PROTOTYPE(dgettext) __attribute__((format_arg(2))); + +int dlopen_libintl(int log_level); typedef enum LocaleVariable { /* We don't list LC_ALL here on purpose. People should be @@ -31,7 +40,9 @@ int get_locales(char ***ret); bool locale_is_valid(const char *name); int locale_is_installed(const char *name); -#define _(String) dgettext(GETTEXT_PACKAGE, String) +/* Falls back to the untranslated string if dlopen_libintl() hasn't run or has failed, so callers don't have + * to gate every translatable message on a runtime check. */ +#define _(String) (sym_dgettext ? sym_dgettext(GETTEXT_PACKAGE, (String)) : (String)) #define N_(String) String bool is_locale_utf8(void); diff --git a/src/basic/lock-util.c b/src/basic/lock-util.c index bd267eabf9..24eee3b9e4 100644 --- a/src/basic/lock-util.c +++ b/src/basic/lock-util.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include #include #include #include @@ -227,25 +226,6 @@ int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeo if (r < 0) return log_error_errno(r, "Failed to flock block device in child process: %m"); if (r == 0) { - struct sigevent sev = { - .sigev_notify = SIGEV_SIGNAL, - .sigev_signo = SIGALRM, - }; - timer_t id; - - if (timer_create(CLOCK_MONOTONIC, &sev, &id) < 0) { - log_error_errno(errno, "Failed to allocate CLOCK_MONOTONIC timer: %m"); - _exit(EXIT_FAILURE); - } - - struct itimerspec its = {}; - timespec_store(&its.it_value, timeout); - - if (timer_settime(id, /* flags= */ 0, &its, NULL) < 0) { - log_error_errno(errno, "Failed to start CLOCK_MONOTONIC timer: %m"); - _exit(EXIT_FAILURE); - } - if (lock_generic(fd, type, operation) < 0) { log_error_errno(errno, "Unable to get an exclusive lock on the device: %m"); _exit(EXIT_FAILURE); @@ -255,7 +235,7 @@ int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeo } siginfo_t status; - r = pidref_wait_for_terminate(&pidref, &status); + r = pidref_wait_for_terminate_full(&pidref, timeout, &status); if (r < 0) return r; @@ -270,11 +250,6 @@ int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeo return 0; case CLD_KILLED: - if (status.si_status == SIGALRM) - return -ETIMEDOUT; - - _fallthrough_; - case CLD_DUMPED: return -EPROTO; diff --git a/src/basic/meson.build b/src/basic/meson.build index f847b175b6..9007cff178 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -212,15 +212,12 @@ libbasic_static = static_library( include_directories : basic_includes, implicit_include_directories : false, dependencies : [libbzip2_cflags, - libdl, libgcrypt_cflags, liblz4_cflags, libm, - librt, libxz_cflags, libz_cflags, libzstd_cflags, - threads, userspace], c_args : ['-fvisibility=default'], build_by_default : false) diff --git a/src/bpf/bpf-skel-wrapper.h.in b/src/bpf/bpf-skel-wrapper.h.in index 3dc3cede3e..d9450a12b0 100644 --- a/src/bpf/bpf-skel-wrapper.h.in +++ b/src/bpf/bpf-skel-wrapper.h.in @@ -7,7 +7,7 @@ * fine given that LGPL-2.1-or-later downgrades to GPL if needed. */ -#include "bpf-dlopen.h" /* IWYU pragma: keep */ +#include "bpf-util.h" /* IWYU pragma: keep */ /* libbpf is used via dlopen(), so rename symbols */ #define bpf_object__attach_skeleton sym_bpf_object__attach_skeleton diff --git a/src/bpf/meson.build b/src/bpf/meson.build index 13af4c968e..ac05eb4b18 100644 --- a/src/bpf/meson.build +++ b/src/bpf/meson.build @@ -394,7 +394,7 @@ foreach program : bpf_programs # Keeping it out of bpf_programs_by_name also keeps it out of the # clang-tidy per-source test loop, which would otherwise fall back # to a BPF compile_commands.json entry (no -Isrc/shared) and fail - # to resolve bpf-dlopen.h. + # to resolve bpf-util.h. configure_file( input : 'bpf-skel-wrapper.h.in', output : name + '-skel.h', diff --git a/src/core/bpf-bind-iface.c b/src/core/bpf-bind-iface.c index 74cb2b3d52..1ba643a116 100644 --- a/src/core/bpf-bind-iface.c +++ b/src/core/bpf-bind-iface.c @@ -12,7 +12,7 @@ #if BPF_FRAMEWORK /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "bind-iface-skel.h" diff --git a/src/core/bpf-restrict-fs.c b/src/core/bpf-restrict-fs.c index d3c6adc145..d28abfe4dd 100644 --- a/src/core/bpf-restrict-fs.c +++ b/src/core/bpf-restrict-fs.c @@ -15,7 +15,7 @@ #if BPF_FRAMEWORK /* libbpf, clang and llc compile time dependencies are satisfied */ -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "restrict-fs-skel.h" diff --git a/src/core/bpf-restrict-fsaccess.c b/src/core/bpf-restrict-fsaccess.c index be66f7da01..e043bf9fd6 100644 --- a/src/core/bpf-restrict-fsaccess.c +++ b/src/core/bpf-restrict-fsaccess.c @@ -37,7 +37,7 @@ const char* const restrict_fsaccess_link_names[_RESTRICT_FILESYSTEM_ACCESS_LINK_ }; #if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "restrict-fsaccess-skel.h" diff --git a/src/core/bpf-restrict-ifaces.c b/src/core/bpf-restrict-ifaces.c index 3c73a682a3..e30d15cd25 100644 --- a/src/core/bpf-restrict-ifaces.c +++ b/src/core/bpf-restrict-ifaces.c @@ -14,7 +14,7 @@ #if BPF_FRAMEWORK /* libbpf, clang and llc compile time dependencies are satisfied */ -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "restrict-ifaces-skel.h" diff --git a/src/core/bpf-socket-bind.c b/src/core/bpf-socket-bind.c index 87e7d60c05..b4bf37b41e 100644 --- a/src/core/bpf-socket-bind.c +++ b/src/core/bpf-socket-bind.c @@ -9,7 +9,7 @@ #if BPF_FRAMEWORK /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "socket-bind-api.bpf.h" #include "socket-bind-skel.h" diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 260e7a36af..b82f7b995b 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -21,7 +21,7 @@ #include "ask-password-api.h" #include "barrier.h" #include "bitfield.h" -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-restrict-fs.h" #include "btrfs-util.h" #include "capability-util.h" diff --git a/src/core/meson.build b/src/core/meson.build index 2bd8170c6a..8971800bcb 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -148,13 +148,10 @@ libcore_static = static_library( dependencies : [libaudit_cflags, libbpf_cflags, libcryptsetup_cflags, - libdl, libm, libmount_cflags, - librt, libseccomp_cflags, libselinux_cflags, - threads, userspace], build_by_default : false) diff --git a/src/coredump/meson.build b/src/coredump/meson.build index 355993d09e..b0753d86fa 100644 --- a/src/coredump/meson.build +++ b/src/coredump/meson.build @@ -30,7 +30,6 @@ common_dependencies = [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ] executables += [ diff --git a/src/creds/meson.build b/src/creds/meson.build index dc4a5a28ae..c18fe2ec89 100644 --- a/src/creds/meson.build +++ b/src/creds/meson.build @@ -12,7 +12,6 @@ executables += [ 'dependencies' : [ libmount_cflags, libopenssl_cflags, - threads, ], }, ] diff --git a/src/cryptenroll/meson.build b/src/cryptenroll/meson.build index 8213a0e672..aa789c0a07 100644 --- a/src/cryptenroll/meson.build +++ b/src/cryptenroll/meson.build @@ -22,7 +22,6 @@ executables += [ 'sources' : systemd_cryptenroll_sources, 'dependencies' : [ libcryptsetup_cflags, - libdl, libfido2_cflags, libopenssl_cflags, libp11kit_cflags, diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c index a2804e033a..0265b2d5a0 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c @@ -2,6 +2,7 @@ #include #include +#include #include "sd-json.h" @@ -37,8 +38,12 @@ _public_ int cryptsetup_token_open_pin( assert(pin || pin_size == 0); assert(token >= 0); + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + /* This must not fail at this moment (internal error) */ - r = crypt_token_json_get(cd, token, &json); + r = sym_crypt_token_json_get(cd, token, &json); /* Use assert_se() here to avoid emitting warning with -DNDEBUG */ assert_se(token == r); assert(json); @@ -98,6 +103,9 @@ _public_ void cryptsetup_token_dump( assert(json); + if (dlopen_cryptsetup(LOG_DEBUG) < 0) + return; + r = parse_luks2_fido2_data(cd, json, &rp_id, &salt, &salt_size, &cid, &cid_size, &required); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m."); @@ -162,6 +170,10 @@ _public_ int cryptsetup_token_validate( assert(json); + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + r = sd_json_parse(json, SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL); if (r < 0) return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m."); diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c index 16cf910fe6..e99fcfea85 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "sd-json.h" @@ -36,8 +37,12 @@ _public_ int cryptsetup_token_open_pin( assert(pin || pin_size == 0); assert(token >= 0); + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + /* This must not fail at this moment (internal error) */ - r = crypt_token_json_get(cd, token, &json); + r = sym_crypt_token_json_get(cd, token, &json); /* Use assert_se() here to avoid emitting warning with -DNDEBUG */ assert_se(token == r); assert(json); @@ -89,6 +94,9 @@ _public_ void cryptsetup_token_dump( _cleanup_free_ char *pkcs11_uri = NULL, *key_str = NULL; _cleanup_free_ void *pkcs11_key = NULL; + if (dlopen_cryptsetup(LOG_DEBUG) < 0) + return; + r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &pkcs11_key, &pkcs11_key_size); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m."); @@ -115,6 +123,10 @@ _public_ int cryptsetup_token_validate( sd_json_variant *w; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + r = sd_json_parse(json, SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL); if (r < 0) return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m."); diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index 58dc37c5bf..ad14942622 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "alloc-util.h" #include "cryptsetup-token.h" @@ -60,8 +61,12 @@ _public_ int cryptsetup_token_open_pin( assert(ret_password); assert(ret_password_len); + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + /* This must not fail at this moment (internal error) */ - r = crypt_token_json_get(cd, token, &json); + r = sym_crypt_token_json_get(cd, token, &json); assert(token == r); assert(json); @@ -186,6 +191,9 @@ _public_ void cryptsetup_token_dump( assert(json); + if (dlopen_cryptsetup(LOG_DEBUG) < 0) + return; + r = sd_json_parse(json, SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON object: %m"); @@ -275,6 +283,10 @@ _public_ int cryptsetup_token_validate( assert(json); + r = dlopen_cryptsetup(LOG_DEBUG); + if (r < 0) + return r; + r = sd_json_parse(json, SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL); if (r < 0) return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m"); diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.h b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.h index 68b09fc458..c6a7d25f39 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.h +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.h @@ -2,22 +2,21 @@ #pragma once -#include - +#include "cryptsetup-util.h" #include "shared-forward.h" /* crypt_dump() internal indentation magic */ #define CRYPT_DUMP_LINE_SEP "\n\t " -#define crypt_log_debug(cd, ...) crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__) -#define crypt_log_error(cd, ...) crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__) -#define crypt_log_verbose(cd, ...) crypt_logf(cd, CRYPT_LOG_VERBOSE, __VA_ARGS__) -#define crypt_log(cd, ...) crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__) +#define crypt_log_debug(cd, ...) sym_crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__) +#define crypt_log_error(cd, ...) sym_crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__) +#define crypt_log_verbose(cd, ...) sym_crypt_logf(cd, CRYPT_LOG_VERBOSE, __VA_ARGS__) +#define crypt_log(cd, ...) sym_crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__) #define crypt_log_full_errno(cd, e, lvl, ...) ({ \ int _e = ABS(e), _s = errno; \ errno = _e; \ - crypt_logf(cd, lvl, __VA_ARGS__); \ + sym_crypt_logf(cd, lvl, __VA_ARGS__); \ errno = _s; \ -_e; \ }) diff --git a/src/cryptsetup/cryptsetup-tokens/meson.build b/src/cryptsetup/cryptsetup-tokens/meson.build index 0fd6309201..772c29f50f 100644 --- a/src/cryptsetup/cryptsetup-tokens/meson.build +++ b/src/cryptsetup/cryptsetup-tokens/meson.build @@ -45,8 +45,8 @@ modules += [ ], 'sources' : cryptsetup_token_systemd_tpm2_sources, 'dependencies' : [ - libcryptsetup, - tpm2, + libcryptsetup_cflags, + tpm2_cflags, ], }, template + { @@ -57,7 +57,7 @@ modules += [ ], 'sources' : cryptsetup_token_systemd_fido2_sources, 'dependencies' : [ - libcryptsetup, + libcryptsetup_cflags, libfido2_cflags, ], }, @@ -69,7 +69,7 @@ modules += [ ], 'sources' : cryptsetup_token_systemd_pkcs11_sources, 'dependencies' : [ - libcryptsetup, + libcryptsetup_cflags, libp11kit_cflags, ], }, diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 82e2cb4c3b..12f2aa81dc 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -180,12 +180,14 @@ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) -#ifdef __clang__ -# define ABS(a) __builtin_llabs(a) -#else -# define ABS(a) __builtin_imaxabs(a) -#endif -assert_cc(sizeof(long long) == sizeof(intmax_t)); +#define ABS(a) _Generic((a), \ + float: __builtin_fabsf((float) (a)), \ + double: __builtin_fabs((double) (a)), \ + long double: __builtin_fabsl((long double) (a)), \ + unsigned long long: (a), \ + unsigned long: (a), \ + unsigned int: (a), \ + default: __builtin_llabs((long long) (a))) #define IS_UNSIGNED_INTEGER_TYPE(type) \ (__builtin_types_compatible_p(typeof(type), unsigned char) || \ diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index fc6fe8a4b1..0fcf7b9395 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -41,6 +40,7 @@ #include "homed-manager-bus.h" #include "homed-operation.h" #include "homed-varlink.h" +#include "logarithm.h" #include "mkdir.h" #include "notify-recv.h" #include "ordered-set.h" @@ -1937,9 +1937,9 @@ static int manager_rebalance_calculate(Manager *m) { } /* Scale next rebalancing interval based on the least amount of space of any of the home - * directories. We pick a time in the range 1min … 15min, scaled by log2(min_free), so that: - * 10M → ~0.7min, 100M → ~2.7min, 1G → ~4.6min, 10G → ~6.5min, 100G ~8.4 */ - m->rebalance_interval_usec = (usec_t) CLAMP((LESS_BY(log2(min_free), 22)*15*USEC_PER_MINUTE)/26, + * directories. We pick a time in the range 1min … 15min, scaled by floor(log2(min_free)), + * so that: 10M → ~0.6min, 100M → ~2.3min, 1G → ~4.0min, 10G → ~6.3min, 100G → ~8.1min */ + m->rebalance_interval_usec = (usec_t) CLAMP((LESS_BY(log2u64(min_free), 22u)*15*USEC_PER_MINUTE)/26, 1 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE); diff --git a/src/home/meson.build b/src/home/meson.build index 600f00b4ac..b724517ae9 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -67,11 +67,7 @@ executables += [ 'dbus' : true, 'sources' : systemd_homed_sources, 'extract' : systemd_homed_extract_sources, - 'dependencies' : [ - libm, - libopenssl_cflags, - threads, - ], + 'dependencies' : libopenssl_cflags, }, libexec_template + { 'name' : 'systemd-homework', @@ -82,7 +78,6 @@ executables += [ libfdisk_cflags, libopenssl_cflags, libp11kit_cflags, - threads, ], }, executable_template + { @@ -92,10 +87,8 @@ executables += [ 'extract' : homectl_extract, 'objects' : ['systemd-homed'], 'dependencies' : [ - libdl, libopenssl_cflags, libp11kit_cflags, - threads, ], }, test_template + { @@ -114,12 +107,6 @@ modules += [ 'name' : 'pam_systemd_home', 'conditions' : ['HAVE_PAM'], 'sources' : pam_systemd_home_sources, - 'dependencies' : [ - libintl, - libpam_misc, - libpam, - threads, - ], 'version-script' : meson.current_source_dir() / 'pam_systemd_home.sym', }, ] diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index 1de66b4c03..6e24924e91 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include -#include - #include "sd-bus.h" #include "alloc-util.h" @@ -45,7 +42,7 @@ static int parse_argv( k = parse_boolean(v); if (k < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse suspend= argument, ignoring: %s", v); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse suspend= argument, ignoring: %s", v); else if (flags) SET_FLAG(*flags, ACQUIRE_PLEASE_SUSPEND, k); @@ -57,12 +54,12 @@ static int parse_argv( int k; k = parse_boolean(v); if (k < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", v); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", v); else if (debug) *debug = k; } else - pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + sym_pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } return 0; @@ -76,7 +73,7 @@ static int parse_env(pam_handle_t *pamh, AcquireHomeFlags *flags) { * easy to declare the features of a display manager in code rather than configuration, and this is * really a feature of code */ - v = pam_getenv(pamh, "SYSTEMD_HOME_SUSPEND"); + v = sym_pam_getenv(pamh, "SYSTEMD_HOME_SUSPEND"); if (!v) { /* Also check the process env block, so that people can control this via an env var from the * outside of our process. */ @@ -87,7 +84,7 @@ static int parse_env(pam_handle_t *pamh, AcquireHomeFlags *flags) { r = parse_boolean(v); if (r < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v); else if (flags) SET_FLAG(*flags, ACQUIRE_PLEASE_SUSPEND, r); @@ -106,7 +103,7 @@ static int acquire_user_record( assert(pamh); if (!username) { - r = pam_get_user(pamh, &username, NULL); + r = sym_pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) @@ -149,7 +146,7 @@ static int acquire_user_record( return pam_log_oom(pamh); /* Let's use the cache, so that we can share it between the session and the authentication hooks */ - r = pam_get_data(pamh, homed_field, (const void**) &json); + r = sym_pam_get_data(pamh, homed_field, (const void**) &json); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); if (r == PAM_SUCCESS && json) { @@ -211,13 +208,13 @@ static int acquire_user_record( return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Acquired user record does not match user name."); - /* Update the 'username' pointer to point to our own record now. The pam_set_item() call below is + /* Update the 'username' pointer to point to our own record now. The sym_pam_set_item() call below is * going to invalidate the old version after all */ username = ur->user_name; /* We passed all checks. Let's now make sure the rest of the PAM stack continues with the primary, * normalized name of the user record (i.e. not an alias or so). */ - r = pam_set_item(pamh, PAM_USER, ur->user_name); + r = sym_pam_set_item(pamh, PAM_USER, ur->user_name); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to update username PAM item to '%s': @PAMERR@", ur->user_name); @@ -230,7 +227,7 @@ static int acquire_user_record( if (!json_copy) return pam_log_oom(pamh); - r = pam_set_data(pamh, homed_field, json_copy, pam_cleanup_free); + r = sym_pam_set_data(pamh, homed_field, json_copy, pam_cleanup_free); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", homed_field); @@ -246,7 +243,7 @@ static int acquire_user_record( if (!generic_field) return pam_log_oom(pamh); - r = pam_set_data(pamh, generic_field, json_copy, pam_cleanup_free); + r = sym_pam_set_data(pamh, generic_field, json_copy, pam_cleanup_free); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", generic_field); @@ -256,7 +253,7 @@ static int acquire_user_record( /* Let's store the area we parsed out of the name in an env var, so that pam_systemd later can honour it. */ if (area) { - r = pam_misc_setenv(pamh, "XDG_AREA", area, /* readonly= */ 0); + r = pam_putenv_assign(pamh, "XDG_AREA", area); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable $XDG_AREA to '%s': @PAMERR@", area); @@ -269,7 +266,7 @@ static int acquire_user_record( user_unknown: /* Cache this, so that we don't check again */ - r = pam_set_data(pamh, homed_field, POINTER_MAX, NULL); + r = sym_pam_set_data(pamh, homed_field, POINTER_MAX, NULL); if (r != PAM_SUCCESS) pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s' to invalid, ignoring: @PAMERR@", @@ -289,7 +286,7 @@ static int release_user_record(pam_handle_t *pamh, const char *username) { if (!homed_field) return pam_log_oom(pamh); - r = pam_set_data(pamh, homed_field, NULL, NULL); + r = sym_pam_set_data(pamh, homed_field, NULL, NULL); if (r != PAM_SUCCESS) pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM user record data '%s': @PAMERR@", homed_field); @@ -298,7 +295,7 @@ static int release_user_record(pam_handle_t *pamh, const char *username) { if (!generic_field) return pam_log_oom(pamh); - k = pam_set_data(pamh, generic_field, NULL, NULL); + k = sym_pam_set_data(pamh, generic_field, NULL, NULL); if (k != PAM_SUCCESS) pam_syslog_pam_error(pamh, LOG_ERR, k, "Failed to release PAM user record data '%s': @PAMERR@", generic_field); @@ -569,7 +566,7 @@ static int acquire_home( * prompt the user for the missing unlock credentials, and then chainload the real shell. */ - r = pam_get_user(pamh, &username, NULL); + r = sym_pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) @@ -580,7 +577,7 @@ static int acquire_home( if (!fd_field) return pam_log_oom(pamh); - r = pam_get_data(pamh, fd_field, &home_fd_ptr); + r = sym_pam_get_data(pamh, fd_field, &home_fd_ptr); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to retrieve PAM home reference fd: @PAMERR@"); @@ -618,7 +615,7 @@ static int acquire_home( /* If there's already a cached password, use it. But if not let's authenticate * without anything, maybe some other authentication mechanism systemd-homed * implements (such as PKCS#11) allows us to authenticate without anything else. */ - r = pam_get_item(pamh, PAM_AUTHTOK, (const void**) &cached_password); + r = sym_pam_get_item(pamh, PAM_AUTHTOK, (const void**) &cached_password); if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get cached password: @PAMERR@"); @@ -681,7 +678,7 @@ static int acquire_home( (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Home of user %s is currently locked, please unlock locally first."), ur->user_name); if (FLAGS_SET(flags, ACQUIRE_MUST_AUTHENTICATE)) - pam_syslog(pamh, LOG_ERR, "Failed to prompt for password/prompt."); + sym_pam_syslog(pamh, LOG_ERR, "Failed to prompt for password/prompt."); else pam_debug_syslog(pamh, debug, "Failed to prompt for password/prompt."); @@ -720,12 +717,12 @@ static int acquire_home( /* Later PAM modules may need the auth token, but only during pam_authenticate. */ if (FLAGS_SET(flags, ACQUIRE_MUST_AUTHENTICATE) && !strv_isempty(secret->password)) { - r = pam_set_item(pamh, PAM_AUTHTOK, *secret->password); + r = sym_pam_set_item(pamh, PAM_AUTHTOK, *secret->password); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); } - r = pam_set_data(pamh, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd); + r = sym_pam_set_data(pamh, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); TAKE_FD(acquired_fd); @@ -744,13 +741,13 @@ static int acquire_home( * manager for us (since it would see an inaccessible home directory). Hence set an environment * variable that pam_systemd looks for). */ if (unrestricted) { - r = pam_putenv(pamh, "XDG_SESSION_INCOMPLETE=1"); + r = sym_pam_putenv(pamh, "XDG_SESSION_INCOMPLETE=1"); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_WARNING, r, "Failed to set XDG_SESSION_INCOMPLETE= environment variable: @PAMERR@"); - pam_syslog(pamh, LOG_NOTICE, "Home for user %s acquired in incomplete mode, requires later activation.", ur->user_name); + sym_pam_syslog(pamh, LOG_NOTICE, "Home for user %s acquired in incomplete mode, requires later activation.", ur->user_name); } else - pam_syslog(pamh, LOG_NOTICE, "Home for user %s successfully acquired.", ur->user_name); + sym_pam_syslog(pamh, LOG_NOTICE, "Home for user %s successfully acquired.", ur->user_name); return PAM_SUCCESS; } @@ -767,13 +764,13 @@ static int release_home_fd(pam_handle_t *pamh, const char *username) { if (!fd_field) return pam_log_oom(pamh); - r = pam_get_data(pamh, fd_field, &home_fd_ptr); + r = sym_pam_get_data(pamh, fd_field, &home_fd_ptr); if (r == PAM_NO_MODULE_DATA || (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) < 0)) return PAM_NO_MODULE_DATA; if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to retrieve PAM home reference fd: @PAMERR@"); - r = pam_set_data(pamh, fd_field, NULL, NULL); + r = sym_pam_set_data(pamh, fd_field, NULL, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM home reference fd: @PAMERR@"); @@ -793,6 +790,8 @@ _public_ PAM_EXTERN int pam_sm_authenticate( if (r < 0) return PAM_SERVICE_ERR; + (void) dlopen_libintl(LOG_DEBUG); /* best-effort: messages won't be translated if this fails */ + pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -858,6 +857,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r < 0) return PAM_SERVICE_ERR; + (void) dlopen_libintl(LOG_DEBUG); /* best-effort: messages won't be translated if this fails */ + pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -887,12 +888,12 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) return r; - r = pam_putenv(pamh, "SYSTEMD_HOME=1"); + r = sym_pam_putenv(pamh, "SYSTEMD_HOME=1"); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable $SYSTEMD_HOME: @PAMERR@"); - r = pam_putenv(pamh, FLAGS_SET(flags, ACQUIRE_PLEASE_SUSPEND) ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0"); + r = sym_pam_putenv(pamh, FLAGS_SET(flags, ACQUIRE_PLEASE_SUSPEND) ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0"); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: @PAMERR@"); @@ -911,6 +912,12 @@ _public_ PAM_EXTERN int pam_sm_close_session( bool debug = false; int r; + r = dlopen_libpam(LOG_DEBUG); + if (r < 0) + return PAM_SERVICE_ERR; + + (void) dlopen_libintl(LOG_DEBUG); /* best-effort: messages won't be translated if this fails */ + pam_log_setup(); if (parse_argv(pamh, @@ -921,7 +928,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( pam_debug_syslog(pamh, debug, "pam-systemd-homed: closing session..."); - r = pam_get_user(pamh, &username, NULL); + r = sym_pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) @@ -954,7 +961,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SESSION_ERR, "Failed to release user home: %s", bus_error_message(&error, r)); - pam_syslog(pamh, LOG_NOTICE, "Not deactivating home directory of %s, as it is still used.", username); + sym_pam_syslog(pamh, LOG_NOTICE, "Not deactivating home directory of %s, as it is still used.", username); } return PAM_SUCCESS; @@ -976,6 +983,8 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( if (r < 0) return PAM_SERVICE_ERR; + (void) dlopen_libintl(LOG_DEBUG); /* best-effort: messages won't be translated if this fails */ + pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -1005,7 +1014,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( switch (r) { case -ESTALE: - pam_syslog(pamh, LOG_WARNING, "User record for '%s' is newer than current system time, assuming incorrect system clock, allowing access.", ur->user_name); + sym_pam_syslog(pamh, LOG_WARNING, "User record for '%s' is newer than current system time, assuming incorrect system clock, allowing access.", ur->user_name); break; case -ENOLCK: @@ -1062,7 +1071,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( case -ESTALE: /* If the system clock is wrong, let's log but continue */ - pam_syslog(pamh, LOG_WARNING, "Couldn't check if password change is required, last change is in the future, system clock likely wrong."); + sym_pam_syslog(pamh, LOG_WARNING, "Couldn't check if password change is required, last change is in the future, system clock likely wrong."); break; case -EROFS: @@ -1095,6 +1104,8 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( if (r < 0) return PAM_SERVICE_ERR; + (void) dlopen_libintl(LOG_DEBUG); /* best-effort: messages won't be translated if this fails */ + pam_log_setup(); if (parse_argv(pamh, @@ -1121,7 +1132,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( /* No, it's not cached, then let's ask for the password and its verification, and cache * it. */ - r = pam_get_authtok_noverify(pamh, &new_password, "New password: "); + r = sym_pam_get_authtok_noverify(pamh, &new_password, "New password: "); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get new password: @PAMERR@"); @@ -1130,7 +1141,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( return PAM_AUTHTOK_ERR; } - r = pam_get_authtok_verify(pamh, &new_password, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */ + r = sym_pam_get_authtok_verify(pamh, &new_password, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */ if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get password again: @PAMERR@"); diff --git a/src/import/meson.build b/src/import/meson.build index c2879c5d84..f133f276b4 100644 --- a/src/import/meson.build +++ b/src/import/meson.build @@ -17,7 +17,6 @@ executables += [ 'import-common.c', 'qcow2-util.c', ), - 'dependencies' : threads, }, libexec_template + { 'name' : 'systemd-pull', diff --git a/src/include/glibc/stdio.h b/src/include/glibc/stdio.h new file mode 100644 index 0000000000..7e45cb3ba2 --- /dev/null +++ b/src/include/glibc/stdio.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* Force glibc's stdio.h to route sscanf/fscanf to the old __isoc99_* siblings (GLIBC_2.7) rather + * than the newer __isoc23_* ones (GLIBC_2.38). The only behavioural difference is "0b" prefix + * support in %i conversions, which we don't use. We include features.h first so the macro is set + * to its normal value, then override it before stdio.h's body evaluates __GLIBC_USE(C23_STRTOL). + * + * The macro was named __GLIBC_USE_C2X_STRTOL on glibc 2.38–2.39 and renamed to the C23 spelling + * in glibc 2.40; clear both so this override works across that range. */ + +#include +#undef __GLIBC_USE_C2X_STRTOL +#define __GLIBC_USE_C2X_STRTOL 0 +#undef __GLIBC_USE_C23_STRTOL +#define __GLIBC_USE_C23_STRTOL 0 + +#include_next /* IWYU pragma: export */ diff --git a/src/include/glibc/stdlib.h b/src/include/glibc/stdlib.h new file mode 100644 index 0000000000..a3ad2a3b5a --- /dev/null +++ b/src/include/glibc/stdlib.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* Force glibc's stdlib.h to leave strtol/strtoul/strtoll/strtoull as their original GLIBC_2.2.5 + * symbols rather than redirect to __isoc23_* (GLIBC_2.38). The only behavioural difference is + * "0b" prefix support in base 0/2 parsing, which we don't use. + * + * The macro was named __GLIBC_USE_C2X_STRTOL on glibc 2.38–2.39 and renamed to the C23 spelling + * in glibc 2.40; clear both so this override works across that range. */ + +#include +#undef __GLIBC_USE_C2X_STRTOL +#define __GLIBC_USE_C2X_STRTOL 0 +#undef __GLIBC_USE_C23_STRTOL +#define __GLIBC_USE_C23_STRTOL 0 + +#include_next /* IWYU pragma: export */ diff --git a/src/journal-remote/meson.build b/src/journal-remote/meson.build index f6aa71349c..22ac8703b5 100644 --- a/src/journal-remote/meson.build +++ b/src/journal-remote/meson.build @@ -25,7 +25,6 @@ common_deps = [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ] executables += [ diff --git a/src/journal/meson.build b/src/journal/meson.build index 1f40e9b43b..75cd7b7a30 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -72,7 +72,6 @@ executables += [ libselinux_cflags, libxz_cflags, libzstd_cflags, - threads, ], }, libexec_template + { @@ -86,7 +85,6 @@ executables += [ 'public' : true, 'sources' : files('cat.c'), 'objects' : ['systemd-journald'], - 'dependencies' : [threads], }, executable_template + { 'name' : 'journalctl', @@ -94,11 +92,9 @@ executables += [ 'sources' : journalctl_sources, 'link_with' : journalctl_link_with, 'dependencies' : [ - libdl, liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ], }, journal_test_template + { @@ -123,7 +119,6 @@ executables += [ liblz4_cflags, libselinux_cflags, libxz_cflags, - threads, ], }, journal_test_template + { diff --git a/src/libc/libc-shim.h b/src/libc/libc-shim.h index c5cf9c8acd..022ee5ad15 100644 --- a/src/libc/libc-shim.h +++ b/src/libc/libc-shim.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include #include #include #include @@ -35,21 +36,38 @@ #define _SHIM_NAME_8(t, n, ...) n, _SHIM_NAME_7(__VA_ARGS__) #define _SHIM_NAME(...) _SHIM_CAT(_SHIM_NAME_, _SHIM_PAIRS(__VA_ARGS__))(__VA_ARGS__) -/* Defines a wrapper that calls the libc symbol if available at runtime, or falls back to the - * corresponding direct syscall otherwise. The libc symbol is redeclared as a weak reference so the - * binary still loads on libc versions that don't provide it. Each parameter is passed as type, - * name pairs (flat). +/* The shim resolves the libc symbol via dlsym(RTLD_DEFAULT) at DSO-load time using a constructor + * and caches the result in a file-scope static. Constructors run single-threaded before main() and + * before any signal handler can fire, so the cached pointer needs no atomics: subsequent reads from + * any thread observe the value stored during init. Resolving eagerly also keeps dlsym() out of + * contexts where it is not async-signal-safe (signal handlers, between fork() and exec()). * - * The weak reference is bound to the libc symbol via an __asm__("label") rename so that the bare - * libc identifier never appears as a C token. This matters because override/musl headers - * sometimes #define the libc name to redirect it to the _shim variant — without the rename the - * caller would have to #undef each name before invoking the macro. # and ## operators don't - * macro-expand their operands, so the parameter "func" stays a literal token everywhere. */ + * The asm barrier after dlsym() is load-bearing: without it, when LTO determines the cache store + * is dead (because no caller of func##_shim survives DCE) the compiler is free to tail-call + * dlsym() (jmp dlsym@plt). Under glibc, dlsym reads __builtin_return_address(0) to find its + * caller's link map; with a tail call that read lands inside ld.so's call_init(), the resulting + * link map has no l_scope, and _dl_lookup_symbol_x SIGSEGVs. Filed upstream in glibc by + * https://sourceware.org/bugzilla/show_bug.cgi?id=34156. The barrier keeps us working on + * unpatched libc. + * + * Each reference to `func` in the macro body is positioned as an operand of `#` or `##` so the + * override headers (e.g. "#define openat2 openat2_shim") don't rewrite the token before pasting or + * stringification. For the same reason the resolution logic isn't extracted into a helper macro — + * passing `func` to a nested macro would expand it as a regular argument and re-trigger the + * override. + * + * Defines a wrapper that calls the libc symbol if available at runtime, or falls back to the + * corresponding direct syscall otherwise. Each parameter is passed as type, name pairs (flat). */ #define DEFINE_SYSCALL_SHIM(func, ret, ...) \ - extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__)); \ + static typeof(&func##_shim) func##_shim_cache; \ + __attribute__((constructor)) static void func##_shim_init(void) { \ + void *p = dlsym(RTLD_DEFAULT, #func); \ + __asm__ volatile("" ::: "memory"); \ + func##_shim_cache = (typeof(&func##_shim)) p; \ + } \ ret func##_shim(_SHIM_DECL(__VA_ARGS__)) { \ - if (func##_libc_weak) \ - return func##_libc_weak(_SHIM_NAME(__VA_ARGS__)); \ + if (func##_shim_cache) \ + return func##_shim_cache(_SHIM_NAME(__VA_ARGS__)); \ return syscall(__NR_##func, _SHIM_NAME(__VA_ARGS__)); \ } @@ -57,20 +75,30 @@ * by returning the positive errno value directly (posix_spawn-family convention). If the libc symbol * is missing at runtime, ENOSYS is returned. */ #define DEFINE_LIBC_SHIM(func, ret, ...) \ - extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__)); \ + static typeof(&func##_shim) func##_shim_cache; \ + __attribute__((constructor)) static void func##_shim_init(void) { \ + void *p = dlsym(RTLD_DEFAULT, #func); \ + __asm__ volatile("" ::: "memory"); \ + func##_shim_cache = (typeof(&func##_shim)) p; \ + } \ ret func##_shim(_SHIM_DECL(__VA_ARGS__)) { \ - if (func##_libc_weak) \ - return func##_libc_weak(_SHIM_NAME(__VA_ARGS__)); \ + if (func##_shim_cache) \ + return func##_shim_cache(_SHIM_NAME(__VA_ARGS__)); \ return ENOSYS; \ } /* Like DEFINE_LIBC_SHIM but for libc helpers that report errors via errno + -1 return value. If the * libc symbol is missing at runtime, errno is set to ENOSYS and -1 is returned. */ #define DEFINE_LIBC_ERRNO_SHIM(func, ret, ...) \ - extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__)); \ + static typeof(&func##_shim) func##_shim_cache; \ + __attribute__((constructor)) static void func##_shim_init(void) { \ + void *p = dlsym(RTLD_DEFAULT, #func); \ + __asm__ volatile("" ::: "memory"); \ + func##_shim_cache = (typeof(&func##_shim)) p; \ + } \ ret func##_shim(_SHIM_DECL(__VA_ARGS__)) { \ - if (func##_libc_weak) \ - return func##_libc_weak(_SHIM_NAME(__VA_ARGS__)); \ + if (func##_shim_cache) \ + return func##_shim_cache(_SHIM_NAME(__VA_ARGS__)); \ errno = ENOSYS; \ return -1; \ } diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 2fab547194..b7e11c9bb2 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -150,9 +150,7 @@ libsystemd_static = static_library( c_args : libsystemd_c_args, link_with : [libc_wrapper_static, libbasic_static], - dependencies : [threads, - libm, - librt, + dependencies : [libm, userspace], build_by_default : false) @@ -203,51 +201,42 @@ simple_tests += files( libsystemd_tests += [ { 'sources' : files('sd-bus/test-bus-address.c'), - 'dependencies' : threads }, { 'sources' : files('sd-bus/test-bus-benchmark.c'), - 'dependencies' : threads, 'type' : 'manual', }, { 'sources' : files('sd-bus/test-bus-chat.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-cleanup.c'), - 'dependencies' : [threads, libseccomp_cflags], + 'dependencies' : libseccomp_cflags, }, { 'sources' : files('sd-bus/test-bus-marshal.c'), 'dependencies' : [ - libdbus, - libgio, - libglib, - libgobject, + libdbus_cflags, + libgio_cflags, + libglib_cflags, + libgobject_cflags, libm, - threads, ], }, { 'sources' : files('sd-bus/test-bus-objects.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-peersockaddr.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-queue-ref-cycle.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-server.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-signature.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-bus/test-bus-track.c'), @@ -255,12 +244,11 @@ libsystemd_tests += [ }, { 'sources' : files('sd-bus/test-bus-watch-bind.c'), - 'dependencies' : threads, 'timeout' : 120, }, { 'sources' : files('sd-device/test-sd-device.c'), - 'dependencies' : [threads, libmount_cflags], + 'dependencies' : libmount_cflags, }, { 'sources' : files('sd-event/test-event.c'), @@ -288,16 +276,13 @@ libsystemd_tests += [ }, { 'sources' : files('sd-resolve/test-resolve.c'), - 'dependencies' : threads, 'timeout' : 120, }, { 'sources' : files('sd-varlink/test-varlink.c'), - 'dependencies' : threads, }, { 'sources' : files('sd-varlink/test-varlink-idl.c'), - 'dependencies' : threads, }, ] diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index e26ca43344..5c2fca0f83 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - /* We make an exception here to our usual "include system headers first" rule because we need one of these * macros to disable a warning triggered by the glib headers. */ #include "macro-fundamental.h" @@ -23,6 +21,7 @@ REENABLE_WARNING #include "bus-label.h" #include "bus-message.h" #include "bus-util.h" +#include "dlfcn-util.h" #include "escape.h" #include "fd-util.h" #include "log.h" @@ -31,6 +30,40 @@ REENABLE_WARNING #include "stat-util.h" #include "tests.h" +#if HAVE_GLIB +static void *glib_dl = NULL; +static DLSYM_PROTOTYPE(g_dbus_message_new_from_blob) = NULL; +static DLSYM_PROTOTYPE(g_dbus_message_print) = NULL; +static DLSYM_PROTOTYPE(g_free) = NULL; +static DLSYM_PROTOTYPE(g_object_unref) = NULL; + +static int dlopen_glib(void) { + return dlopen_many_sym_or_warn( + &glib_dl, "libgio-2.0.so.0", LOG_DEBUG, + DLSYM_ARG(g_dbus_message_new_from_blob), + DLSYM_ARG(g_dbus_message_print), + DLSYM_ARG(g_free), + DLSYM_ARG(g_object_unref)); +} +#endif + +#if HAVE_DBUS +static void *libdbus_dl = NULL; +static DLSYM_PROTOTYPE(dbus_error_init) = NULL; +static DLSYM_PROTOTYPE(dbus_error_free) = NULL; +static DLSYM_PROTOTYPE(dbus_message_demarshal) = NULL; +static DLSYM_PROTOTYPE(dbus_message_unref) = NULL; + +static int dlopen_libdbus(void) { + return dlopen_many_sym_or_warn( + &libdbus_dl, "libdbus-1.so.3", LOG_DEBUG, + DLSYM_ARG(dbus_error_init), + DLSYM_ARG(dbus_error_free), + DLSYM_ARG(dbus_message_demarshal), + DLSYM_ARG(dbus_message_unref)); +} +#endif + static void test_bus_path_encode_unique(void) { _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL; @@ -322,39 +355,32 @@ int main(int argc, char *argv[]) { log_info("message size = %zu, contents =\n%s", sz, h); #if HAVE_GLIB - /* Work-around for asan bug. See c8d980a3e962aba2ea3a4cedf75fa94890a6d746. */ -#if !HAS_FEATURE_ADDRESS_SANITIZER - { + if (dlopen_glib() >= 0) { GDBusMessage *g; char *p; -#if !defined(GLIB_VERSION_2_36) - g_type_init(); -#endif - - g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL); - p = g_dbus_message_print(g, 0); + g = sym_g_dbus_message_new_from_blob(buffer, sz, 0, NULL); + p = sym_g_dbus_message_print(g, 0); log_info("%s", p); - g_free(p); - g_object_unref(g); + sym_g_free(p); + sym_g_object_unref(g); } #endif -#endif #if HAVE_DBUS - { + if (dlopen_libdbus() >= 0) { DBusMessage *w; DBusError error; - dbus_error_init(&error); + sym_dbus_error_init(&error); - w = dbus_message_demarshal(buffer, sz, &error); + w = sym_dbus_message_demarshal(buffer, sz, &error); if (!w) log_error("%s", error.message); else - dbus_message_unref(w); + sym_dbus_message_unref(w); - dbus_error_free(&error); + sym_dbus_error_free(&error); } #endif @@ -451,7 +477,7 @@ int main(int argc, char *argv[]) { assert_se(r > 0); assert_se(streq(x, "foo")); assert_se(u64 == 815ULL); - assert_se(fabs(dbl - 47.0) < 0.1); + assert_se(ABS(dbl - 47.0) < 0.1); assert_se(streq(y, "/")); r = sd_bus_message_peek_type(m, NULL, NULL); diff --git a/src/libsystemd/sd-json/test-json.c b/src/libsystemd/sd-json/test-json.c index c9aa5d2f90..2e7efe438f 100644 --- a/src/libsystemd/sd-json/test-json.c +++ b/src/libsystemd/sd-json/test-json.c @@ -61,8 +61,8 @@ static void test_tokenizer_one(const char *data, ...) { d = va_arg(ap, double); - assert_se(fabs(d - v.real) < 1e-10 || - fabs((d - v.real) / v.real) < 1e-10); + assert_se(ABS(d - v.real) < 1e-10 || + ABS((d - v.real) / v.real) < 1e-10); } else if (t == JSON_TOKEN_INTEGER) { int64_t i; @@ -243,7 +243,7 @@ static void test_2(sd_json_variant *v) { /* has thisisaverylongproperty */ p = sd_json_variant_by_key(v, "thisisaverylongproperty"); - assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_REAL && fabs(sd_json_variant_real(p) - 1.27) < 0.001); + assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_REAL && ABS(sd_json_variant_real(p) - 1.27) < 0.001); } static void test_zeroes(sd_json_variant *v) { @@ -753,14 +753,14 @@ static void test_float_match(sd_json_variant *v) { assert_se(sd_json_variant_is_array(v)); assert_se(sd_json_variant_elements(v) == 11); assert_se(!iszero_safe(sd_json_variant_real(sd_json_variant_by_index(v, 0)))); - assert_se(fabs(1.0 - (DBL_MIN / sd_json_variant_real(sd_json_variant_by_index(v, 0)))) <= delta); + assert_se(ABS(1.0 - (DBL_MIN / sd_json_variant_real(sd_json_variant_by_index(v, 0)))) <= delta); assert_se(!iszero_safe(sd_json_variant_real(sd_json_variant_by_index(v, 1)))); - assert_se(fabs(1.0 - (DBL_MAX / sd_json_variant_real(sd_json_variant_by_index(v, 1)))) <= delta); + assert_se(ABS(1.0 - (DBL_MAX / sd_json_variant_real(sd_json_variant_by_index(v, 1)))) <= delta); assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 2))); /* nan is not supported by json → null */ assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 3))); /* +inf is not supported by json → null */ assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 4))); /* -inf is not supported by json → null */ assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 5)) || - fabs(1.0 - (HUGE_VAL / sd_json_variant_real(sd_json_variant_by_index(v, 5)))) <= delta); /* HUGE_VAL might be +inf, but might also be something else */ + ABS(1.0 - (HUGE_VAL / sd_json_variant_real(sd_json_variant_by_index(v, 5)))) <= delta); /* HUGE_VAL might be +inf, but might also be something else */ assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 6)) && sd_json_variant_is_integer(sd_json_variant_by_index(v, 6)) && sd_json_variant_integer(sd_json_variant_by_index(v, 6)) == 0); @@ -773,11 +773,11 @@ static void test_float_match(sd_json_variant *v) { assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 9)) && !sd_json_variant_is_integer(sd_json_variant_by_index(v, 9))); assert_se(!iszero_safe(sd_json_variant_real(sd_json_variant_by_index(v, 9)))); - assert_se(fabs(1.0 - (DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 9)))) <= delta); + assert_se(ABS(1.0 - (DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 9)))) <= delta); assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 10)) && !sd_json_variant_is_integer(sd_json_variant_by_index(v, 10))); assert_se(!iszero_safe(sd_json_variant_real(sd_json_variant_by_index(v, 10)))); - assert_se(fabs(1.0 - (-DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 10)))) <= delta); + assert_se(ABS(1.0 - (-DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 10)))) <= delta); } TEST(float) { @@ -1143,8 +1143,8 @@ TEST(json_dispatch_double) { /* flags= */ 0, &data) >= 0); - assert_se(fabs(data.x1 - 0.5) < 0.01); - assert_se(fabs(data.x2 + 0.5) < 0.01); + assert_se(ABS(data.x1 - 0.5) < 0.01); + assert_se(ABS(data.x2 + 0.5) < 0.01); assert_se(isinf(data.x3)); assert_se(data.x3 > 0); assert_se(isinf(data.x4)); diff --git a/src/libudev/libudev.pc.in b/src/libudev/libudev.pc.in index 6541bcb1ab..72d46ffc50 100644 --- a/src/libudev/libudev.pc.in +++ b/src/libudev/libudev.pc.in @@ -16,5 +16,4 @@ Name: libudev Description: Library to access udev device information Version: {{PROJECT_VERSION}} Libs: -L${libdir} -ludev -Libs.private: -lrt -pthread Cflags: -I${includedir} diff --git a/src/locale/meson.build b/src/locale/meson.build index 1b97628abb..2f99bb8d80 100644 --- a/src/locale/meson.build +++ b/src/locale/meson.build @@ -18,7 +18,6 @@ localectl_sources = files('localectl.c') # specify where the headers are. if conf.get('HAVE_XKBCOMMON') == 1 libxkbcommon_deps = [ - libdl, libxkbcommon_cflags, ] else diff --git a/src/login/meson.build b/src/login/meson.build index 390960d5f6..44325ccd7c 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -48,9 +48,6 @@ executables += [ 'dbus' : true, 'sources' : systemd_logind_sources, 'extract' : systemd_logind_extract_sources, - 'dependencies' : [ - threads, - ], }, executable_template + { 'name' : 'loginctl', @@ -60,7 +57,6 @@ executables += [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ], }, executable_template + { @@ -79,7 +75,6 @@ executables += [ test_template + { 'sources' : files('test-login-tables.c'), 'objects' : ['systemd-logind'], - 'dependencies' : threads, }, test_template + { 'sources' : files('test-session-properties.c'), diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 4e571e7056..1b0adfae9e 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -88,7 +87,7 @@ static int parse_caps( c = capability_from_name(s); if (c < 0) { - pam_syslog(pamh, LOG_WARNING, "Unknown capability, ignoring: %s", s); + sym_pam_syslog(pamh, LOG_WARNING, "Unknown capability, ignoring: %s", s); continue; } @@ -146,7 +145,7 @@ static int parse_argv( } else if ((p = startswith(argv[i], "area="))) { if (!isempty(p) && !filename_is_valid(p)) - pam_syslog(pamh, LOG_WARNING, "Area name specified among PAM module parameters is not valid, ignoring: %s", p); + sym_pam_syslog(pamh, LOG_WARNING, "Area name specified among PAM module parameters is not valid, ignoring: %s", p); else if (area) *area = p; @@ -157,22 +156,22 @@ static int parse_argv( } else if ((p = startswith(argv[i], "debug="))) { r = parse_boolean(p); if (r < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", p); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", p); else if (debug) *debug = r; } else if ((p = startswith(argv[i], "default-capability-bounding-set="))) { r = parse_caps(pamh, p, default_capability_bounding_set); if (r < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-bounding-set= argument, ignoring: %s", p); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-bounding-set= argument, ignoring: %s", p); } else if ((p = startswith(argv[i], "default-capability-ambient-set="))) { r = parse_caps(pamh, p, default_capability_ambient_set); if (r < 0) - pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-ambient-set= argument, ignoring: %s", p); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-ambient-set= argument, ignoring: %s", p); } else - pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + sym_pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } return 0; @@ -184,7 +183,7 @@ static int acquire_user_record(pam_handle_t *pamh, UserRecord **ret_record) { assert(pamh); const char *username = NULL; - r = pam_get_user(pamh, &username, NULL); + r = sym_pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) @@ -198,7 +197,7 @@ static int acquire_user_record(pam_handle_t *pamh, UserRecord **ret_record) { _cleanup_(user_record_unrefp) UserRecord *ur = NULL; const char *json = NULL; - r = pam_get_data(pamh, field, (const void**) &json); + r = sym_pam_get_data(pamh, field, (const void**) &json); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); if (r == PAM_SUCCESS && json) { @@ -240,7 +239,7 @@ static int acquire_user_record(pam_handle_t *pamh, UserRecord **ret_record) { return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to format user JSON: %m"); /* And cache it for everyone else */ - r = pam_set_data(pamh, field, formatted, pam_cleanup_free); + r = sym_pam_set_data(pamh, field, formatted, pam_cleanup_free); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", field); @@ -382,7 +381,7 @@ static int append_session_memory_max(pam_handle_t *pamh, sd_bus_message *m, cons uint64_t val; r = parse_size(limit, 1024, &val); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit); return 0; } @@ -402,7 +401,7 @@ static int append_session_runtime_max_sec(pam_handle_t *pamh, sd_bus_message *m, usec_t val; r = parse_sec(limit, &val); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit); return 0; } @@ -422,7 +421,7 @@ static int append_session_tasks_max(pam_handle_t *pamh, sd_bus_message *m, const uint64_t val; r = safe_atou64(limit, &val); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit); return 0; } @@ -441,7 +440,7 @@ static int append_session_cpu_weight(pam_handle_t *pamh, sd_bus_message *m, cons uint64_t val; r = cg_cpu_weight_parse(limit, &val); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit); return 0; } @@ -460,7 +459,7 @@ static int append_session_io_weight(pam_handle_t *pamh, sd_bus_message *m, const uint64_t val; r = cg_weight_parse(limit, &val); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit); + sym_pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit); return 0; } @@ -479,7 +478,7 @@ static const char* getenv_harder(pam_handle_t *pamh, const char *key, const char * PAM services don't have to be reworked to set systemd-specific properties, but these properties * can still be set from the unit file Environment= block. */ - v = pam_getenv(pamh, key); + v = sym_pam_getenv(pamh, key); if (!isempty(v)) return v; @@ -507,9 +506,9 @@ static bool getenv_harder_bool(pam_handle_t *pamh, const char *key, bool fallbac r = parse_boolean(v); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, - "Failed to parse environment variable value '%s' of '%s', falling back to using '%s'.", - v, key, true_false(fallback)); + sym_pam_syslog(pamh, LOG_WARNING, + "Failed to parse environment variable value '%s' of '%s', falling back to using '%s'.", + v, key, true_false(fallback)); return fallback; } @@ -529,9 +528,9 @@ static uint32_t getenv_harder_uint32(pam_handle_t *pamh, const char *key, uint32 uint32_t u; r = safe_atou32(v, &u); if (r < 0) { - pam_syslog(pamh, LOG_WARNING, - "Failed to parse environment variable value '%s' of '%s' as unsigned integer, falling back to using %" PRIu32 ".", - v, key, fallback); + sym_pam_syslog(pamh, LOG_WARNING, + "Failed to parse environment variable value '%s' of '%s' as unsigned integer, falling back to using %" PRIu32 ".", + v, key, fallback); return fallback; } @@ -548,14 +547,14 @@ static int update_environment(pam_handle_t *pamh, const char *key, const char *v * about errors. */ if (isempty(value)) { - /* Unset the variable if set. Note that pam_putenv() would log nastily behind our back if we + /* Unset the variable if set. Note that sym_pam_putenv() would log nastily behind our back if we * call it without the variable actually being set. Hence we check explicitly if it's set * before. */ - if (!pam_getenv(pamh, key)) + if (!sym_pam_getenv(pamh, key)) return PAM_SUCCESS; - r = pam_putenv(pamh, key); + r = sym_pam_putenv(pamh, key); if (!IN_SET(r, PAM_SUCCESS, PAM_BAD_ITEM)) return pam_syslog_pam_error(pamh, LOG_WARNING, r, "Failed to unset %s environment variable: @PAMERR@", key); @@ -563,7 +562,7 @@ static int update_environment(pam_handle_t *pamh, const char *key, const char *v return PAM_SUCCESS; } - r = pam_misc_setenv(pamh, key, value, /* readonly= */ false); + r = pam_putenv_assign(pamh, key, value); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable %s: @PAMERR@", key); @@ -588,7 +587,7 @@ static int propagate_credential_to_environment(pam_handle_t *pamh, bool debug, c return PAM_SUCCESS; } - r = pam_misc_setenv(pamh, varname, value, 0); + r = pam_putenv_assign(pamh, varname, value); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable %s: @PAMERR@", varname); @@ -610,7 +609,7 @@ static bool validate_runtime_directory(pam_handle_t *pamh, const char *path, uid * otherwise we might end up setting $XDG_RUNTIME_DIR to some directory owned by the wrong user. */ if (!path_is_absolute(path)) { - pam_syslog(pamh, LOG_ERR, "Provided runtime directory '%s' is not absolute.", path); + sym_pam_syslog(pamh, LOG_ERR, "Provided runtime directory '%s' is not absolute.", path); goto fail; } @@ -620,19 +619,19 @@ static bool validate_runtime_directory(pam_handle_t *pamh, const char *path, uid } if (!S_ISDIR(st.st_mode)) { - pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not actually a directory.", path); + sym_pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not actually a directory.", path); goto fail; } if (st.st_uid != uid) { - pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not owned by UID " UID_FMT ", as it should.", path, uid); + sym_pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not owned by UID " UID_FMT ", as it should.", path, uid); goto fail; } return true; fail: - pam_syslog(pamh, LOG_WARNING, "Not setting $XDG_RUNTIME_DIR, as the directory is not in order."); + sym_pam_syslog(pamh, LOG_WARNING, "Not setting $XDG_RUNTIME_DIR, as the directory is not in order."); return false; } @@ -642,7 +641,7 @@ static int pam_putenv_and_log(pam_handle_t *pamh, const char *e, bool debug) { assert(pamh); assert(e); - r = pam_putenv(pamh, e); + r = sym_pam_putenv(pamh, e); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable %s: @PAMERR@", e); @@ -992,7 +991,7 @@ static void session_context_mangle( c->area = ur->default_area; if (!isempty(c->area) && !filename_is_valid(c->area)) { - pam_syslog(pamh, LOG_WARNING, "Specified area '%s' is not a valid filename, ignoring area request.", c->area); + sym_pam_syslog(pamh, LOG_WARNING, "Specified area '%s' is not a valid filename, ignoring area request.", c->area); c->area = NULL; } @@ -1048,7 +1047,7 @@ static void session_context_mangle( if (streq(c->class, "user")) c->class = "user-incomplete"; else - pam_syslog(pamh, LOG_WARNING, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class); + sym_pam_syslog(pamh, LOG_WARNING, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class); } c->remote = !isempty(c->remote_host) && !is_localhost(c->remote_host); @@ -1253,8 +1252,7 @@ static int register_session( return PAM_SUCCESS; } - pam_syslog(pamh, LOG_ERR, - "Failed to create session: %s", bus_error_message(&error, r)); + sym_pam_syslog(pamh, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); return PAM_SESSION_ERR; } @@ -1282,7 +1280,7 @@ static int register_session( if (fd < 0) return pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to dup session fd: %m"); - r = pam_set_data(pamh, "systemd.session-fd", FD_TO_PTR(fd), NULL); + r = sym_pam_set_data(pamh, "systemd.session-fd", FD_TO_PTR(fd), NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to install session fd: @PAMERR@"); TAKE_FD(fd); @@ -1580,7 +1578,7 @@ static int setup_environment( pam_syslog_errno(pamh, LOG_WARNING, r, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory: %m", j, area); /* Also tell the user directly at login, but a bit more vague */ - pam_info(pamh, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory.", j, area); + sym_pam_info(pamh, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory.", j, area); area = NULL; } else { /* Validate that the target is definitely owned by user */ @@ -1589,10 +1587,10 @@ static int setup_environment( return pam_syslog_errno(pamh, LOG_ERR, errno, "Unable to fstat() target area directory '%s': %m", ha); if (st.st_uid != ur->uid) { - pam_syslog(pamh, LOG_ERR, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); + sym_pam_syslog(pamh, LOG_ERR, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); /* Also tell the user directly at login. */ - pam_info(pamh, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); + sym_pam_info(pamh, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); area = NULL; } else { /* All good, now make a copy of the area string, since we quite likely are @@ -1631,13 +1629,13 @@ static int open_osc_context(pam_handle_t *pamh, const char *session_type, UserRe if (!streq_ptr(session_type, "tty")) return PAM_SUCCESS; - const char *e = pam_getenv(pamh, "TERM"); + const char *e = sym_pam_getenv(pamh, "TERM"); if (!e) e = getenv("TERM"); if (streq_ptr(e, "dumb")) return PAM_SUCCESS; - /* NB: we output directly to stdout, instead of going via pam_info() or so, because that's too + /* NB: we output directly to stdout, instead of going via sym_pam_info() or so, because that's too * high-level for us, as it suffixes the output with a newline, expecting a full blown text message * as prompt string, not just an ANSI sequence. Note that PAM's conv_misc() actually goes to stdout * anyway, hence let's do so here too, but only after careful validation. */ @@ -1657,7 +1655,7 @@ static int open_osc_context(pam_handle_t *pamh, const char *session_type, UserRe sd_id128_t osc_id; r = osc_context_open_session( ur->user_name, - pam_getenv(pamh, "XDG_SESSION_ID"), + sym_pam_getenv(pamh, "XDG_SESSION_ID"), &osc, &osc_id); if (r < 0) @@ -1672,7 +1670,7 @@ static int open_osc_context(pam_handle_t *pamh, const char *session_type, UserRe if (!osc_id_copy) return pam_log_oom(pamh); - r = pam_set_data(pamh, "systemd.osc-context-id", osc_id_copy, pam_cleanup_free); + r = sym_pam_set_data(pamh, "systemd.osc-context-id", osc_id_copy, pam_cleanup_free); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM OSC sequence ID data: @PAMERR@"); @@ -1680,7 +1678,7 @@ static int open_osc_context(pam_handle_t *pamh, const char *session_type, UserRe TAKE_PTR(osc_id_copy); if (tty_opath_fd >= 0) { - r = pam_set_data(pamh, "systemd.osc-context-fd", FD_TO_PTR(tty_opath_fd), pam_cleanup_close); + r = sym_pam_set_data(pamh, "systemd.osc-context-fd", FD_TO_PTR(tty_opath_fd), pam_cleanup_close); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM OSC sequence fd data: @PAMERR@"); @@ -1698,7 +1696,7 @@ static int close_osc_context(pam_handle_t *pamh, bool debug) { const void *p; int tty_opath_fd = -EBADF; - r = pam_get_data(pamh, "systemd.osc-context-fd", &p); + r = sym_pam_get_data(pamh, "systemd.osc-context-fd", &p); if (r == PAM_SUCCESS) tty_opath_fd = PTR_TO_FD(p); else if (r != PAM_NO_MODULE_DATA) @@ -1707,7 +1705,7 @@ static int close_osc_context(pam_handle_t *pamh, bool debug) { return PAM_SUCCESS; const sd_id128_t *osc_id = NULL; - r = pam_get_data(pamh, "systemd.osc-context-id", (const void**) &osc_id); + r = sym_pam_get_data(pamh, "systemd.osc-context-id", (const void**) &osc_id); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM OSC context id data: @PAMERR@"); if (!osc_id) @@ -1721,7 +1719,7 @@ static int close_osc_context(pam_handle_t *pamh, bool debug) { } /* /bin/login calls us with fds 0, 1, 2 closed, which is just weird. Let's step outside of that - * range, just in case pam_syslog() or so logs to stderr */ + * range, just in case sym_pam_syslog() or so logs to stderr */ fd = fd_move_above_stdio(fd); /* Safety check, let's verify this is a valid TTY we just opened */ @@ -1849,6 +1847,10 @@ _public_ PAM_EXTERN int pam_sm_close_session( assert(pamh); + r = dlopen_libpam(LOG_DEBUG); + if (r < 0) + return PAM_SERVICE_ERR; + pam_log_setup(); if (parse_argv(pamh, @@ -1866,7 +1868,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( (void) close_osc_context(pamh, debug); - id = pam_getenv(pamh, "XDG_SESSION_ID"); + id = sym_pam_getenv(pamh, "XDG_SESSION_ID"); if (id) { _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; bool done = false; diff --git a/src/login/pam_systemd_loadkey.c b/src/login/pam_systemd_loadkey.c index 93ccddc25b..9d44863b02 100644 --- a/src/login/pam_systemd_loadkey.c +++ b/src/login/pam_systemd_loadkey.c @@ -41,7 +41,7 @@ _public_ PAM_EXTERN int pam_sm_authenticate( else if (streq(argv[i], "debug")) debug = true; else - pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + sym_pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } pam_debug_syslog(pamh, debug, "pam-systemd-loadkey: initializing..."); @@ -81,7 +81,7 @@ _public_ PAM_EXTERN int pam_sm_authenticate( } else if (passwords_len > 1) pam_debug_syslog(pamh, debug, "Multiple passwords found in the key. Using the last one."); - r = pam_set_item(pamh, PAM_AUTHTOK, passwords[passwords_len - 1]); + r = sym_pam_set_item(pamh, PAM_AUTHTOK, passwords[passwords_len - 1]); if (r != PAM_SUCCESS) return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); diff --git a/src/machine/meson.build b/src/machine/meson.build index 13756cb8a1..fc16e9f5c5 100644 --- a/src/machine/meson.build +++ b/src/machine/meson.build @@ -36,13 +36,11 @@ executables += [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ], }, test_template + { 'sources' : files('test-machine-tables.c'), 'objects' : ['systemd-machined'], - 'dependencies': threads, }, ] diff --git a/src/network/meson.build b/src/network/meson.build index 0319102492..23f6f3a4fe 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -188,7 +188,6 @@ network_fuzz_template = fuzz_template + { libsystemd_network, ], 'objects' : ['systemd-networkd'], - 'dependencies' : threads, 'include_directories' : network_includes, } @@ -204,7 +203,6 @@ executables += [ libsystemd_network, networkd_link_with, ], - 'dependencies' : threads, 'bpf_programs': [ 'sysctl-monitor', ] @@ -240,11 +238,9 @@ executables += [ }, network_test_template + { 'sources' : files('test-network-tables.c'), - 'dependencies' : threads, }, network_test_template + { 'sources' : files('test-network.c'), - 'dependencies' : threads, }, network_test_template + { 'sources' : files('test-networkd-address.c'), diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 0801ba977a..ba90d342c5 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -5,7 +5,7 @@ #include "sd-messages.h" #include "af-list.h" -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "conf-parser.h" #include "alloc-util.h" #include "cgroup-util.h" diff --git a/src/nsresourced/meson.build b/src/nsresourced/meson.build index 881fd911e4..1654e1766b 100644 --- a/src/nsresourced/meson.build +++ b/src/nsresourced/meson.build @@ -24,13 +24,11 @@ executables += [ 'name' : 'systemd-nsresourced', 'sources' : systemd_nsresourced_sources, 'extract' : systemd_nsresourced_extract_sources, - 'dependencies' : threads, 'bpf_programs': ['userns-restrict'], }, libexec_template + { 'name' : 'systemd-nsresourcework', 'sources' : systemd_nsresourcework_sources, - 'dependencies' : threads, 'objects' : ['systemd-nsresourced'], 'bpf_programs': ['userns-restrict'], }, diff --git a/src/nsresourced/nsresourced-manager.c b/src/nsresourced/nsresourced-manager.c index 406db72e7d..c2a6cd6eab 100644 --- a/src/nsresourced/nsresourced-manager.c +++ b/src/nsresourced/nsresourced-manager.c @@ -5,7 +5,7 @@ #include "sd-daemon.h" -#include "bpf-dlopen.h" +#include "bpf-util.h" #if HAVE_VMLINUX_H #include "bpf-link.h" #include "userns-restrict-skel.h" diff --git a/src/nsresourced/userns-restrict.c b/src/nsresourced/userns-restrict.c index a6cdd03c5e..bc7bac6942 100644 --- a/src/nsresourced/userns-restrict.c +++ b/src/nsresourced/userns-restrict.c @@ -6,7 +6,7 @@ #include "userns-restrict-skel.h" #endif -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "fd-util.h" #include "log.h" diff --git a/src/portable/meson.build b/src/portable/meson.build index 3029ad4177..0bd5d1c3ce 100644 --- a/src/portable/meson.build +++ b/src/portable/meson.build @@ -32,7 +32,6 @@ executables += [ libcryptsetup_cflags, libmount_cflags, libselinux_cflags, - threads, ], }, executable_template + { @@ -40,7 +39,6 @@ executables += [ 'public' : true, 'sources' : files('portablectl.c'), 'link_with' : portabled_link_with, - 'dependencies' : threads, }, ] diff --git a/src/pstore/meson.build b/src/pstore/meson.build index d6bb925789..a94f1b1e88 100644 --- a/src/pstore/meson.build +++ b/src/pstore/meson.build @@ -12,7 +12,6 @@ executables += [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ], }, ] diff --git a/src/repart/meson.build b/src/repart/meson.build index 9b89f56f7a..bb5b63be05 100644 --- a/src/repart/meson.build +++ b/src/repart/meson.build @@ -17,7 +17,6 @@ executables += [ libfdisk_cflags, libmount_cflags, libopenssl_cflags, - threads, ], }, executable_template + { @@ -35,7 +34,6 @@ executables += [ libfdisk_cflags, libmount_cflags, libopenssl_cflags, - threads, ], }, ] diff --git a/src/resolve/meson.build b/src/resolve/meson.build index 5802889746..3650313355 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -72,7 +72,6 @@ resolve_common_template = { libidn2_cflags, libopenssl_cflags, libm, - threads, ], } diff --git a/src/shared/bpf-compat.h b/src/shared/bpf-compat.h deleted file mode 100644 index 7f76ee87a0..0000000000 --- a/src/shared/bpf-compat.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include - -/* libbpf has been moving quickly. - * They added new symbols in the 0.x versions and shortly after removed - * deprecated symbols in 1.0. - * We only need bpf_map_create and libbpf_probe_bpf_prog_type so we work - * around the incompatibility here by: - * - declaring both symbols, and looking for either depending on the libbpf - * so version we found - * - having helpers that automatically use the appropriate version behind the - * new API for easy cleanup later - * - * The advantage of doing this instead of only looking for the symbols declared at - * compile time is that we can then load either the old or the new symbols at runtime - * regardless of the version we were compiled with */ - -/* declare the struct for libbpf <= 0.6.0 -- it causes no harm on newer versions */ -struct bpf_map_create_opts; - -/* new symbols available from 0.7.0. - * We need the symbols here: - * - after bpf_map_create_opts struct has been defined for older libbpf - * - before the compat static inline helpers that use them. - * When removing this file move these back to bpf-dlopen.h */ -extern int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *); -extern struct bpf_map* (*sym_bpf_object__next_map)(const struct bpf_object *obj, const struct bpf_map *map); - -/* compat symbols removed in libbpf 1.0 */ -extern int (*sym_bpf_create_map)(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags); - -/* helpers to use the available variant behind new API */ -static inline int compat_bpf_map_create( - enum bpf_map_type map_type, - const char *map_name, - __u32 key_size, - __u32 value_size, - __u32 max_entries, - const struct bpf_map_create_opts *opts) { - - if (sym_bpf_map_create) - return sym_bpf_map_create(map_type, map_name, key_size, - value_size, max_entries, opts); - - return sym_bpf_create_map(map_type, key_size, value_size, max_entries, - 0 /* opts->map_flags, but opts is always NULL for us so skip build dependency on the type */); -} diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c deleted file mode 100644 index ca74682823..0000000000 --- a/src/shared/bpf-dlopen.c +++ /dev/null @@ -1,221 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "sd-dlopen.h" - -#include "bpf-dlopen.h" -#include "dlfcn-util.h" -#include "errno-util.h" -#include "initrd-util.h" -#include "log.h" - -#if HAVE_LIBBPF - -/* libbpf changed types of function prototypes around, so we need to disable some type checking for older - * libbpf. We consider everything older than 0.7 too old for accurate type checks. */ -#if defined(__LIBBPF_CURRENT_VERSION_GEQ) -#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7) -#define MODERN_LIBBPF 1 -#endif -#endif -#if !defined(MODERN_LIBBPF) -#define MODERN_LIBBPF 0 -#endif - -static void *bpf_dl = NULL; - -static DLSYM_PROTOTYPE(libbpf_get_error) = NULL; - -DLSYM_PROTOTYPE(bpf_link__destroy) = NULL; -DLSYM_PROTOTYPE(bpf_link__fd) = NULL; -DLSYM_PROTOTYPE(bpf_link__open) = NULL; -DLSYM_PROTOTYPE(bpf_link__pin) = NULL; -DLSYM_PROTOTYPE(bpf_map__fd) = NULL; -DLSYM_PROTOTYPE(bpf_map__name) = NULL; -DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL; -DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL; -DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL; -DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL; -DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL; -DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL; -DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL; -DLSYM_PROTOTYPE(bpf_obj_get_info_by_fd) = NULL; -DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL; -DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL; -DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL; -DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL; -DLSYM_PROTOTYPE(bpf_object__name) = NULL; -DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL; -DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL; -DLSYM_PROTOTYPE(bpf_program__attach) = NULL; -DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL; -DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL; -DLSYM_PROTOTYPE(bpf_program__name) = NULL; -DLSYM_PROTOTYPE(bpf_program__set_autoload) = NULL; -DLSYM_PROTOTYPE(libbpf_set_print) = NULL; -DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL; -DLSYM_PROTOTYPE(ring_buffer__free) = NULL; -DLSYM_PROTOTYPE(ring_buffer__new) = NULL; -DLSYM_PROTOTYPE(ring_buffer__poll) = NULL; - -/* new symbols available from libbpf 0.7.0 */ -int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *); -struct bpf_map* (*sym_bpf_object__next_map)(const struct bpf_object *obj, const struct bpf_map *map); - -/* compat symbols removed in libbpf 1.0 */ -int (*sym_bpf_create_map)(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags); - -_printf_(2,0) -static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) { -#if !LOG_TRACE - /* libbpf logs a lot of details at its debug level, which we don't need to see. */ - if (level == LIBBPF_DEBUG) - return 0; -#endif - /* All other levels are downgraded to LOG_DEBUG */ - - /* errno is used here, on the assumption that if the log message uses %m, errno will be set to - * something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */ - return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap); -} - -int dlopen_bpf(int log_level) { - static int cached = 0; - int r; - - if (cached != 0) - return cached; - - SD_ELF_NOTE_DLOPEN( - "bpf", - "Support firewalling and sandboxing with BPF", - SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, - "libbpf.so.1", "libbpf.so.0"); - - DISABLE_WARNING_DEPRECATED_DECLARATIONS; - - _cleanup_(dlclosep) void *dl = NULL; - r = dlopen_safe("libbpf.so.1", &dl, /* reterr_dlerror= */ NULL); - if (r < 0) { - /* libbpf < 1.0.0 (we rely on 0.1.0+) provide most symbols we care about, but - * unfortunately not all until 0.7.0. See bpf-compat.h for more details. - * Once we consider we can assume 0.7+ is present we can just use the same symbol - * list for both files, and when we assume 1.0+ is present we can remove this dlopen */ - const char *dle = NULL; - r = dlopen_safe("libbpf.so.0", &dl, &dle); - if (r < 0) { - log_full_errno(in_initrd() ? LOG_DEBUG : log_level, r, - "Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled: %s", dle ?: STRERROR(r)); - return (cached = -EOPNOTSUPP); /* turn into recognizable error */ - } - - log_debug("Loaded 'libbpf.so.0' via dlopen()"); - - /* symbols deprecated in 1.0 we use as compat */ - r = dlsym_many_or_warn( - dl, LOG_DEBUG, -#if MODERN_LIBBPF - /* Don't exist anymore in new libbpf, hence cannot type check them */ - DLSYM_ARG_FORCE(bpf_create_map) -#else - DLSYM_ARG(bpf_create_map) -#endif - ); - - /* NB: we don't try to load bpf_object__next_map() on old versions */ - } else { - log_debug("Loaded 'libbpf.so.1' via dlopen()"); - - /* symbols available from 0.7.0 */ - r = dlsym_many_or_warn( - dl, LOG_DEBUG, -#if MODERN_LIBBPF - DLSYM_ARG(bpf_map_create), - DLSYM_ARG(bpf_object__next_map) -#else - /* These symbols did not exist in old libbpf, hence we cannot type check them */ - DLSYM_ARG_FORCE(bpf_map_create), - DLSYM_ARG_FORCE(bpf_object__next_map) -#endif - ); - } - if (r < 0) - return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m"); - - r = dlsym_many_or_warn( - dl, LOG_DEBUG, - DLSYM_ARG(bpf_link__destroy), - DLSYM_ARG(bpf_link__fd), - DLSYM_ARG(bpf_link__open), - DLSYM_ARG(bpf_link__pin), - DLSYM_ARG(bpf_map__fd), - DLSYM_ARG(bpf_map__name), - DLSYM_ARG(bpf_map__set_inner_map_fd), - DLSYM_ARG(bpf_map__set_max_entries), - DLSYM_ARG(bpf_map__set_pin_path), - DLSYM_ARG(bpf_map_delete_elem), - DLSYM_ARG(bpf_map_get_fd_by_id), - DLSYM_ARG(bpf_map_lookup_elem), - DLSYM_ARG(bpf_map_update_elem), - DLSYM_ARG(bpf_obj_get_info_by_fd), - DLSYM_ARG(bpf_object__attach_skeleton), - DLSYM_ARG(bpf_object__destroy_skeleton), - DLSYM_ARG(bpf_object__detach_skeleton), - DLSYM_ARG(bpf_object__load_skeleton), - DLSYM_ARG(bpf_object__name), - DLSYM_ARG(bpf_object__open_skeleton), - DLSYM_ARG(bpf_object__pin_maps), -#if MODERN_LIBBPF - DLSYM_ARG(bpf_program__attach), - DLSYM_ARG(bpf_program__attach_cgroup), - DLSYM_ARG(bpf_program__attach_lsm), -#else - /* libbpf added a "const" to function parameters where it should not have, ignore this type incompatibility */ - DLSYM_ARG_FORCE(bpf_program__attach), - DLSYM_ARG_FORCE(bpf_program__attach_cgroup), - DLSYM_ARG_FORCE(bpf_program__attach_lsm), -#endif - DLSYM_ARG(bpf_program__name), - DLSYM_ARG(bpf_program__set_autoload), - DLSYM_ARG(libbpf_get_error), - DLSYM_ARG(libbpf_set_print), - DLSYM_ARG(ring_buffer__epoll_fd), - DLSYM_ARG(ring_buffer__free), - DLSYM_ARG(ring_buffer__new), - DLSYM_ARG(ring_buffer__poll)); - if (r < 0) - return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m"); - - /* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */ - (void) sym_libbpf_set_print(bpf_print_func); - - REENABLE_WARNING; - - bpf_dl = TAKE_PTR(dl); - - return cached = true; -} - -int bpf_get_error_translated(const void *ptr) { - int r; - - r = sym_libbpf_get_error(ptr); - - switch (r) { - case -524: - /* Workaround for kernel bug, BPF returns an internal error instead of translating it, until - * it is fixed: - * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27 - */ - return -EOPNOTSUPP; - default: - return r; - } -} - -#else - -int dlopen_bpf(int log_level) { - return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), - "libbpf support is not compiled in, cgroup BPF features disabled."); -} -#endif diff --git a/src/shared/bpf-link.c b/src/shared/bpf-link.c index 80a6db47de..4ae402625b 100644 --- a/src/shared/bpf-link.c +++ b/src/shared/bpf-link.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "bpf-link.h" #include "serialize.h" diff --git a/src/shared/bpf-util.c b/src/shared/bpf-util.c new file mode 100644 index 0000000000..03f3281b07 --- /dev/null +++ b/src/shared/bpf-util.c @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-dlopen.h" + +#include "bpf-util.h" +#include "dlfcn-util.h" +#include "initrd-util.h" +#include "log.h" +#include "strv.h" + +#if HAVE_LIBBPF + +/* libbpf changed types of function prototypes around, so we need to disable some type checking for older + * libbpf. We consider everything older than 0.7 too old for accurate type checks. */ +#if defined(__LIBBPF_CURRENT_VERSION_GEQ) +#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7) +#define MODERN_LIBBPF 1 +#endif +#endif +#if !defined(MODERN_LIBBPF) +#define MODERN_LIBBPF 0 +#endif + +static DLSYM_PROTOTYPE(libbpf_get_error) = NULL; + +DLSYM_PROTOTYPE(bpf_create_map) = NULL; +DLSYM_PROTOTYPE(bpf_link__destroy) = NULL; +DLSYM_PROTOTYPE(bpf_link__fd) = NULL; +DLSYM_PROTOTYPE(bpf_link__open) = NULL; +DLSYM_PROTOTYPE(bpf_link__pin) = NULL; +DLSYM_PROTOTYPE(bpf_map__fd) = NULL; +DLSYM_PROTOTYPE(bpf_map__name) = NULL; +DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL; +DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL; +DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL; +DLSYM_PROTOTYPE(bpf_map_create) = NULL; +DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL; +DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL; +DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL; +DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL; +DLSYM_PROTOTYPE(bpf_obj_get_info_by_fd) = NULL; +DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL; +DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL; +DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL; +DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL; +DLSYM_PROTOTYPE(bpf_object__name) = NULL; +DLSYM_PROTOTYPE(bpf_object__next_map) = NULL; +DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL; +DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL; +DLSYM_PROTOTYPE(bpf_program__attach) = NULL; +DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL; +DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL; +DLSYM_PROTOTYPE(bpf_program__name) = NULL; +DLSYM_PROTOTYPE(bpf_program__set_autoload) = NULL; +static int missing_bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts) { + return -ENOSYS; +} +DLSYM_PROTOTYPE(bpf_token_create) = missing_bpf_token_create; +DLSYM_PROTOTYPE(libbpf_set_print) = NULL; +DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL; +DLSYM_PROTOTYPE(ring_buffer__free) = NULL; +DLSYM_PROTOTYPE(ring_buffer__new) = NULL; +DLSYM_PROTOTYPE(ring_buffer__poll) = NULL; + +_printf_(2,0) +static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) { +#if !LOG_TRACE + /* libbpf logs a lot of details at its debug level, which we don't need to see. */ + if (level == LIBBPF_DEBUG) + return 0; +#endif + /* All other levels are downgraded to LOG_DEBUG */ + + /* errno is used here, on the assumption that if the log message uses %m, errno will be set to + * something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */ + return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap); +} + +int dlopen_bpf(int log_level) { + static void *bpf_dl = NULL; + int r; + + SD_ELF_NOTE_DLOPEN( + "bpf", + "Support firewalling and sandboxing with BPF", + SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libbpf.so.1", "libbpf.so.0"); + + DISABLE_WARNING_DEPRECATED_DECLARATIONS; + + FOREACH_STRING(soname, "libbpf.so.1", "libbpf.so.0") { + r = dlopen_many_sym_or_warn( + &bpf_dl, soname, LOG_DEBUG, + DLSYM_ARG(bpf_link__destroy), + DLSYM_ARG(bpf_link__fd), + DLSYM_ARG(bpf_link__open), + DLSYM_ARG(bpf_link__pin), + DLSYM_ARG(bpf_map__fd), + DLSYM_ARG(bpf_map__name), + DLSYM_ARG(bpf_map__set_inner_map_fd), + DLSYM_ARG(bpf_map__set_max_entries), + DLSYM_ARG(bpf_map__set_pin_path), + DLSYM_ARG(bpf_map_delete_elem), + DLSYM_ARG(bpf_map_get_fd_by_id), + DLSYM_ARG(bpf_map_lookup_elem), + DLSYM_ARG(bpf_map_update_elem), + DLSYM_ARG(bpf_obj_get_info_by_fd), + DLSYM_ARG(bpf_object__attach_skeleton), + DLSYM_ARG(bpf_object__destroy_skeleton), + DLSYM_ARG(bpf_object__detach_skeleton), + DLSYM_ARG(bpf_object__load_skeleton), + DLSYM_ARG(bpf_object__name), + DLSYM_ARG(bpf_object__open_skeleton), + DLSYM_ARG(bpf_object__pin_maps), +#if MODERN_LIBBPF + DLSYM_ARG(bpf_program__attach), + DLSYM_ARG(bpf_program__attach_cgroup), + DLSYM_ARG(bpf_program__attach_lsm), +#else + /* libbpf added a "const" to function parameters where it should not have, ignore this type incompatibility */ + DLSYM_ARG_FORCE(bpf_program__attach), + DLSYM_ARG_FORCE(bpf_program__attach_cgroup), + DLSYM_ARG_FORCE(bpf_program__attach_lsm), +#endif + DLSYM_ARG(bpf_program__name), + DLSYM_ARG(bpf_program__set_autoload), + DLSYM_ARG(libbpf_get_error), + DLSYM_ARG(libbpf_set_print), + DLSYM_ARG(ring_buffer__epoll_fd), + DLSYM_ARG(ring_buffer__free), + DLSYM_ARG(ring_buffer__new), + DLSYM_ARG(ring_buffer__poll)); + if (r >= 0) + break; + } + REENABLE_WARNING; + if (r < 0) + return log_full_errno(in_initrd() ? LOG_DEBUG : log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), + "Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled."); + + /* Version-specific symbols: bpf_create_map exists only in libbpf < 1.0; bpf_map_create and + * bpf_object__next_map only in 0.7+. bpf_token_create only in 1.5+. Unresolved prototypes keep + * their initializers (NULL, or a fallback returning -ENOSYS for bpf_token_create). */ + DLSYM_OPTIONAL(bpf_dl, bpf_create_map); + DLSYM_OPTIONAL(bpf_dl, bpf_map_create); + DLSYM_OPTIONAL(bpf_dl, bpf_object__next_map); + DLSYM_OPTIONAL(bpf_dl, bpf_token_create); + + /* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */ + (void) sym_libbpf_set_print(bpf_print_func); + + return 1; +} + +int bpf_get_error_translated(const void *ptr) { + int r; + + r = sym_libbpf_get_error(ptr); + + switch (r) { + case -524: + /* Workaround for kernel bug, BPF returns an internal error instead of translating it, until + * it is fixed: + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27 + */ + return -EOPNOTSUPP; + default: + return r; + } +} + +#else + +int dlopen_bpf(int log_level) { + return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), + "libbpf support is not compiled in, cgroup BPF features disabled."); +} +#endif diff --git a/src/shared/bpf-dlopen.h b/src/shared/bpf-util.h similarity index 52% rename from src/shared/bpf-dlopen.h rename to src/shared/bpf-util.h index 62ea9cf707..622e4c2e28 100644 --- a/src/shared/bpf-dlopen.h +++ b/src/shared/bpf-util.h @@ -8,10 +8,27 @@ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ -#include "bpf-compat.h" /* IWYU pragma: export */ #include "dlfcn-util.h" #include "shared-forward.h" +/* Always redeclare these so DLSYM_PROTOTYPE's typeof() resolves regardless of libbpf version; + * suppress the warning when the libbpf headers already declare them. + * - bpf_map_create, bpf_object__next_map: available since libbpf 0.7 + * - bpf_token_create: available since libbpf 1.5 + * - bpf_create_map: removed in libbpf 1.0 + */ +DISABLE_WARNING_REDUNDANT_DECLS; +/* NOLINTBEGIN(readability-redundant-declaration) */ +struct bpf_map_create_opts; +struct bpf_token_create_opts; +extern int bpf_create_map(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags); +extern int bpf_map_create(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *); +extern struct bpf_map* bpf_object__next_map(const struct bpf_object *obj, const struct bpf_map *map); +extern int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts); +/* NOLINTEND(readability-redundant-declaration) */ +REENABLE_WARNING; + +extern DLSYM_PROTOTYPE(bpf_create_map); extern DLSYM_PROTOTYPE(bpf_link__destroy); extern DLSYM_PROTOTYPE(bpf_link__fd); extern DLSYM_PROTOTYPE(bpf_link__open); @@ -21,6 +38,7 @@ extern DLSYM_PROTOTYPE(bpf_map__name); extern DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd); extern DLSYM_PROTOTYPE(bpf_map__set_max_entries); extern DLSYM_PROTOTYPE(bpf_map__set_pin_path); +extern DLSYM_PROTOTYPE(bpf_map_create); extern DLSYM_PROTOTYPE(bpf_map_delete_elem); extern DLSYM_PROTOTYPE(bpf_map_get_fd_by_id); extern DLSYM_PROTOTYPE(bpf_map_lookup_elem); @@ -33,6 +51,7 @@ extern DLSYM_PROTOTYPE(bpf_object__destroy_skeleton); extern DLSYM_PROTOTYPE(bpf_object__detach_skeleton); extern DLSYM_PROTOTYPE(bpf_object__load_skeleton); extern DLSYM_PROTOTYPE(bpf_object__name); +extern DLSYM_PROTOTYPE(bpf_object__next_map); extern DLSYM_PROTOTYPE(bpf_object__open_skeleton); extern DLSYM_PROTOTYPE(bpf_object__pin_maps); extern DLSYM_PROTOTYPE(bpf_program__attach); @@ -40,12 +59,30 @@ extern DLSYM_PROTOTYPE(bpf_program__attach_cgroup); extern DLSYM_PROTOTYPE(bpf_program__attach_lsm); extern DLSYM_PROTOTYPE(bpf_program__name); extern DLSYM_PROTOTYPE(bpf_program__set_autoload); +extern DLSYM_PROTOTYPE(bpf_token_create); extern DLSYM_PROTOTYPE(libbpf_set_print); extern DLSYM_PROTOTYPE(ring_buffer__epoll_fd); extern DLSYM_PROTOTYPE(ring_buffer__free); extern DLSYM_PROTOTYPE(ring_buffer__new); extern DLSYM_PROTOTYPE(ring_buffer__poll); +/* Helper that uses the available variant behind the new API. */ +static inline int compat_bpf_map_create( + enum bpf_map_type map_type, + const char *map_name, + __u32 key_size, + __u32 value_size, + __u32 max_entries, + const struct bpf_map_create_opts *opts) { + + if (sym_bpf_map_create) + return sym_bpf_map_create(map_type, map_name, key_size, + value_size, max_entries, opts); + + return sym_bpf_create_map(map_type, key_size, value_size, max_entries, + 0 /* opts->map_flags, but opts is always NULL for us so skip build dependency on the type */); +} + /* libbpf sometimes returns error codes that make sense only in the kernel, like 524 for EOPNOTSUPP. Use * this helper instead of libbpf_get_error() to ensure some of the known ones are translated into errnos * we understand. */ diff --git a/src/shared/color-util.c b/src/shared/color-util.c index 1912785954..f2add33b1d 100644 --- a/src/shared/color-util.c +++ b/src/shared/color-util.c @@ -11,8 +11,8 @@ void rgb_to_hsv(double r, double g, double b, assert(g >= 0 && g <= 1); assert(b >= 0 && b <= 1); - double max_color = fmax(r, fmax(g, b)); - double min_color = fmin(r, fmin(g, b)); + double max_color = MAX(r, MAX(g, b)); + double min_color = MIN(r, MIN(g, b)); double delta = max_color - min_color; if (ret_v) @@ -32,13 +32,15 @@ void rgb_to_hsv(double r, double g, double b, if (ret_h) { if (delta > 0) { if (r >= max_color) - *ret_h = 60 * fmod((g - b) / delta, 6); + *ret_h = 60 * (g - b) / delta; else if (g >= max_color) *ret_h = 60 * (((b - r) / delta) + 2); - else if (b >= max_color) + else /* b >= max_color */ *ret_h = 60 * (((r - g) / delta) + 4); - *ret_h = fmod(*ret_h, 360); + /* The r-max branch produces (-60, 60); fold the negative half up. */ + if (*ret_h < 0) + *ret_h += 360; } else *ret_h = NAN; } @@ -49,29 +51,33 @@ void hsv_to_rgb(double h, double s, double v, double c, x, m, r, g, b; + assert(h >= 0 && h <= 360); assert(s >= 0 && s <= 100); assert(v >= 0 && v <= 100); assert(ret_r); assert(ret_g); assert(ret_b); - h = fmod(h, 360); c = (s / 100.0) * (v / 100.0); - x = c * (1 - fabs(fmod(h / 60.0, 2) - 1)); m = (v / 100) - c; - if (h >= 0 && h < 60) - r = c, g = x, b = 0.0; - else if (h >= 60 && h < 120) - r = x, g = c, b = 0.0; - else if (h >= 120 && h < 180) - r = 0.0, g = c, b = x; - else if (h >= 180 && h < 240) - r = 0.0, g = x, b = c; - else if (h >= 240 && h < 300) - r = x, g = 0.0, b = c; - else - r = c, g = 0.0, b = x; + /* Split h into sector index k ∈ [0, 6] and fractional offset f ∈ [0, 1) within the sector. + * Within each sector exactly one of {r, g, b} equals c, one equals 0, and the third (x) + * ramps linearly between them — ascending in even sectors, descending in odd. h == 360 is + * the cyclic boundary equivalent to h == 0, and maps to sector 0. */ + double seg = h / 60.0; + int k = (int) seg % 6; + double f = seg - (int) seg; + x = c * (k & 1 ? 1.0 - f : f); + + switch (k) { + case 0: r = c; g = x; b = 0.0; break; + case 1: r = x; g = c; b = 0.0; break; + case 2: r = 0.0; g = c; b = x; break; + case 3: r = 0.0; g = x; b = c; break; + case 4: r = x; g = 0.0; b = c; break; + default: r = c; g = 0.0; b = x; break; + } *ret_r = (uint8_t) ((r + m) * 255); *ret_g = (uint8_t) ((g + m) * 255); diff --git a/src/shared/cryptsetup-util.c b/src/shared/cryptsetup-util.c index 7aa3d5d9c5..a51783cb29 100644 --- a/src/shared/cryptsetup-util.c +++ b/src/shared/cryptsetup-util.c @@ -45,6 +45,7 @@ DLSYM_PROTOTYPE(crypt_keyslot_destroy) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_max) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_status) = NULL; DLSYM_PROTOTYPE(crypt_load) = NULL; +DLSYM_PROTOTYPE(crypt_logf) = NULL; DLSYM_PROTOTYPE(crypt_metadata_locking) = NULL; DLSYM_PROTOTYPE(crypt_persistent_flags_get) = NULL; DLSYM_PROTOTYPE(crypt_persistent_flags_set) = NULL; @@ -315,6 +316,7 @@ int dlopen_cryptsetup(int log_level) { DLSYM_ARG(crypt_keyslot_max), DLSYM_ARG(crypt_keyslot_status), DLSYM_ARG(crypt_load), + DLSYM_ARG(crypt_logf), DLSYM_ARG(crypt_metadata_locking), DLSYM_ARG(crypt_persistent_flags_get), DLSYM_ARG(crypt_persistent_flags_set), diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h index 5c83aad8ee..23d52d111a 100644 --- a/src/shared/cryptsetup-util.h +++ b/src/shared/cryptsetup-util.h @@ -46,6 +46,7 @@ extern DLSYM_PROTOTYPE(crypt_keyslot_destroy); extern DLSYM_PROTOTYPE(crypt_keyslot_max); extern DLSYM_PROTOTYPE(crypt_keyslot_status); extern DLSYM_PROTOTYPE(crypt_load); +extern DLSYM_PROTOTYPE(crypt_logf); extern DLSYM_PROTOTYPE(crypt_metadata_locking); extern DLSYM_PROTOTYPE(crypt_persistent_flags_get); extern DLSYM_PROTOTYPE(crypt_persistent_flags_set); diff --git a/src/shared/meson.build b/src/shared/meson.build index 9b539f7983..55cf8364d3 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -19,8 +19,8 @@ shared_sources = files( 'boot-entry.c', 'boot-timestamps.c', 'bootspec.c', - 'bpf-dlopen.c', 'bpf-program.c', + 'bpf-util.c', 'bridge-util.c', 'btrfs-util.c', 'bus-get-properties.c', @@ -383,8 +383,7 @@ shared_sources += [dns_type_from_name_inc, dns_type_to_name_inc] libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag) -libshared_deps = [threads, - libacl_cflags, +libshared_deps = [libacl_cflags, libapparmor_cflags, libarchive_cflags, libaudit_cflags, @@ -393,7 +392,6 @@ libshared_deps = [threads, libcrypt_cflags, libcryptsetup_cflags, libcurl_cflags, - libdl, libdw_cflags, libelf_cflags, libfdisk_cflags, @@ -410,7 +408,6 @@ libshared_deps = [threads, libpcre2_cflags, libpwquality_cflags, libqrencode_cflags, - librt, libseccomp_cflags, libselinux_cflags, libxenctrl_cflags, diff --git a/src/shared/pam-util.c b/src/shared/pam-util.c index 9728c3e00d..37f2caf31e 100644 --- a/src/shared/pam-util.c +++ b/src/shared/pam-util.c @@ -25,10 +25,15 @@ static void *libpam_dl = NULL; DLSYM_PROTOTYPE(pam_acct_mgmt) = NULL; DLSYM_PROTOTYPE(pam_close_session) = NULL; DLSYM_PROTOTYPE(pam_end) = NULL; +DLSYM_PROTOTYPE(pam_get_authtok_noverify) = NULL; +DLSYM_PROTOTYPE(pam_get_authtok_verify) = NULL; DLSYM_PROTOTYPE(pam_get_data) = NULL; DLSYM_PROTOTYPE(pam_get_item) = NULL; +DLSYM_PROTOTYPE(pam_get_user) = NULL; +DLSYM_PROTOTYPE(pam_getenv) = NULL; DLSYM_PROTOTYPE(pam_getenvlist) = NULL; DLSYM_PROTOTYPE(pam_open_session) = NULL; +DLSYM_PROTOTYPE(pam_prompt) = NULL; DLSYM_PROTOTYPE(pam_putenv) = NULL; DLSYM_PROTOTYPE(pam_set_data) = NULL; DLSYM_PROTOTYPE(pam_set_item) = NULL; @@ -361,6 +366,19 @@ int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, cons return PAM_SUCCESS; } +int pam_putenv_assign(pam_handle_t *pamh, const char *name, const char *value) { + _cleanup_(erase_and_freep) char *s = NULL; + + assert(pamh); + assert(name); + assert(value); + + if (asprintf(&s, "%s=%s", name, value) < 0) + return PAM_BUF_ERR; + + return sym_pam_putenv(pamh, s); +} + #endif int dlopen_libpam(int log_level) { @@ -378,10 +396,15 @@ int dlopen_libpam(int log_level) { DLSYM_ARG(pam_acct_mgmt), DLSYM_ARG(pam_close_session), DLSYM_ARG(pam_end), + DLSYM_ARG(pam_get_authtok_noverify), + DLSYM_ARG(pam_get_authtok_verify), DLSYM_ARG(pam_get_data), DLSYM_ARG(pam_get_item), + DLSYM_ARG(pam_get_user), + DLSYM_ARG(pam_getenv), DLSYM_ARG(pam_getenvlist), DLSYM_ARG(pam_open_session), + DLSYM_ARG(pam_prompt), DLSYM_ARG(pam_putenv), DLSYM_ARG(pam_set_data), DLSYM_ARG(pam_set_item), diff --git a/src/shared/pam-util.h b/src/shared/pam-util.h index 96d522d8f9..ca3ed0c7c8 100644 --- a/src/shared/pam-util.h +++ b/src/shared/pam-util.h @@ -6,7 +6,7 @@ #if HAVE_PAM #include #include -#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ #include #include "dlfcn-util.h" @@ -14,10 +14,15 @@ extern DLSYM_PROTOTYPE(pam_acct_mgmt); extern DLSYM_PROTOTYPE(pam_close_session); extern DLSYM_PROTOTYPE(pam_end); +extern DLSYM_PROTOTYPE(pam_get_authtok_noverify); +extern DLSYM_PROTOTYPE(pam_get_authtok_verify); extern DLSYM_PROTOTYPE(pam_get_data); extern DLSYM_PROTOTYPE(pam_get_item); +extern DLSYM_PROTOTYPE(pam_get_user); +extern DLSYM_PROTOTYPE(pam_getenv); extern DLSYM_PROTOTYPE(pam_getenvlist); extern DLSYM_PROTOTYPE(pam_open_session); +extern DLSYM_PROTOTYPE(pam_prompt); extern DLSYM_PROTOTYPE(pam_putenv); extern DLSYM_PROTOTYPE(pam_set_data); extern DLSYM_PROTOTYPE(pam_set_item); @@ -27,6 +32,11 @@ extern DLSYM_PROTOTYPE(pam_strerror); extern DLSYM_PROTOTYPE(pam_syslog); extern DLSYM_PROTOTYPE(pam_vsyslog); +/* sym_pam_prompt() replacement for the pam_info() macro from , which expands to a direct + * pam_prompt() call. */ +#define sym_pam_info(pamh, fmt, ...) \ + sym_pam_prompt((pamh), PAM_TEXT_INFO, NULL, (fmt), ## __VA_ARGS__) + void pam_log_setup(void); int errno_to_pam_error(int error) _const_; @@ -90,6 +100,10 @@ int pam_get_data_many_internal(pam_handle_t *pamh, ...) _sentinel_; int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, const char *fmt, ...) _printf_(4,5); +/* Equivalent of pam_misc_setenv(pamh, name, value, 0), without the libpam_misc dep — builds "name=value" + * and hands it to sym_pam_putenv(), then erases the buffer before freeing in case it carried a secret. */ +int pam_putenv_assign(pam_handle_t *pamh, const char *name, const char *value); + #endif int dlopen_libpam(int log_level); diff --git a/src/socket-activate/meson.build b/src/socket-activate/meson.build index a4d18b58a8..628dbe79ff 100644 --- a/src/socket-activate/meson.build +++ b/src/socket-activate/meson.build @@ -5,6 +5,5 @@ executables += [ 'name' : 'systemd-socket-activate', 'public' : true, 'sources' : files('socket-activate.c'), - 'dependencies' : threads, }, ] diff --git a/src/socket-proxy/meson.build b/src/socket-proxy/meson.build index 52d63a8440..1106b445e9 100644 --- a/src/socket-proxy/meson.build +++ b/src/socket-proxy/meson.build @@ -5,6 +5,5 @@ executables += [ 'name' : 'systemd-socket-proxyd', 'public' : true, 'sources' : files('socket-proxyd.c'), - 'dependencies' : threads, }, ] diff --git a/src/systemctl/meson.build b/src/systemctl/meson.build index 2ce11c8f48..882704c9d7 100644 --- a/src/systemctl/meson.build +++ b/src/systemctl/meson.build @@ -58,7 +58,6 @@ executables += [ liblz4_cflags, libxz_cflags, libzstd_cflags, - threads, ], 'install_tag' : 'systemctl', }, diff --git a/src/sysupdate/meson.build b/src/sysupdate/meson.build index 0cfe22f528..da554ddcc3 100644 --- a/src/sysupdate/meson.build +++ b/src/sysupdate/meson.build @@ -30,7 +30,6 @@ executables += [ 'dependencies' : [ libfdisk_cflags, libopenssl_cflags, - threads, ], }, libexec_template + { @@ -38,7 +37,6 @@ executables += [ 'dbus' : true, 'conditions' : ['ENABLE_SYSUPDATED'], 'sources' : files('sysupdated.c'), - 'dependencies' : threads, }, executable_template + { 'name' : 'updatectl', diff --git a/src/test/meson.build b/src/test/meson.build index 4871c5517f..b581de293b 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -223,10 +223,8 @@ simple_tests += files( common_test_dependencies = [ libmount_cflags, - librt, libseccomp_cflags, libselinux_cflags, - threads, ] executables += [ @@ -303,14 +301,13 @@ executables += [ ], }, test_template + { - # only static linking apart from libdl, to make sure that the - # module is linked to all libraries that it uses. + # only static linking, to make sure that the module is linked + # to all libraries that it uses. 'sources' : files('test-dlopen.c'), 'link_with' : [ libc_wrapper_static, libbasic_static, ], - 'dependencies' : libdl, 'install' : false, 'type' : 'manual', }, @@ -359,10 +356,7 @@ executables += [ test_template + { 'sources' : files('test-libmount.c'), 'conditions' : ['HAVE_LIBMOUNT'], - 'dependencies' : [ - libmount_cflags, - threads, - ], + 'dependencies' : libmount_cflags, }, test_template + { 'sources' : files('test-loopback.c'), @@ -378,7 +372,6 @@ executables += [ }, test_template + { 'sources' : files('test-pressure.c'), - 'dependencies' : threads, }, test_template + { 'sources' : files('test-mount-util.c'), @@ -398,17 +391,13 @@ executables += [ test_template + { 'sources' : files('test-nss-hosts.c'), 'extract' : files('nss-test-util.c'), - 'dependencies' : [ - libdl, - libseccomp_cflags, - ], + 'dependencies' : libseccomp_cflags, 'conditions' : ['ENABLE_NSS'], 'timeout' : 120, }, test_template + { 'sources' : files('test-nss-users.c'), 'objects' : ['test-nss-hosts'], - 'dependencies' : libdl, 'conditions' : ['ENABLE_NSS'], }, test_template + { @@ -426,7 +415,6 @@ executables += [ }, test_template + { 'sources' : files('test-process-util.c'), - 'dependencies' : threads, }, test_template + { 'sources' : files('test-progress-bar.c'), @@ -441,7 +429,6 @@ executables += [ }, test_template + { 'sources' : files('test-qrcode-util.c'), - 'dependencies' : libdl, }, test_template + { 'sources' : files('test-random-util.c'), @@ -471,7 +458,6 @@ executables += [ }, test_template + { 'sources' : files('test-set-disable-mempool.c'), - 'dependencies' : threads, }, test_template + { 'sources' : files('test-sizeof.c'), @@ -554,7 +540,7 @@ executables += [ }, core_test_template + { 'sources' : files('test-bpf-token.c'), - 'dependencies' : common_test_dependencies + libbpf, + 'dependencies' : common_test_dependencies + libbpf_cflags, 'conditions' : ['BPF_FRAMEWORK'], 'type' : 'manual', }, @@ -603,7 +589,6 @@ executables += [ }, core_test_template + { 'sources' : files('test-loop-util.c'), - 'dependencies' : [threads], 'parallel' : false, }, core_test_template + { @@ -611,10 +596,7 @@ executables += [ }, core_test_template + { 'sources' : files('test-namespace.c'), - 'dependencies' : [ - threads, - libmount_cflags, - ], + 'dependencies' : libmount_cflags, }, core_test_template + { 'sources' : files('test-ns.c'), @@ -632,7 +614,6 @@ executables += [ }, core_test_template + { 'sources' : files('test-socket-bind.c'), - 'dependencies' : libdl, 'conditions' : ['BPF_FRAMEWORK'], }, core_test_template + { @@ -666,7 +647,6 @@ executables += [ libbasic_static, libsystemd, ], - 'dependencies' : threads, }, test_template + { 'sources' : files('../libudev/test-udev-device-thread.c'), @@ -675,7 +655,6 @@ executables += [ libbasic_static, libudev, ], - 'dependencies' : threads, }, test_template + { 'sources' : files('../libudev/test-libudev.c'), diff --git a/src/test/test-bpf-restrict-fsaccess.c b/src/test/test-bpf-restrict-fsaccess.c index e95e706c27..0d4e18671a 100644 --- a/src/test/test-bpf-restrict-fsaccess.c +++ b/src/test/test-bpf-restrict-fsaccess.c @@ -92,7 +92,7 @@ static int do_mprotect_exec(const char *path) { } #if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "restrict-fsaccess-skel.h" static struct restrict_fsaccess_bpf *restrict_fsaccess_bpf_free(struct restrict_fsaccess_bpf *obj) { diff --git a/src/test/test-bpf-token.c b/src/test/test-bpf-token.c index 7e83a048e5..f991f92601 100644 --- a/src/test/test-bpf-token.c +++ b/src/test/test-bpf-token.c @@ -1,26 +1,34 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include +#include "bpf-util.h" #include "fd-util.h" #include "main-func.h" -#include "tests.h" /* NOLINT(misc-include-cleaner): this is needed conditionally */ +#include "tests.h" static int run(int argc, char *argv[]) { -#if defined(LIBBPF_MAJOR_VERSION) && (LIBBPF_MAJOR_VERSION > 1 || (LIBBPF_MAJOR_VERSION == 1 && LIBBPF_MINOR_VERSION >= 5)) - _cleanup_close_ int bpffs_fd = open("/sys/fs/bpf", O_RDONLY); +#if HAVE_LIBBPF + int r; + + r = dlopen_bpf(LOG_ERR); + if (r < 0) + return r; + + _cleanup_close_ int bpffs_fd = open("/sys/fs/bpf", O_CLOEXEC|O_RDONLY); if (bpffs_fd < 0) return log_error_errno(errno, "Failed to open '/sys/fs/bpf': %m"); - _cleanup_close_ int token_fd = bpf_token_create(bpffs_fd, /* opts= */ NULL); + _cleanup_close_ int token_fd = sym_bpf_token_create(bpffs_fd, /* opts= */ NULL); + if (token_fd == -ENOSYS) + return log_tests_skipped("bpf_token_create() unavailable (libbpf too old or kernel lacks BPF_TOKEN_CREATE support)"); if (token_fd < 0) - return log_error_errno(errno, "Failed to create bpf token: %m"); + return log_error_errno(token_fd, "Failed to create bpf token: %m"); log_info("Successfully created token fd."); return 0; #else - return log_tests_skipped("libbpf is older than v1.5"); + return log_tests_skipped("BPF framework support is disabled"); #endif } diff --git a/src/test/test-color-util.c b/src/test/test-color-util.c index 3d00d8719d..a1369f4ef5 100644 --- a/src/test/test-color-util.c +++ b/src/test/test-color-util.c @@ -6,58 +6,126 @@ TEST(hsv_to_rgb) { uint8_t r, g, b; + /* Black at any hue. */ hsv_to_rgb(0, 0, 0, &r, &g, &b); - assert(r == 0 && g == 0 && b == 0); + ASSERT_EQ(r, 0); + ASSERT_EQ(g, 0); + ASSERT_EQ(b, 0); hsv_to_rgb(60, 0, 0, &r, &g, &b); - assert(r == 0 && g == 0 && b == 0); + ASSERT_EQ(r, 0); + ASSERT_EQ(g, 0); + ASSERT_EQ(b, 0); + /* White: s=0 must ignore hue. */ hsv_to_rgb(0, 0, 100, &r, &g, &b); - assert(r == 255 && g == 255 && b == 255); + ASSERT_EQ(r, 255); + ASSERT_EQ(g, 255); + ASSERT_EQ(b, 255); - hsv_to_rgb(0, 100, 100, &r, &g, &b); - assert(r == 255 && g == 0 && b == 0); + hsv_to_rgb(180, 0, 100, &r, &g, &b); + ASSERT_EQ(r, 255); + ASSERT_EQ(g, 255); + ASSERT_EQ(b, 255); - hsv_to_rgb(120, 100, 100, &r, &g, &b); - assert(r == 0 && g == 255 && b == 0); + /* Pure primary and secondary colors — one per sector boundary. */ + hsv_to_rgb(0, 100, 100, &r, &g, &b); /* red */ + ASSERT_EQ(r, 255); ASSERT_EQ(g, 0); ASSERT_EQ(b, 0); + hsv_to_rgb(60, 100, 100, &r, &g, &b); /* yellow */ + ASSERT_EQ(r, 255); ASSERT_EQ(g, 255); ASSERT_EQ(b, 0); + hsv_to_rgb(120, 100, 100, &r, &g, &b); /* green */ + ASSERT_EQ(r, 0); ASSERT_EQ(g, 255); ASSERT_EQ(b, 0); + hsv_to_rgb(180, 100, 100, &r, &g, &b); /* cyan */ + ASSERT_EQ(r, 0); ASSERT_EQ(g, 255); ASSERT_EQ(b, 255); + hsv_to_rgb(240, 100, 100, &r, &g, &b); /* blue */ + ASSERT_EQ(r, 0); ASSERT_EQ(g, 0); ASSERT_EQ(b, 255); + hsv_to_rgb(300, 100, 100, &r, &g, &b); /* magenta */ + ASSERT_EQ(r, 255); ASSERT_EQ(g, 0); ASSERT_EQ(b, 255); - hsv_to_rgb(240, 100, 100, &r, &g, &b); - assert(r == 0 && g == 0 && b == 255); + /* Sector midpoints. Catches inverted ramp direction (k & 1 ? 1-f : f) in any single + * sector — a regression would shift exactly one channel by ±half-intensity. */ + hsv_to_rgb(30, 100, 100, &r, &g, &b); /* orange — sector 0 */ + ASSERT_EQ(r, 255); ASSERT_EQ(g, 127); ASSERT_EQ(b, 0); + hsv_to_rgb(90, 100, 100, &r, &g, &b); /* chartreuse — sector 1 */ + ASSERT_EQ(r, 127); ASSERT_EQ(g, 255); ASSERT_EQ(b, 0); + hsv_to_rgb(150, 100, 100, &r, &g, &b); /* spring green — sector 2 */ + ASSERT_EQ(r, 0); ASSERT_EQ(g, 255); ASSERT_EQ(b, 127); + hsv_to_rgb(210, 100, 100, &r, &g, &b); /* azure — sector 3 */ + ASSERT_EQ(r, 0); ASSERT_EQ(g, 127); ASSERT_EQ(b, 255); + hsv_to_rgb(270, 100, 100, &r, &g, &b); /* violet — sector 4 */ + ASSERT_EQ(r, 127); ASSERT_EQ(g, 0); ASSERT_EQ(b, 255); + hsv_to_rgb(330, 100, 100, &r, &g, &b); /* rose — sector 5 */ + ASSERT_EQ(r, 255); ASSERT_EQ(g, 0); ASSERT_EQ(b, 127); + /* Just below 360 — ensures (int) seg stays in sector 5 and doesn't wrap to 6. */ + hsv_to_rgb(359.5, 100, 100, &r, &g, &b); + ASSERT_EQ(r, 255); ASSERT_EQ(g, 0); ASSERT_EQ(b, 2); + + /* Exactly 360 — cyclic boundary, equivalent to 0 (red). Callers like color_for_pcr() in + * pcrlock.c can reach this via floating-point arithmetic (e.g. 360.0/23*23 == 360.0). */ + hsv_to_rgb(360, 100, 100, &r, &g, &b); + ASSERT_EQ(r, 255); ASSERT_EQ(g, 0); ASSERT_EQ(b, 0); + + /* Non-trivial s/v: regression check for the multiply-and-cast path. */ hsv_to_rgb(311, 52, 62, &r, &g, &b); - assert(r == 158 && g == 75 && b == 143); + ASSERT_EQ(r, 158); ASSERT_EQ(g, 75); ASSERT_EQ(b, 143); } TEST(rgb_to_hsv) { double h, s, v; + + /* Grayscale: delta == 0, h is NaN, s == 0. */ rgb_to_hsv(0, 0, 0, &h, &s, &v); - assert(s <= 0); - assert(v <= 0); + ASSERT_TRUE(s <= 0); + ASSERT_TRUE(v <= 0); rgb_to_hsv(1, 1, 1, &h, &s, &v); - assert(s <= 0); - assert(v >= 100); + ASSERT_TRUE(s <= 0); + ASSERT_TRUE(v >= 100); - rgb_to_hsv(1, 0, 0, &h, &s, &v); - assert(h >= 359 || h <= 1); - assert(s >= 100); - assert(v >= 100); + rgb_to_hsv(0.5, 0.5, 0.5, &h, &s, &v); + ASSERT_TRUE(s <= 0); + ASSERT_TRUE(v >= 49 && v <= 51); - rgb_to_hsv(0, 1, 0, &h, &s, &v); - assert(h >= 119 && h <= 121); - assert(s >= 100); - assert(v >= 100); + /* Pure primary colors. */ + rgb_to_hsv(1, 0, 0, &h, &s, &v); /* red */ + ASSERT_TRUE(h >= 0 && h <= 1); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); - rgb_to_hsv(0, 0, 1, &h, &s, &v); - assert(h >= 239 && h <= 241); - assert(s >= 100); - assert(v >= 100); + rgb_to_hsv(0, 1, 0, &h, &s, &v); /* green */ + ASSERT_TRUE(h >= 119 && h <= 121); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); + rgb_to_hsv(0, 0, 1, &h, &s, &v); /* blue */ + ASSERT_TRUE(h >= 239 && h <= 241); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); + + /* Pure secondary colors — each exercises a different "max" branch. Magenta exercises + * the negative-hue wrap from the r-max branch (raw value is -60). */ + rgb_to_hsv(1, 1, 0, &h, &s, &v); /* yellow — r-max branch, positive */ + ASSERT_TRUE(h >= 59 && h <= 61); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); + + rgb_to_hsv(0, 1, 1, &h, &s, &v); /* cyan — g-max branch */ + ASSERT_TRUE(h >= 179 && h <= 181); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); + + rgb_to_hsv(1, 0, 1, &h, &s, &v); /* magenta — r-max branch, wrapped */ + ASSERT_TRUE(h >= 299 && h <= 301); + ASSERT_TRUE(s >= 100); + ASSERT_TRUE(v >= 100); + + /* Mixed values. */ rgb_to_hsv(0.5, 0.6, 0.7, &h, &s, &v); - assert(h >= 209 && h <= 211); - assert(s >= 28 && s <= 31); - assert(v >= 69 && v <= 71); + ASSERT_TRUE(h >= 209 && h <= 211); + ASSERT_TRUE(s >= 28 && s <= 31); + ASSERT_TRUE(v >= 69 && v <= 71); } DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 7421a77024..de1d767139 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -3,7 +3,7 @@ #include "acl-util.h" #include "apparmor-util.h" #include "blkid-util.h" -#include "bpf-dlopen.h" +#include "bpf-util.h" #include "compress.h" #include "crypto-util.h" #include "cryptsetup-util.h" @@ -18,6 +18,7 @@ #include "libcrypt-util.h" #include "libfido2-util.h" #include "libmount-util.h" +#include "locale-util.h" #include "main-func.h" #include "microhttpd-util.h" #include "module-util.h" @@ -65,6 +66,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID); ASSERT_DLOPEN(dlopen_libcrypt, HAVE_LIBCRYPT); ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2); + ASSERT_OK(dlopen_libintl(LOG_DEBUG)); /* Required to be available at build time. */ ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD); ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT); ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM); diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 0c2cc500b1..bc74856fde 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -2,7 +2,6 @@ #include #include -#include #include #include "capability-util.h" @@ -660,7 +659,7 @@ TEST(safe_atod) { ASSERT_ERROR(safe_atod("junk", &d), EINVAL); ASSERT_OK_ZERO(safe_atod("0.2244", &d)); - assert_se(fabs(d - 0.2244) < 0.000001); + assert_se(ABS(d - 0.2244) < 0.000001); ASSERT_ERROR(safe_atod("0,5", &d), EINVAL); ASSERT_ERROR(safe_atod("", &d), EINVAL); @@ -672,7 +671,7 @@ TEST(safe_atod) { return (void) log_tests_skipped_errno(errno, "locale de_DE.utf8 not found"); ASSERT_OK_ZERO(safe_atod("0.2244", &d)); - assert_se(fabs(d - 0.2244) < 0.000001); + assert_se(ABS(d - 0.2244) < 0.000001); ASSERT_ERROR(safe_atod("0,5", &d), EINVAL); ASSERT_ERROR(safe_atod("", &d), EINVAL); diff --git a/src/test/test-random-util.c b/src/test/test-random-util.c index e5972718b4..d5043779b7 100644 --- a/src/test/test-random-util.c +++ b/src/test/test-random-util.c @@ -65,7 +65,7 @@ static void test_random_u64_range_one(unsigned mod) { i, count[i], dev, (int) (count[i] / scale), "x"); - assert_se(fabs(dev) < 6); /* 6 sigma is excessive, but this check should be enough to + assert_se(ABS(dev) < 6); /* 6 sigma is excessive, but this check should be enough to * identify catastrophic failure while minimizing false * positives. */ } diff --git a/src/timesync/meson.build b/src/timesync/meson.build index b307245772..c42fcd3e70 100644 --- a/src/timesync/meson.build +++ b/src/timesync/meson.build @@ -35,10 +35,7 @@ executables += [ 'sources' : timesyncd_sources, 'extract' : timesyncd_extract_sources, 'link_with' : timesyncd_link_with, - 'dependencies' : [ - libm, - threads, - ], + 'dependencies' : libm, }, libexec_template + { 'name' : 'systemd-time-wait-sync', diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index e4f471e2aa..b0f22516df 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -244,7 +244,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) { /* For small deltas, tell the kernel to gradually adjust the system clock to the NTP time, larger * deltas are just directly set. */ - if (fabs(offset) < NTP_MAX_ADJUST) { + if (ABS(offset) < NTP_MAX_ADJUST) { tmx = (struct timex) { .modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR, .status = STA_PLL, @@ -346,7 +346,7 @@ static bool manager_sample_spike_detection(Manager *m, double offset, double del return false; /* always accept offset if we are farther off than the round-trip delay */ - if (fabs(offset) > delay) + if (ABS(offset) > delay) return false; /* we need a few samples before looking at them */ @@ -354,11 +354,11 @@ static bool manager_sample_spike_detection(Manager *m, double offset, double del return false; /* do not accept anything worse than the maximum possible error of the best sample */ - if (fabs(offset) > m->samples[idx_min].delay) + if (ABS(offset) > m->samples[idx_min].delay) return true; /* compare the difference between the current offset to the previous offset and jitter */ - return fabs(offset - m->samples[idx_cur].offset) > 3 * jitter; + return ABS(offset - m->samples[idx_cur].offset) > 3 * jitter; } static void manager_adjust_poll(Manager *m, double offset, bool spike) { @@ -371,20 +371,20 @@ static void manager_adjust_poll(Manager *m, double offset, bool spike) { } /* set to minimal poll interval */ - if (!spike && fabs(offset) > NTP_ACCURACY_SEC) { + if (!spike && ABS(offset) > NTP_ACCURACY_SEC) { m->poll_interval_usec = m->poll_interval_min_usec; return; } /* increase polling interval */ - if (fabs(offset) < NTP_ACCURACY_SEC * 0.25) { + if (ABS(offset) < NTP_ACCURACY_SEC * 0.25) { if (m->poll_interval_usec < m->poll_interval_max_usec) m->poll_interval_usec *= 2; return; } /* decrease polling interval */ - if (spike || fabs(offset) > NTP_ACCURACY_SEC * 0.75) { + if (spike || ABS(offset) > NTP_ACCURACY_SEC * 0.75) { if (m->poll_interval_usec > m->poll_interval_min_usec) m->poll_interval_usec /= 2; return; diff --git a/src/udev/meson.build b/src/udev/meson.build index 700a8cc8d5..7e2435d0fa 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -122,7 +122,6 @@ udev_dependencies = [ libblkid_cflags, libkmod_cflags, libmount_cflags, - threads, ] udev_plugin_template = executable_template + { @@ -138,7 +137,6 @@ udev_common_template = { 'dependencies' : [ libacl_cflags, libblkid_cflags, - threads, ], } udev_test_template = test_template + udev_common_template diff --git a/src/userdb/meson.build b/src/userdb/meson.build index a933a4907b..c25c40bc0a 100644 --- a/src/userdb/meson.build +++ b/src/userdb/meson.build @@ -5,7 +5,6 @@ executables += [ 'name' : 'systemd-userwork', 'conditions' : ['ENABLE_USERDB'], 'sources' : files('userwork.c'), - 'dependencies' : threads, }, libexec_template + { 'name' : 'systemd-userdbd', @@ -14,13 +13,11 @@ executables += [ 'userdbd-manager.c', 'userdbd.c', ), - 'dependencies' : threads, }, executable_template + { 'name' : 'userdbctl', 'conditions' : ['ENABLE_USERDB'], 'sources' : files('userdbctl.c'), - 'dependencies' : threads, }, ]