From 88e375f89c11c989737f6d00b0cfe6309f7447d7 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 8 Aug 2025 12:50:12 +0100 Subject: [PATCH 1/3] fix(dracut-install): the -n short option for --dry-run I forgot to update the getopt call. Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -1638,7 +1638,7 @@ static int parse_argv(int argc, char *argv[]) {NULL, 0, NULL, 0} }; - while ((c = getopt_long(argc, argv, "madfhlL:oD:Hr:Rp:P:s:S:N:v", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "madfhlL:oD:Hr:Rp:P:s:S:N:vn", options, NULL)) != -1) { switch (c) { case ARG_VERSION: puts(PROGRAM_VERSION_STRING); -- 2.50.1 From 06e95cc602d0c6df99f4a54b2ade7deb59343a40 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 8 Aug 2025 12:52:23 +0100 Subject: [PATCH 2/3] fix(dracut-install): the RUNPATH expansion returning empty strings The input was not initially copied into the result, so the result would start with a null pointer and be treated as an empty string. Expansion will not occur in most cases, leading to a straight copy of input being returned, so just do that in the first place. Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -770,7 +770,7 @@ static char *search_via_ldconf(const char *conf_pattern, const char *soname, con expands to the directory of the given src path. $LIB expands to lib if match64 is NULL or lib64 otherwise. Returns a newly allocated string even if no expansion was necessary. */ -static char *expand_runpath(char *input, const char *src, const Elf64_Ehdr *match64) +static char *expand_runpath(const char *input, const char *src, const Elf64_Ehdr *match64) { regex_t regex; regmatch_t rmatch[3]; /* 0: full match, 1: without brackets, 2: with brackets */ @@ -780,11 +780,15 @@ static char *expand_runpath(char *input, const char *src, const Elf64_Ehdr *matc return NULL; } - char *result = NULL, *current = input; + char *result = strdup(input); + if (!result) + goto oom; + + const char *current = input; int offset = 0; while (regexec(®ex, current + offset, 3, rmatch, 0) == 0) { - char *varname = NULL; + const char *varname = NULL; _cleanup_free_ char *varval = NULL; size_t varname_len, varval_len; @@ -823,7 +827,7 @@ static char *expand_runpath(char *input, const char *src, const Elf64_Ehdr *matc } regfree(®ex); - return result ?: strdup(current); + return result; oom: log_error("Out of memory"); -- 2.50.1 From 9f2f306fa971ee00cee0ae307479bc8a8dbc5263 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 8 Aug 2025 13:18:07 +0100 Subject: [PATCH 3/3] fix(dracut-install): the handling of absolute paths in sonames If the soname is an absolute path, expand it like the RUNPATH, and return it (with the sysroot) without further checks like glibc and musl do. They also support relative paths, but we cannot feasibly support them. Such paths are relative to the current directory of the calling process at runtime, which we cannot know in this context. This was observed with Neovim. Bug: https://bugs.gentoo.org/961101 Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -894,6 +894,21 @@ oom: static char *find_library(const char *soname, const char *src, size_t src_len, const Elf64_Ehdr *match64, const Elf32_Ehdr *match32) { + /* If the soname is an absolute path, expand it like the RUNPATH, and + return it (with the sysroot) without further checks like glibc and + musl do. They also support relative paths, but we cannot feasibly + support them. Such paths are relative to the current directory of the + calling process at runtime, which we cannot know in this context. */ + if (soname[0] == '/') { + _cleanup_free_ char *expanded = expand_runpath(soname, src, match64); + if (!expanded) + return NULL; + + char *sysroot_expanded = NULL; + _asprintf(&sysroot_expanded, "%s%s", sysrootdir ?: "", expanded); + return sysroot_expanded; + } + if (match64) FIND_LIBRARY_RUNPATH_FOR_BITS(64, match64); else if (match32) -- 2.50.1 From 7186fa47fee7060a70fa6698748c4f4793edadf8 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 11 Aug 2025 10:12:59 +0100 Subject: [PATCH 4/6] fix(dracut-install): handling of multiple sonames in dlopen JSON We should not try to install every library referenced in the soname array, only the first one present. The array is intended to be an ordered preference list. Closes: https://github.com/dracut-ng/dracut-ng/issues/1552 Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -951,9 +951,10 @@ static void resolve_deps_dlopen_parse_json(Hashmap *pdeps, Hashmap *deps, const for (size_t entry_idx = 0; entry_idx < sd_json_variant_elements(dlopen_json); entry_idx++) { sd_json_variant *entry = sd_json_variant_by_index(dlopen_json, entry_idx); sd_json_variant *feature_json = sd_json_variant_by_key(entry, "feature"); + const char *feature = NULL; if (feature_json && sd_json_variant_is_string(feature_json)) { - const char *feature = sd_json_variant_string(feature_json); + feature = sd_json_variant_string(feature_json); const char *name = src_soname ?: basename(fullsrcpath); Iterator i; @@ -988,12 +989,15 @@ static void resolve_deps_dlopen_parse_json(Hashmap *pdeps, Hashmap *deps, const const char *soname = sd_json_variant_string(soname_json); if (hashmap_get(pdeps, soname)) - continue; + goto skip; char *library = find_library(soname, fullsrcpath, src_len, match64, match32); - if (!library || hashmap_put_strdup_key(deps, soname, library) < 0) - log_warning("WARNING: could not locate dlopen dependency %s requested by '%s'", soname, fullsrcpath); + if (library && hashmap_put_strdup_key(deps, soname, library) == 0) + goto skip; } + + log_warning("WARNING: could not locate dlopen dependency for %s feature requested by '%s'", feature ?: "unnamed", + fullsrcpath); skip: } } -- 2.50.1 From 5c69be7d20af599cc6dd94d451a16d8639139bce Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 11 Aug 2025 10:51:51 +0100 Subject: [PATCH 5/6] fix(dracut-install): cache resolve_deps calls for speed and less noise The dlopen dependency failure warning was particularly noisy and likely to trigger. We were already caching the processed items in resolve_lazy, but resolve_deps recurses many times, so it was necessary to move the cache down a level. I didn't reuse "items" here because it would have clashed with its usage elsewhere. I had to think about whether the cache would function correctly with changing values of pdeps. If a dependency is not found on the first attempt, it does not prevent its consumer from being installed, so it does not matter that it might be found via a RUNPATH on a subsequent attempt. Closes: https://github.com/dracut-ng/dracut-ng/issues/1552 Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -93,6 +93,7 @@ static Hashmap *items_failed = NULL; static Hashmap *modules_loaded = NULL; static Hashmap *modules_suppliers = NULL; static Hashmap *processed_suppliers = NULL; +static Hashmap *processed_deps = NULL; static Hashmap *modalias_to_kmod = NULL; static Hashmap *add_dlopen_features = NULL; static Hashmap *omit_dlopen_features = NULL; @@ -1132,13 +1133,21 @@ skip: Both ELF binaries and scripts with shebangs are handled. */ static int resolve_deps(const char *src, Hashmap *pdeps) { - _cleanup_free_ char *fullsrcpath = NULL; - - fullsrcpath = get_real_file(src, true); + char *fullsrcpath = get_real_file(src, true); log_debug("resolve_deps('%s') -> get_real_file('%s', true) = '%s'", src, src, fullsrcpath); if (!fullsrcpath) return 0; + switch (hashmap_put(processed_deps, fullsrcpath, fullsrcpath)) { + case -EEXIST: + free(fullsrcpath); + return 0; + case -ENOMEM: + log_error("Out of memory"); + free(fullsrcpath); + return -ENOMEM; + } + _cleanup_close_ int fd = open(fullsrcpath, O_RDONLY | O_CLOEXEC); if (fd < 0) { log_error("ERROR: cannot open '%s': %m", fullsrcpath); @@ -1838,27 +1847,10 @@ static int parse_argv(int argc, char *argv[]) static int resolve_lazy(int argc, char **argv) { int i; - size_t destrootdirlen = strlen(destrootdir); int ret = 0; - char *item; for (i = 0; i < argc; i++) { - const char *src = argv[i]; - char *p = argv[i]; - - log_debug("resolve_deps('%s')", src); - - if (strstr(src, destrootdir)) { - p = &argv[i][destrootdirlen]; - } - - if (check_hashmap(items, p)) { - continue; - } - - item = strdup(p); - hashmap_put(items, item, item); - - ret += resolve_deps(src, NULL); + log_debug("resolve_deps('%s')", argv[i]); + ret += resolve_deps(argv[i], NULL); } return ret; } @@ -3008,13 +3000,14 @@ int main(int argc, char **argv) items = hashmap_new(string_hash_func, string_compare_func); items_failed = hashmap_new(string_hash_func, string_compare_func); processed_suppliers = hashmap_new(string_hash_func, string_compare_func); + processed_deps = hashmap_new(string_hash_func, string_compare_func); modalias_to_kmod = hashmap_new(string_hash_func, string_compare_func); dlopen_features[0] = add_dlopen_features = hashmap_new(string_hash_func, string_compare_func); dlopen_features[1] = omit_dlopen_features = hashmap_new(string_hash_func, string_compare_func); if (!items || !items_failed || !processed_suppliers || !modules_loaded || - !add_dlopen_features || !omit_dlopen_features) { + !processed_deps || !add_dlopen_features || !omit_dlopen_features) { log_error("Out of memory"); r = EXIT_FAILURE; goto finish1; @@ -3093,6 +3086,9 @@ finish2: while ((i = hashmap_steal_first(processed_suppliers))) item_free(i); + while ((i = hashmap_steal_first(processed_deps))) + item_free(i); + for (size_t j = 0; j < 2; j++) { char ***array; Iterator it; @@ -3118,6 +3114,7 @@ finish2: hashmap_free(modules_loaded); hashmap_free(modules_suppliers); hashmap_free(processed_suppliers); + hashmap_free(processed_deps); hashmap_free(modalias_to_kmod); if (arg_mod_filter_path) -- 2.50.1 From edb94a1b2c7d11a29eb055a28fa598e8fd317fe4 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Tue, 12 Aug 2025 10:15:58 +0100 Subject: [PATCH 6/6] fix(dracut-install): broken calls to mmap with 0 length This results in an invalid argument error, so check for 0 length first. Fixes: https://bugs.gentoo.org/961340 Signed-off-by: James Le Cuirot --- a/src/install/dracut-install.c +++ b/src/install/dracut-install.c @@ -632,7 +632,11 @@ static char *check_lib_match(const char *dirname, const char *basename, const ch if (fstat(fd, &sb) < 0) goto finish2; - void *map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + size_t lib_len = sb.st_size; + if (lib_len == 0) + goto finish2; + + void *map = mmap(NULL, lib_len, PROT_READ, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) goto finish2; @@ -1161,6 +1165,9 @@ static int resolve_deps(const char *src, Hashmap *pdeps) } size_t src_len = sb.st_size; + if (src_len == 0) + return 0; + void *map = mmap(NULL, src_len, PROT_READ, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { log_error("ERROR: cannot mmap '%s': %m", fullsrcpath); -- 2.50.1