From: Michael Tremer Date: Wed, 1 Jan 2025 17:56:45 +0000 (+0000) Subject: ELF: Move RELRO check X-Git-Tag: 0.9.30~595 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bea6e5f1d33e221b11a2ebb68743d1226e5305da;p=pakfire.git ELF: Move RELRO check Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/elf.c b/src/libpakfire/elf.c index 9f69f6c57..268c2b3a5 100644 --- a/src/libpakfire/elf.c +++ b/src/libpakfire/elf.c @@ -286,6 +286,39 @@ static int pakfire_elf_get_section(struct pakfire_elf* self, return 1; } +typedef int (*pakfire_elf_dyn_walk_callback) + (struct pakfire_elf* self, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data); + +static int pakfire_elf_dyn_walk(struct pakfire_elf* self, + pakfire_elf_dyn_walk_callback callback, void* data) { + Elf_Scn* dynamic = NULL; + GElf_Shdr shdr; + Elf_Data* elf_data = NULL; + GElf_Dyn dyn; + int r; + + // Find the dynamic linking information + r = pakfire_elf_get_section(self, SHT_DYNAMIC, &dynamic, &shdr, &elf_data); + if (r) { + DEBUG(self->ctx, "%s does not have a dynamic section\n", self->path); + return r; + } + + // Walk through all entries... + for (unsigned int i = 0; ; i++) { + // Fetch the next entry + if (!gelf_getdyn(elf_data, i, &dyn)) + break; + + // Call the callback + r = callback(self, &shdr, &dyn, data); + if (r) + return r; + } + + return 0; +} + int pakfire_elf_is_pie(struct pakfire_elf* self) { switch (pakfire_elf_type(self)) { // Shared Object files are good @@ -399,6 +432,54 @@ int pakfire_elf_has_execstack(struct pakfire_elf* self) { return 0; } +static int pakfire_elf_has_bind_now(struct pakfire_elf* self, + const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) { + switch (dyn->d_tag) { + case DT_BIND_NOW: + return 1; + break; + + case DT_FLAGS: + if (dyn->d_un.d_val & DF_BIND_NOW) + return 1; + break; + + case DT_FLAGS_1: + if (dyn->d_un.d_val & DF_1_NOW) + return 1; + break; + + default: + break; + } + + return 0; +} + +int pakfire_elf_is_fully_relro(struct pakfire_elf* self) { + return pakfire_elf_dyn_walk(self, pakfire_elf_has_bind_now, NULL); +} + +int pakfire_elf_is_partially_relro(struct pakfire_elf* self) { + GElf_Phdr phdr; + + // Walk through all program headers + for (unsigned int i = 0;; i++) { + if (!gelf_getphdr(self->elf, i, &phdr)) + break; + + switch (phdr.p_type) { + case PT_GNU_RELRO: + return 1; + + default: + break; + } + } + + return 0; +} + int pakfire_elf_is_stripped(struct pakfire_elf* self) { Elf_Scn* symtab = NULL; diff --git a/src/libpakfire/include/pakfire/elf.h b/src/libpakfire/include/pakfire/elf.h index f34e405e1..d36f52b48 100644 --- a/src/libpakfire/include/pakfire/elf.h +++ b/src/libpakfire/include/pakfire/elf.h @@ -45,6 +45,8 @@ const char* pakfire_elf_debuglink(struct pakfire_elf* self); int pakfire_elf_is_pie(struct pakfire_elf* self); int pakfire_elf_has_ssp(struct pakfire_elf* self); int pakfire_elf_has_execstack(struct pakfire_elf* self); +int pakfire_elf_is_fully_relro(struct pakfire_elf* self); +int pakfire_elf_is_partially_relro(struct pakfire_elf* self); int pakfire_elf_is_stripped(struct pakfire_elf* self); #endif /* PAKFIRE_PRIVATE */ diff --git a/src/libpakfire/linter-file.c b/src/libpakfire/linter-file.c index 3f4164337..fb2f7ace5 100644 --- a/src/libpakfire/linter-file.c +++ b/src/libpakfire/linter-file.c @@ -488,62 +488,16 @@ static int pakfire_linter_file_check_execstack(struct pakfire_linter_file* lfile return 0; } -static int __pakfire_linter_file_has_bind_now(struct pakfire_linter_file* lfile, - const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) { - int* has_bind_now = (int*)data; - - switch (dyn->d_tag) { - case DT_BIND_NOW: - *has_bind_now = 1; - break; - - case DT_FLAGS: - if (dyn->d_un.d_val & DF_BIND_NOW) - *has_bind_now = 1; - break; - - case DT_FLAGS_1: - if (dyn->d_un.d_val & DF_1_NOW) - *has_bind_now = 1; - break; - - default: - break; - } - - return 0; -} - static int pakfire_linter_file_check_relro(struct pakfire_linter_file* lfile) { - int has_bind_now = 0; - GElf_Phdr phdr; - int r; - - // Check if we have BIND_NOW - r = pakfire_linter_file_elf_dyn_walk(lfile, - __pakfire_linter_file_has_bind_now, &has_bind_now); - if (r) - return r; - - // We are fully RELRO - if (has_bind_now) + // If the file is fully RELRO, everything is good + if (pakfire_elf_is_fully_relro(lfile->_elf)) return 0; - // Walk through all program headers - for (unsigned int i = 0;; i++) { - if (!gelf_getphdr(lfile->elf, i, &phdr)) - break; - - switch (phdr.p_type) { - case PT_GNU_RELRO: - return pakfire_linter_file_warning(lfile, "Is partially RELRO"); - - default: - break; - } - } + // Show a warning if the file is only partially RELRO + else if (pakfire_elf_is_partially_relro(lfile->_elf)) + return pakfire_linter_file_warning(lfile, "Is partially RELRO"); - // This file does not seem to have PT_GNU_RELRO set + // Return an error if this file is not RELRO at all return pakfire_linter_file_error(lfile, "Is not RELRO"); }