From cb7e3126b95e9be3bd722f38502d138c4d4d3eeb Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sun, 5 May 2024 16:45:21 +0100 Subject: [PATCH 1/3] docs: add specification for ELF dlopen metadata Tool to parse it and to use it for Debian packaging available at https://github.com/systemd/package-notes Add 3 levels of priority like Debian does, but using terminology from RPM as it seems more apt. We will very likely never use 'required', as we use this functionality for optional features, but it is worth having it in the spec nonetheless as we want it to be generalized. --- docs/ELF_DLOPEN_METADATA.md | 89 +++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/ELF_DLOPEN_METADATA.md diff --git a/docs/ELF_DLOPEN_METADATA.md b/docs/ELF_DLOPEN_METADATA.md new file mode 100644 index 0000000000..5c3bf1eae2 --- /dev/null +++ b/docs/ELF_DLOPEN_METADATA.md @@ -0,0 +1,89 @@ +--- +title: Dlopen Metadata for ELF Files +category: Interfaces +layout: default +SPDX-License-Identifier: LGPL-2.1-or-later +--- + +# `dlopen()` Metadata for ELF Files + +*Intended audience: hackers working on packaging ELF files that use dlopen to load libraries.* + +## Motivation + +Using `dlopen()` to load optional dependencies brings several advantages: programs can gracefully downgrade +a feature when a library is not available, and the shared library is only loaded into the process (and its +ELF constructors are run) only when the requested feature is actually used. But it also has some drawbacks, +and the main one is that it is harder to track a program's dependencies, since unlike build-time dynamic +linking there will not be a mention in the ELF metadata. This specification aims to solve this problem by +providing a standardized specification for a custom ELF note that can be used to list `dlopen()` +dependencies. + +## Implementation + +This document will attempt to define a common metadata format specification, so that multiple implementers +might use it when coding upstream software, and packagers might use it when building packages and setting +dependencies. + +The metadata will be embedded in a series of new, 4-byte-aligned, allocated, 0-padded, read-only ELF header +sections, in a JSON array containing name-value objects, either one ELF note per dependency or as a single +note listing multiple dependencies in the top-level array. Implementers working on parsing ELF files should +not assume a specific list of names, but parse anything that is included in the section, and should look for +the note using the `note type`. Implementers working on build tools should strive to use the same names, for +consistency. The most common will be listed here. + +* Section header + +``` +SECTION: `.note.dlopen` +note type: `0x407c0c0a` +Owner: `FDO` (FreeDesktop.org) +Value: an array of JSON objects encoded as a zero-terminated UTF-8 string +``` + +* JSON payload + +```json +[ + { + "soname": ["libfoo.so.1"], + "feature": "foo", + "description": "Enables the foo feature", + "priority": "recommended" + } +] +``` + +The format is a single JSON array containing objects, encoded as a zero-terminated `UTF-8` string. Each key +in each object shall be unique as per recommendations of [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259#section-4). +Strings shall not contain any control characters or use `\uXXX` escaping. + +Reference implementations of [packaging tools for `.deb` and `.rpm`](https://github.com/systemd/package-notes) +are available, and provide macros/helpers to parse the note when building packages and adding dependencies. + +## Well-known keys + +The metadata format is intentionally extensible, so that upstreams and later revisions of this spec can add +their own information. The 'soname' array is required, with at least one element, everything else is +optional. If alternative soname versions for the same library are supported at the same time, an array can +be used, listing the most preferred first, and parsers are expected to select only the first one that is +available on the system, as it is a mechanism to specify alternatives. If the `priority` field is used, it +must follow the specification and use one of the values specified in the table. If it is not specified, a +parser should assume 'recommended' if a priority is needed. If the `feature` field is used, it will identify +an individual feature, and multiple entries using the same `feature` denote functionality that requires all +of the libraries they specify in order to be enabled. + +| Key name | Key type | Mandatory | Key description | Example value | +|-------------|----------------------------|-----------|--------------------------------------------------------------------------|----------------------------------| +| soname | array of strings | yes | The library names loaded by `dlopen()` | [ "libfoo.so.1", "libfoo.so.0" ] | +| feature | string | no | A keyword identifying the feature that the library contributes to enable | "foo" | +| description | string | no | A human-readable text string describing the feature | "Enables the foo feature" | +| priority | string | no | The priority of the feature, one of: required, recommended, suggested | "recommended" | + +### Priority definition + +| Priority | Semantics | +|-------------|--------------------------------------------------------------------------------------------------------------------------------------| +| required | Core functionality needs the dependency, the binary will not work if it cannot be found | +| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided | +| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations | From 2f6bd11c1a0147f6bd24bce3ed00c3d91c0884e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Apr 2024 17:45:17 +0200 Subject: [PATCH 2/3] dlfcn: add macro for exporting dlopen() module names in ELF sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows code to declare "weak" dlopen() style deps via an ELF section following the just added specification. The idea is that any user of dlopen() will place ELF_NOTE_DLOPEN(…) somewhere close which will synthesize the note. Tools such as rpm/dpkg package builders as well as initrd generators (such as dracut) can then automatically pick up these weak deps of suggested dependencies for their purposes. Co-authored-by: Luca Boccassi --- src/basic/dlfcn-util.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/basic/dlfcn-util.h b/src/basic/dlfcn-util.h index 050f1e2da7..b395d4ca04 100644 --- a/src/basic/dlfcn-util.h +++ b/src/basic/dlfcn-util.h @@ -39,3 +39,44 @@ int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_l /* libbpf is a bit confused about type-safety and API compatibility. Provide a macro that can tape over that mess. Sad. */ #define DLSYM_ARG_FORCE(arg) \ &sym_##arg, STRINGIFY(arg) + +#define ELF_NOTE_DLOPEN_VENDOR "FDO" +#define ELF_NOTE_DLOPEN_TYPE UINT32_C(0x407c0c0a) +#define ELF_NOTE_DLOPEN_PRIORITY_REQUIRED "required" +#define ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended" +#define ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED "suggested" + +/* Add an ".note.dlopen" ELF note to our binary that declares our weak dlopen() dependency. This + * information can be read from an ELF file via "readelf -p .note.dlopen" or an equivalent command. */ +#define _ELF_NOTE_DLOPEN(json, variable_name) \ + __attribute__((used, section(".note.dlopen"))) _Alignas(sizeof(uint32_t)) static const struct { \ + struct { \ + uint32_t n_namesz, n_descsz, n_type; \ + } nhdr; \ + char name[sizeof(ELF_NOTE_DLOPEN_VENDOR)]; \ + _Alignas(sizeof(uint32_t)) char dlopen_json[sizeof(json)]; \ + } variable_name = { \ + .nhdr = { \ + .n_namesz = sizeof(ELF_NOTE_DLOPEN_VENDOR), \ + .n_descsz = sizeof(json), \ + .n_type = ELF_NOTE_DLOPEN_TYPE, \ + }, \ + .name = ELF_NOTE_DLOPEN_VENDOR, \ + .dlopen_json = json, \ + } + +#define _SONAME_ARRAY1(a) "[\""a"\"]" +#define _SONAME_ARRAY2(a, b) "[\""a"\",\""b"\"]" +#define _SONAME_ARRAY3(a, b, c) "[\""a"\",\""b"\",\""c"\"]" +#define _SONAME_ARRAY4(a, b, c, d) "[\""a"\",\""b"\",\""c"\"",\""d"\"]" +#define _SONAME_ARRAY5(a, b, c, d, e) "[\""a"\",\""b"\",\""c"\"",\""d"\",\""e"\"]" +#define _SONAME_ARRAY_GET(_1,_2,_3,_4,_5,NAME,...) NAME +#define _SONAME_ARRAY(...) _SONAME_ARRAY_GET(__VA_ARGS__, _SONAME_ARRAY5, _SONAME_ARRAY4, _SONAME_ARRAY3, _SONAME_ARRAY2, _SONAME_ARRAY1)(__VA_ARGS__) + +/* The 'priority' must be one of 'required', 'recommended' or 'suggested' as per specification, use the + * macro defined above to specify it. + * Multiple sonames can be passed and they will be automatically contructed into a json array (but note that + * due to preprocessor language limitations if more than the limit defined above is used, a new + * _SONAME_ARRAY will need to be added). */ +#define ELF_NOTE_DLOPEN(feature, description, priority, ...) \ + _ELF_NOTE_DLOPEN("[{\"feature\":\"" feature "\",\"description\":\"" description "\",\"priority\":\"" priority "\",\"soname\":" _SONAME_ARRAY(__VA_ARGS__) "}]", UNIQ_T(s, UNIQ)) From cd7c2077954d86d23eafdedf3e258b365622779d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Apr 2024 17:50:41 +0200 Subject: [PATCH 3/3] tree-wide: add dlopen ELF notes to all dlopen() deps of ours Use 'recommended' priority for the default compression library, to indicate that it should be prioritized over the other ones, as it will be used to compress journals/core files. Also use 'recommended' for kmod, as systems will likely fail to boot if it's missing from the initrd. Use 'suggested' for everything else. There is one dlopen'ed TPM library that has the name generated at runtime (depending on the driver), so that cannot be added, as it needs to be known at build time. Also when we support multiple ABI versions list them all, as for the same reason we cannot know which one will be used at build time. $ dlopen-notes.py build/libsystemd.so.0.39.0 build/src/shared/libsystemd-shared-256.so libarchive.so.13 suggested libbpf.so.0 suggested libbpf.so.1 suggested libcryptsetup.so.12 suggested libdw.so.1 suggested libelf.so.1 suggested libfido2.so.1 suggested libgcrypt.so.20 suggested libidn2.so.0 suggested libip4tc.so.2 suggested libkmod.so.2 recommended liblz4.so.1 suggested liblzma.so.5 suggested libp11-kit.so.0 suggested libpcre2-8.so.0 suggested libpwquality.so.1 suggested libqrencode.so.3 suggested libqrencode.so.4 suggested libtss2-esys.so.0 suggested libtss2-mu.so.0 suggested libtss2-rc.so.0 suggested libzstd.so.1 recommended Co-authored-by: Luca Boccassi --- meson.build | 9 +++++++++ src/basic/compress.c | 15 +++++++++++++++ src/basic/gcrypt-util.c | 5 +++++ src/locale/xkbcommon-util.c | 4 ++++ src/shared/bpf-dlopen.c | 5 +++++ src/shared/cryptsetup-util.c | 5 +++++ src/shared/elf-util.c | 10 ++++++++++ src/shared/firewall-util-iptables.c | 5 +++++ src/shared/idn-util.c | 10 ++++++++++ src/shared/libarchive-util.c | 5 +++++ src/shared/libfido2-util.c | 5 +++++ src/shared/module-util.c | 5 +++++ src/shared/password-quality-util-passwdqc.c | 5 +++++ src/shared/password-quality-util-pwquality.c | 5 +++++ src/shared/pcre2-util.c | 5 +++++ src/shared/pkcs11-util.c | 5 +++++ src/shared/qrcode-util.c | 5 +++++ src/shared/tpm2-util.c | 15 +++++++++++++++ 18 files changed, 123 insertions(+) diff --git a/meson.build b/meson.build index 63c358194d..6ea9fce85a 100644 --- a/meson.build +++ b/meson.build @@ -1418,6 +1418,15 @@ elif compression == 'lz4' and not liblz4.found() elif compression == 'xz' and not libxz.found() error('default-compression=xz requires xz') endif +# In the dlopen ELF note we save the default compression library with a +# higher priority, so that packages can give it priority over the +# secondary libraries. +conf.set_quoted('COMPRESSION_PRIORITY_ZSTD', + compression == 'zstd' ? 'recommended' : 'suggested') +conf.set_quoted('COMPRESSION_PRIORITY_LZ4', + compression == 'lz4' ? 'recommended' : 'suggested') +conf.set_quoted('COMPRESSION_PRIORITY_XZ', + compression == 'xz' ? 'recommended' : 'suggested') conf.set('DEFAULT_COMPRESSION', 'COMPRESSION_@0@'.format(compression.to_upper())) libarchive = dependency('libarchive', diff --git a/src/basic/compress.c b/src/basic/compress.c index 5a4293fa81..33b27d3b99 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -129,6 +129,11 @@ bool compression_supported(Compression c) { #if HAVE_XZ int dlopen_lzma(void) { + ELF_NOTE_DLOPEN("lzma", + "Support lzma compression in journal and coredump files", + COMPRESSION_PRIORITY_XZ, + "liblzma.so.5"); + return dlopen_many_sym_or_warn( &lzma_dl, "liblzma.so.5", LOG_DEBUG, @@ -186,6 +191,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, #if HAVE_LZ4 int dlopen_lz4(void) { + ELF_NOTE_DLOPEN("lz4", + "Support lz4 compression in journal and coredump files", + COMPRESSION_PRIORITY_LZ4, + "liblz4.so.1"); + return dlopen_many_sym_or_warn( &lz4_dl, "liblz4.so.1", LOG_DEBUG, @@ -242,6 +252,11 @@ int compress_blob_lz4(const void *src, uint64_t src_size, #if HAVE_ZSTD int dlopen_zstd(void) { + ELF_NOTE_DLOPEN("zstd", + "Support zstd compression in journal and coredump files", + COMPRESSION_PRIORITY_ZSTD, + "libzstd.so.1"); + return dlopen_many_sym_or_warn( &zstd_dl, "libzstd.so.1", LOG_DEBUG, diff --git a/src/basic/gcrypt-util.c b/src/basic/gcrypt-util.c index 081866537c..4d68d2c22b 100644 --- a/src/basic/gcrypt-util.c +++ b/src/basic/gcrypt-util.c @@ -41,6 +41,11 @@ DLSYM_FUNCTION(gcry_randomize); DLSYM_FUNCTION(gcry_strerror); static int dlopen_gcrypt(void) { + ELF_NOTE_DLOPEN("gcrypt", + "Support for journald forward-sealing", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libgcrypt.so.20"); + return dlopen_many_sym_or_warn( &gcrypt_dl, "libgcrypt.so.20", LOG_DEBUG, diff --git a/src/locale/xkbcommon-util.c b/src/locale/xkbcommon-util.c index 468452f8af..d4e24cd0dd 100644 --- a/src/locale/xkbcommon-util.c +++ b/src/locale/xkbcommon-util.c @@ -16,6 +16,10 @@ DLSYM_FUNCTION(xkb_keymap_new_from_names); DLSYM_FUNCTION(xkb_keymap_unref); static int dlopen_xkbcommon(void) { + ELF_NOTE_DLOPEN("xkbcommon", + "Support for keyboard locale descriptions", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, "libxkbcommon.so.0"); + return dlopen_many_sym_or_warn( &xkbcommon_dl, "libxkbcommon.so.0", LOG_DEBUG, DLSYM_ARG(xkb_context_new), diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c index de3e40516e..d4ae24053e 100644 --- a/src/shared/bpf-dlopen.c +++ b/src/shared/bpf-dlopen.c @@ -76,6 +76,11 @@ int dlopen_bpf(void) { void *dl; int r; + ELF_NOTE_DLOPEN("bpf", + "Support firewalling and sandboxing with BPF", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libbpf.so.1", "libbpf.so.0"); + DISABLE_WARNING_DEPRECATED_DECLARATIONS; dl = dlopen("libbpf.so.1", RTLD_LAZY); diff --git a/src/shared/cryptsetup-util.c b/src/shared/cryptsetup-util.c index cbbc85a5cc..288e6e8942 100644 --- a/src/shared/cryptsetup-util.c +++ b/src/shared/cryptsetup-util.c @@ -252,6 +252,11 @@ int dlopen_cryptsetup(void) { DISABLE_WARNING_DEPRECATED_DECLARATIONS; + ELF_NOTE_DLOPEN("cryptsetup", + "Support for disk encryption, integrity, and authentication", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libcryptsetup.so.12"); + r = dlopen_many_sym_or_warn( &cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG, DLSYM_ARG(crypt_activate_by_passphrase), diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c index 85f3c173db..9d1f494671 100644 --- a/src/shared/elf-util.c +++ b/src/shared/elf-util.c @@ -87,6 +87,11 @@ static DLSYM_FUNCTION(gelf_getnote); int dlopen_dw(void) { int r; + ELF_NOTE_DLOPEN("dw", + "Support for backtrace and ELF package metadata decoding from core files", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libdw.so.1"); + r = dlopen_many_sym_or_warn( &dw_dl, "libdw.so.1", LOG_DEBUG, DLSYM_ARG(dwarf_getscopes), @@ -130,6 +135,11 @@ int dlopen_dw(void) { int dlopen_elf(void) { int r; + ELF_NOTE_DLOPEN("elf", + "Support for backtraces and reading ELF package metadata from core files", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libelf.so.1"); + r = dlopen_many_sym_or_warn( &elf_dl, "libelf.so.1", LOG_DEBUG, DLSYM_ARG(elf_begin), diff --git a/src/shared/firewall-util-iptables.c b/src/shared/firewall-util-iptables.c index 044d2d0744..b0abccc26b 100644 --- a/src/shared/firewall-util-iptables.c +++ b/src/shared/firewall-util-iptables.c @@ -354,6 +354,11 @@ int fw_iptables_add_local_dnat( } static int dlopen_iptc(void) { + ELF_NOTE_DLOPEN("ip4tc", + "Support for firewall rules", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libip4tc.so.2"); + return dlopen_many_sym_or_warn( &iptc_dl, "libip4tc.so.2", LOG_DEBUG, diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c index 6b26f2064a..aa88e11221 100644 --- a/src/shared/idn-util.c +++ b/src/shared/idn-util.c @@ -21,6 +21,11 @@ const char *(*sym_idn2_strerror)(int rc) _const_ = NULL; DLSYM_FUNCTION(idn2_to_unicode_8z8z); int dlopen_idn(void) { + ELF_NOTE_DLOPEN("idn", + "Support for internationalized domain names", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libidn2.so.0"); + return dlopen_many_sym_or_warn( &idn_dl, "libidn2.so.0", LOG_DEBUG, DLSYM_ARG(idn2_lookup_u8), @@ -39,6 +44,11 @@ int dlopen_idn(void) { _cleanup_(dlclosep) void *dl = NULL; int r; + ELF_NOTE_DLOPEN("idn", + "Support for internationalized domain names", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libidn.so.12", "libidn.so.11"); + if (idn_dl) return 0; /* Already loaded */ diff --git a/src/shared/libarchive-util.c b/src/shared/libarchive-util.c index e6d6581597..58f6554da2 100644 --- a/src/shared/libarchive-util.c +++ b/src/shared/libarchive-util.c @@ -30,6 +30,11 @@ DLSYM_FUNCTION(archive_write_set_format_filter_by_ext); DLSYM_FUNCTION(archive_write_set_format_gnutar); int dlopen_libarchive(void) { + ELF_NOTE_DLOPEN("archive", + "Support for decompressing archive files", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libarchive.so.13"); + return dlopen_many_sym_or_warn( &libarchive_dl, "libarchive.so.13", diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 17fb019ffc..37f6898925 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -72,6 +72,11 @@ static void fido_log_propagate_handler(const char *s) { int dlopen_libfido2(void) { int r; + ELF_NOTE_DLOPEN("fido2", + "Support fido2 for encryption and authentication", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libfido2.so.1"); + r = dlopen_many_sym_or_warn( &libfido2_dl, "libfido2.so.1", LOG_DEBUG, DLSYM_ARG(fido_assert_allow_cred), diff --git a/src/shared/module-util.c b/src/shared/module-util.c index 612ab9c9c5..fa1e0f82bb 100644 --- a/src/shared/module-util.c +++ b/src/shared/module-util.c @@ -25,6 +25,11 @@ DLSYM_FUNCTION(kmod_unref); DLSYM_FUNCTION(kmod_validate_resources); int dlopen_libkmod(void) { + ELF_NOTE_DLOPEN("kmod", + "Support for loading kernel modules", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libkmod.so.2"); + return dlopen_many_sym_or_warn( &libkmod_dl, "libkmod.so.2", diff --git a/src/shared/password-quality-util-passwdqc.c b/src/shared/password-quality-util-passwdqc.c index c32b493534..764b7724b0 100644 --- a/src/shared/password-quality-util-passwdqc.c +++ b/src/shared/password-quality-util-passwdqc.c @@ -20,6 +20,11 @@ DLSYM_FUNCTION(passwdqc_check); DLSYM_FUNCTION(passwdqc_random); int dlopen_passwdqc(void) { + ELF_NOTE_DLOPEN("passwdqc", + "Support for password quality checks", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libpasswdqc.so.1"); + return dlopen_many_sym_or_warn( &passwdqc_dl, "libpasswdqc.so.1", LOG_DEBUG, DLSYM_ARG(passwdqc_params_reset), diff --git a/src/shared/password-quality-util-pwquality.c b/src/shared/password-quality-util-pwquality.c index e070f9636c..7456469c86 100644 --- a/src/shared/password-quality-util-pwquality.c +++ b/src/shared/password-quality-util-pwquality.c @@ -24,6 +24,11 @@ DLSYM_FUNCTION(pwquality_set_int_value); DLSYM_FUNCTION(pwquality_strerror); int dlopen_pwquality(void) { + ELF_NOTE_DLOPEN("pwquality", + "Support for password quality checks", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libpwquality.so.1"); + return dlopen_many_sym_or_warn( &pwquality_dl, "libpwquality.so.1", LOG_DEBUG, DLSYM_ARG(pwquality_check), diff --git a/src/shared/pcre2-util.c b/src/shared/pcre2-util.c index 4f33efc5fc..7deb64fd49 100644 --- a/src/shared/pcre2-util.c +++ b/src/shared/pcre2-util.c @@ -27,6 +27,11 @@ const struct hash_ops pcre2_code_hash_ops_free = {}; int dlopen_pcre2(void) { #if HAVE_PCRE2 + ELF_NOTE_DLOPEN("pcre2", + "Support for regular expressions", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libpcre2-8.so.0"); + /* So here's something weird: PCRE2 actually renames the symbols exported by the library via C * macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is * gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index 8077ec3019..b5cd9a35bb 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -61,6 +61,11 @@ DLSYM_FUNCTION(p11_kit_uri_new); DLSYM_FUNCTION(p11_kit_uri_parse); int dlopen_p11kit(void) { + ELF_NOTE_DLOPEN("p11-kit", + "Support for PKCS11 hardware tokens", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libp11-kit.so.0"); + return dlopen_many_sym_or_warn( &p11kit_dl, "libp11-kit.so.0", LOG_DEBUG, diff --git a/src/shared/qrcode-util.c b/src/shared/qrcode-util.c index c087136bd2..e62a5a8635 100644 --- a/src/shared/qrcode-util.c +++ b/src/shared/qrcode-util.c @@ -24,6 +24,11 @@ static DLSYM_FUNCTION(QRcode_free); int dlopen_qrencode(void) { int r; + ELF_NOTE_DLOPEN("qrencode", + "Support for generating QR codes", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libqrencode.so.4", "libqrencode.so.3"); + FOREACH_STRING(s, "libqrencode.so.4", "libqrencode.so.3") { r = dlopen_many_sym_or_warn( &qrcode_dl, s, LOG_DEBUG, diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 3afeb09516..a64c2738bf 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -113,6 +113,11 @@ static DLSYM_FUNCTION(Tss2_RC_Decode); int dlopen_tpm2(void) { int r; + ELF_NOTE_DLOPEN("tpm", + "Support for TPM", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libtss2-esys.so.0"); + r = dlopen_many_sym_or_warn( &libtss2_esys_dl, "libtss2-esys.so.0", LOG_DEBUG, DLSYM_ARG(Esys_Create), @@ -164,12 +169,22 @@ int dlopen_tpm2(void) { if (r < 0) log_debug("libtss2-esys too old, does not include Esys_TR_GetTpmHandle."); + ELF_NOTE_DLOPEN("tpm", + "Support for TPM", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libtss2-rc.so.0"); + r = dlopen_many_sym_or_warn( &libtss2_rc_dl, "libtss2-rc.so.0", LOG_DEBUG, DLSYM_ARG(Tss2_RC_Decode)); if (r < 0) return r; + ELF_NOTE_DLOPEN("tpm", + "Support for TPM", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libtss2-mu.so.0"); + return dlopen_many_sym_or_warn( &libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG, DLSYM_ARG(Tss2_MU_TPM2_CC_Marshal),