From 9e4e24ec013eec6ed42f0641874b8bd4085ab28c Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 26 Oct 2024 11:36:09 +0000 Subject: [PATCH] linter: Check for RELRO Signed-off-by: Michael Tremer --- src/libpakfire/file.c | 74 ------------------------ src/libpakfire/linter-file.c | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index f4bc1bde3..6b229c576 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -2018,75 +2018,6 @@ static int pakfire_file_check_debuginfo(struct pakfire_file* file) { return pakfire_file_open_elf(file, __pakfire_file_check_debuginfo, NULL); } -static int __pakfire_file_process_bind_now(struct pakfire_file* file, - Elf* elf, 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_file_check_relro( - struct pakfire_file* file, Elf* elf, void* data) { - int has_bind_now = 0; - GElf_Phdr phdr; - int r; - - // Check if we have BIND_NOW - r = pakfire_file_elf_dyn_walk(file, elf, - __pakfire_file_process_bind_now, &has_bind_now); - if (r) - return r; - - // We are not fully RELRO - if (!has_bind_now) { - file->issues |= PAKFIRE_FILE_NO_RELRO; - - return 0; - } - - // Walk through all program headers - for (unsigned int i = 0;; i++) { - if (!gelf_getphdr(elf, i, &phdr)) - break; - - switch (phdr.p_type) { - case PT_GNU_RELRO: - return 0; - - default: - break; - } - } - - // This file does not seem to have PT_GNU_RELRO set - file->issues |= PAKFIRE_FILE_NO_RELRO; - - return 0; -} - -static int pakfire_file_check_relro(struct pakfire_file* file) { - return pakfire_file_open_elf(file, __pakfire_file_check_relro, NULL); -} - /* RPATH/RUNPATH */ @@ -2674,11 +2605,6 @@ int pakfire_file_check(struct pakfire_file* file, int* issues) { if (r) return r; - // Check for RELRO - r = pakfire_file_check_relro(file); - if (r) - return r; - // Check for RUNPATH r = pakfire_file_check_runpath(file); if (r) diff --git a/src/libpakfire/linter-file.c b/src/libpakfire/linter-file.c index 93821f003..1834a795e 100644 --- a/src/libpakfire/linter-file.c +++ b/src/libpakfire/linter-file.c @@ -282,6 +282,38 @@ static int pakfire_linter_file_get_elf_section(struct pakfire_linter_file* lfile return 1; } +static int pakfire_linter_file_elf_dyn_walk(struct pakfire_linter_file* lfile, Elf* elf, + int (*callback)(struct pakfire_linter_file* lfile, Elf* elf, + const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data), 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_linter_file_get_elf_section(lfile, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data); + if (r) { + DEBUG(lfile->ctx, "%s does not have a dynamic section\n", lfile->path); + return 0; + } + + // 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(lfile, elf, &shdr, &dyn, data); + if (r) + return r; + } + + return 0; +} + + static int pakfire_linter_file_check_pie(struct pakfire_linter_file* lfile) { switch (pakfire_linter_file_get_elf_type(lfile)) { // Shared Object files are good @@ -418,6 +450,74 @@ static int pakfire_linter_file_check_execstack(struct pakfire_linter_file* lfile return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_execstack, NULL); } + +static int __pakfire_linter_file_has_bind_now(struct pakfire_linter_file* lfile, + Elf* elf, 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, Elf* elf, void* data) { + int has_bind_now = 0; + GElf_Phdr phdr; + int r; + + // Check if we have BIND_NOW + r = pakfire_linter_file_elf_dyn_walk(lfile, elf, + __pakfire_linter_file_has_bind_now, &has_bind_now); + if (r) + return r; + + // We are not fully RELRO + if (!has_bind_now) + return pakfire_linter_file_error(lfile, "Is not fully RELRO"); + + // Walk through all program headers + for (unsigned int i = 0;; i++) { + if (!gelf_getphdr(elf, i, &phdr)) + break; + + switch (phdr.p_type) { + case PT_GNU_RELRO: + r = pakfire_linter_file_warning(lfile, "Is partially RELRO"); + if (r < 0) + return 0; + break; + + default: + break; + } + } + + // This file does not seem to have PT_GNU_RELRO set + return pakfire_linter_file_error(lfile, "Is not fully RELRO"); +} + +static int pakfire_linter_file_check_relro(struct pakfire_linter_file* lfile) { + return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_relro, NULL); +} + int pakfire_linter_file_lint(struct pakfire_linter_file* lfile) { int r = 0; @@ -449,6 +549,11 @@ int pakfire_linter_file_lint(struct pakfire_linter_file* lfile) { r = pakfire_linter_file_check_execstack(lfile); if (r < 0) return r; + + // Check RELRO + r = pakfire_linter_file_check_relro(lfile); + if (r < 0) + return r; } return 0; -- 2.39.5