Various dlopen/linking cleanups from #42100 (#42166)

- **bpf-util: rename from bpf-dlopen, unify version-specific symbol
handling**
- **cryptsetup: dlopen libcryptsetup in tokens**
- **tree-wide: dlopen libpam in pam plugins**
- **test-bus-marshal: dlopen() glib and libdbus instead of linking
directly**
- **lock-util: Simplify timeout for lock_generic_with_timeout()**
- **color-util: simplify hsv_to_rgb, fix rgb_to_hsv negative-hue wrap**
- **tree-wide: Use our own macros instead of fabs()/fmax()/fmin()**
- **locale-util: dlopen() libintl instead of linking against it**
- **home: Use log2u64() over log2()**
- **meson: drop libdl, threads, and librt dependencies**
- **libc: Use dlsym() from a constructor instead of weak symbols**
- **libc: Make sure C23 versions of strtol(), sscanf() are not used**
This commit is contained in:
Daan De Meyer
2026-05-19 08:54:27 +02:00
committed by GitHub
78 changed files with 802 additions and 719 deletions
+20 -61
View File
@@ -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 <libintl.h>''',
args : '-D_GNU_SOURCE')
libintl = []
else
libintl = cc.find_library('intl')
if not cc.has_function('dgettext',
prefix : '''#include <libintl.h>''',
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,
@@ -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
@@ -9,6 +9,7 @@ Packages=
btrfs-progs
coreutils
kmod
libcryptsetup12
policycoreutils
tpm2.0-tools
+31
View File
@@ -7,7 +7,12 @@
#include <sys/stat.h>
#include <unistd.h>
#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;
+12 -1
View File
@@ -1,9 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <libintl.h> /* IWYU pragma: export */
#include <locale.h> /* 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);
+1 -26
View File
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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;
-3
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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',
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
-3
View File
@@ -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)
-1
View File
@@ -30,7 +30,6 @@ common_dependencies = [
liblz4_cflags,
libxz_cflags,
libzstd_cflags,
threads,
]
executables += [
-1
View File
@@ -12,7 +12,6 @@ executables += [
'dependencies' : [
libmount_cflags,
libopenssl_cflags,
threads,
],
},
]
-1
View File
@@ -22,7 +22,6 @@ executables += [
'sources' : systemd_cryptenroll_sources,
'dependencies' : [
libcryptsetup_cflags,
libdl,
libfido2_cflags,
libopenssl_cflags,
libp11kit_cflags,
@@ -2,6 +2,7 @@
#include <libcryptsetup.h>
#include <string.h>
#include <syslog.h>
#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.");
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <libcryptsetup.h>
#include <syslog.h>
#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.");
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <libcryptsetup.h>
#include <syslog.h>
#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");
@@ -2,22 +2,21 @@
#pragma once
#include <libcryptsetup.h>
#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; \
})
+4 -4
View File
@@ -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,
],
},
+8 -6
View File
@@ -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) || \
+4 -4
View File
@@ -3,7 +3,6 @@
#include <grp.h>
#include <linux/fscrypt.h>
#include <linux/magic.h>
#include <math.h>
#include <pwd.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
@@ -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);
+1 -14
View File
@@ -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',
},
]
+48 -37
View File
@@ -1,8 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <libintl.h>
#include <security/pam_misc.h>
#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@");
-1
View File
@@ -17,7 +17,6 @@ executables += [
'import-common.c',
'qcow2-util.c',
),
'dependencies' : threads,
},
libexec_template + {
'name' : 'systemd-pull',
+18
View File
@@ -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 <features.h>
#undef __GLIBC_USE_C2X_STRTOL
#define __GLIBC_USE_C2X_STRTOL 0
#undef __GLIBC_USE_C23_STRTOL
#define __GLIBC_USE_C23_STRTOL 0
#include_next <stdio.h> /* IWYU pragma: export */
+17
View File
@@ -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 <features.h>
#undef __GLIBC_USE_C2X_STRTOL
#define __GLIBC_USE_C2X_STRTOL 0
#undef __GLIBC_USE_C23_STRTOL
#define __GLIBC_USE_C23_STRTOL 0
#include_next <stdlib.h> /* IWYU pragma: export */
-1
View File
@@ -25,7 +25,6 @@ common_deps = [
liblz4_cflags,
libxz_cflags,
libzstd_cflags,
threads,
]
executables += [
-5
View File
@@ -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 + {
+46 -18
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dlfcn.h>
#include <errno.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -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; \
}
+7 -22
View File
@@ -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,
},
]
+46 -20
View File
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <math.h>
/* 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);
+10 -10
View File
@@ -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));
-1
View File
@@ -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}
-1
View File
@@ -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
-5
View File
@@ -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'),
+51 -49
View File
@@ -3,7 +3,6 @@
#include <endian.h>
#include <fcntl.h>
#include <pwd.h>
#include <security/pam_misc.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
@@ -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;
+2 -2
View File
@@ -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@");
-2
View File
@@ -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,
},
]
-4
View File
@@ -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'),
+1 -1
View File
@@ -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"
-2
View File
@@ -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'],
},
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
-2
View File
@@ -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,
},
]
-1
View File
@@ -12,7 +12,6 @@ executables += [
liblz4_cflags,
libxz_cflags,
libzstd_cflags,
threads,
],
},
]
-2
View File
@@ -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,
],
},
]
-1
View File
@@ -72,7 +72,6 @@ resolve_common_template = {
libidn2_cflags,
libopenssl_cflags,
libm,
threads,
],
}
-49
View File
@@ -1,49 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <bpf/libbpf.h>
/* 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 */);
}
-221
View File
@@ -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
+1 -1
View File
@@ -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"
+178
View File
@@ -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
@@ -8,10 +8,27 @@
#include <bpf/bpf.h> /* IWYU pragma: export */
#include <bpf/libbpf.h> /* 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. */
+25 -19
View File
@@ -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);
+2
View File
@@ -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),
+1
View File
@@ -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);
+2 -5
View File
@@ -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,
+23
View File
@@ -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),
+15 -1
View File
@@ -6,7 +6,7 @@
#if HAVE_PAM
#include <security/pam_appl.h>
#include <security/pam_ext.h>
#include <security/pam_modules.h> /* IWYU pragma: export */
#include <security/pam_modules.h> /* IWYU pragma: export */
#include <syslog.h>
#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 <security/pam_ext.h>, 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);
-1
View File
@@ -5,6 +5,5 @@ executables += [
'name' : 'systemd-socket-activate',
'public' : true,
'sources' : files('socket-activate.c'),
'dependencies' : threads,
},
]
-1
View File
@@ -5,6 +5,5 @@ executables += [
'name' : 'systemd-socket-proxyd',
'public' : true,
'sources' : files('socket-proxyd.c'),
'dependencies' : threads,
},
]
-1
View File
@@ -58,7 +58,6 @@ executables += [
liblz4_cflags,
libxz_cflags,
libzstd_cflags,
threads,
],
'install_tag' : 'systemctl',
},
-2
View File
@@ -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',
+6 -27
View File
@@ -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'),
+1 -1
View File
@@ -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) {
+15 -7
View File
@@ -1,26 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <bpf/bpf.h>
#include <fcntl.h>
#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
}
+97 -29
View File
@@ -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);
+3 -1
View File
@@ -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);
+2 -3
View File
@@ -2,7 +2,6 @@
#include <linux/netfilter/nf_tables.h>
#include <locale.h>
#include <math.h>
#include <sys/socket.h>
#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);
+1 -1
View File
@@ -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. */
}
+1 -4
View File
@@ -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',
+7 -7
View File
@@ -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;
-2
View File
@@ -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
-3
View File
@@ -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,
},
]