From 7b461c8b20add20a058f24edaad6b0aa5ecf615d Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 18 Mar 2023 11:23:32 +0000 Subject: [PATCH] file: Implement RPATH/RUNPATH check Signed-off-by: Michael Tremer --- src/libpakfire/file.c | 109 ++++++++++++++++++++++++++ src/libpakfire/include/pakfire/file.h | 1 + 2 files changed, 110 insertions(+) diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index b31f04747..d8034b6ab 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -656,6 +656,13 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) { if (r < 0) goto ERROR; } + + // Has RUNPATH? + if (file->issues & PAKFIRE_FILE_HAS_RUNPATH) { + r = asprintf(&buffer, "%s [HAS-RUNPATH]", buffer); + if (r < 0) + goto ERROR; + } } return buffer; @@ -1737,6 +1744,42 @@ static int pakfire_file_get_elf_type(struct pakfire_file* file) { return type; } +static int pakfire_file_elf_dyn_walk(struct pakfire_file* file, Elf* elf, + int (*callback)(struct pakfire_file* file, Elf64_Word key, const char* value, void* data), + void* data) { + Elf_Scn* dynamic = NULL; + GElf_Shdr shdr; + Elf_Data* elf_data = NULL; + int r; + + // Find the dynamic linking information + r = pakfire_file_get_elf_section(file, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data); + if (r) { + ERROR(file->pakfire, "%s does not have a dynamic section\n", file->path); + return 1; + } + + GElf_Dyn dyn; + const char* value = NULL; + + // Walk through all entries... + for (unsigned int i = 0; ; i++) { + // Fetch the next entry + if (!gelf_getdyn(elf_data, i, &dyn)) + break; + + // Fetch the value + value = elf_strptr(elf, shdr.sh_link, dyn.d_un.d_val); + + // Call the callback + r = callback(file, dyn.d_tag, value, data); + if (r) + return r; + } + + return 0; +} + static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, void* data) { Elf_Scn* symtab = NULL; int r; @@ -1941,6 +1984,67 @@ static int pakfire_file_check_relro(struct pakfire_file* file) { return pakfire_file_open_elf(file, __pakfire_file_check_partially_relro, NULL); } +/* + RPATH/RUNPATH +*/ +static int __pakfire_file_process_runpath(struct pakfire_file* file, + Elf64_Word key, const char* value, void* data) { + const char* runpath = NULL; + char buffer[PATH_MAX]; + char* p = NULL; + int r; + + switch (key) { + case DT_RUNPATH: + case DT_RPATH: + DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", file->path, value); + + // Copy the value into a buffer we can modify + r = pakfire_string_set(buffer, value); + if (r) + return r; + + // Split the value by : + runpath = strtok_r(buffer, ":", &p); + + // Iterate over all elements + while (runpath) { + DEBUG(file->pakfire, "Checking RUNPATH %s\n", runpath); + + // We do not allow any relative RUNPATHs + if (pakfire_path_match(runpath, "**/../**")) { + file->issues |= PAKFIRE_FILE_HAS_RUNPATH; + break; + } + + /* + We allow some RUNPATHs where some software is loading some + modules as shared objects from a private directory in /usr/lib64. + */ + if (!pakfire_path_match(runpath, "/usr/lib64") + && !pakfire_path_match(runpath, "/usr/lib64/**")) { + file->issues |= PAKFIRE_FILE_HAS_RUNPATH; + break; + } + + // Move on to the next RUNPATH + runpath = strtok_r(NULL, ":", &p); + } + + default: + break; + } + + return 0; +} + +static int __pakfire_file_check_runpath(struct pakfire_file* file, Elf* elf, void* data) { + return pakfire_file_elf_dyn_walk(file, elf, __pakfire_file_process_runpath, data); +} + +static int pakfire_file_check_runpath(struct pakfire_file* file) { + return pakfire_file_open_elf(file, __pakfire_file_check_runpath, NULL); +} int pakfire_file_check(struct pakfire_file* file, int* issues) { int r; @@ -1992,6 +2096,11 @@ int pakfire_file_check(struct pakfire_file* file, int* issues) { r = pakfire_file_check_relro(file); if (r) return r; + + // Check for RUNPATH + r = pakfire_file_check_runpath(file); + if (r) + return r; } DONE: diff --git a/src/libpakfire/include/pakfire/file.h b/src/libpakfire/include/pakfire/file.h index 382c01c1f..0308daf28 100644 --- a/src/libpakfire/include/pakfire/file.h +++ b/src/libpakfire/include/pakfire/file.h @@ -182,6 +182,7 @@ enum pakfire_file_check_issues { PAKFIRE_FILE_MISSING_PIE = (1 << 3), PAKFIRE_FILE_EXECSTACK = (1 << 4), PAKFIRE_FILE_NO_PARTIALLY_RELRO = (1 << 5), + PAKFIRE_FILE_HAS_RUNPATH = (1 << 6), }; int pakfire_file_check(struct pakfire_file* file, int* issues); -- 2.39.5