1
0
mirror of https://github.com/systemd/systemd.git synced 2025-05-29 01:05:59 +03:00
systemd/src/shared/pcre2-util.c
Lennart Poettering cd7c207795 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 <bluca@debian.org>
2024-05-08 11:07:36 +01:00

172 lines
6.1 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "dlfcn-util.h"
#include "log.h"
#include "pcre2-util.h"
#if HAVE_PCRE2
static void *pcre2_dl = NULL;
DLSYM_FUNCTION(pcre2_match_data_create);
DLSYM_FUNCTION(pcre2_match_data_free);
DLSYM_FUNCTION(pcre2_code_free);
DLSYM_FUNCTION(pcre2_compile);
DLSYM_FUNCTION(pcre2_get_error_message);
DLSYM_FUNCTION(pcre2_match);
DLSYM_FUNCTION(pcre2_get_ovector_pointer);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
pcre2_code_hash_ops_free,
pcre2_code,
(void (*)(const pcre2_code *, struct siphash*))trivial_hash_func,
(int (*)(const pcre2_code *, const pcre2_code*))trivial_compare_func,
sym_pcre2_code_free);
#else
const struct hash_ops pcre2_code_hash_ops_free = {};
#endif
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
* actually get away with that. That's because DLSYM_ARG() useses STRINGIFY() to generate a string
* version of the symbol name, and that resolves the macro mapping implicitly already, so that the
* string actually contains the "_8" suffix already due to that and we don't have to append it
* manually anymore. C is weird. 🤯 */
return dlopen_many_sym_or_warn(
&pcre2_dl, "libpcre2-8.so.0", LOG_ERR,
DLSYM_ARG(pcre2_match_data_create),
DLSYM_ARG(pcre2_match_data_free),
DLSYM_ARG(pcre2_code_free),
DLSYM_ARG(pcre2_compile),
DLSYM_ARG(pcre2_get_error_message),
DLSYM_ARG(pcre2_match),
DLSYM_ARG(pcre2_get_ovector_pointer));
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
#endif
}
int pattern_compile_and_log(const char *pattern, PatternCompileCase case_, pcre2_code **ret) {
#if HAVE_PCRE2
PCRE2_SIZE erroroffset;
_cleanup_(sym_pcre2_code_freep) pcre2_code *p = NULL;
unsigned flags = 0;
int errorcode, r;
assert(pattern);
r = dlopen_pcre2();
if (r < 0)
return r;
if (case_ == PATTERN_COMPILE_CASE_INSENSITIVE)
flags = PCRE2_CASELESS;
else if (case_ == PATTERN_COMPILE_CASE_AUTO) {
_cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
bool has_case;
_cleanup_(sym_pcre2_code_freep) pcre2_code *cs = NULL;
md = sym_pcre2_match_data_create(1, NULL);
if (!md)
return log_oom();
r = pattern_compile_and_log("[[:upper:]]", PATTERN_COMPILE_CASE_SENSITIVE, &cs);
if (r < 0)
return r;
r = sym_pcre2_match(cs, (PCRE2_SPTR8) pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
has_case = r >= 0;
flags = !has_case * PCRE2_CASELESS;
}
log_debug("Doing case %s matching based on %s",
flags & PCRE2_CASELESS ? "insensitive" : "sensitive",
case_ != PATTERN_COMPILE_CASE_AUTO ? "request" : "pattern casing");
p = sym_pcre2_compile((PCRE2_SPTR8) pattern,
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
if (!p) {
unsigned char buf[LINE_MAX];
r = sym_pcre2_get_error_message(errorcode, buf, sizeof buf);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad pattern \"%s\": %s", pattern,
r < 0 ? "unknown error" : (char *)buf);
}
if (ret)
*ret = TAKE_PTR(p);
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
#endif
}
int pattern_matches_and_log(pcre2_code *compiled_pattern, const char *message, size_t size, size_t *ret_ovec) {
#if HAVE_PCRE2
_cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
int r;
assert(compiled_pattern);
assert(message);
/* pattern_compile_and_log() must be called before this function is called and that function already
* dlopens pcre2 so we can assert on it being available here. */
assert(pcre2_dl);
md = sym_pcre2_match_data_create(1, NULL);
if (!md)
return log_oom();
r = sym_pcre2_match(compiled_pattern,
(const unsigned char *)message,
size,
0, /* start at offset 0 in the subject */
0, /* default options */
md,
NULL);
if (r == PCRE2_ERROR_NOMATCH)
return false;
if (r < 0) {
unsigned char buf[LINE_MAX];
r = sym_pcre2_get_error_message(r, buf, sizeof(buf));
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Pattern matching failed: %s",
r < 0 ? "unknown error" : (char*) buf);
}
if (ret_ovec) {
ret_ovec[0] = sym_pcre2_get_ovector_pointer(md)[0];
ret_ovec[1] = sym_pcre2_get_ovector_pointer(md)[1];
}
return true;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
#endif
}
void *pattern_free(pcre2_code *p) {
#if HAVE_PCRE2
if (!p)
return NULL;
assert(pcre2_dl);
sym_pcre2_code_free(p);
return NULL;
#else
assert(p == NULL);
return NULL;
#endif
}