From: Michael Tremer Date: Sat, 26 Oct 2024 09:56:58 +0000 (+0000) Subject: linter: Move the SSP check X-Git-Tag: 0.9.30~863 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6adac5d5e9ea0e388ab412dafea414eda24eec5f;p=pakfire.git linter: Move the SSP check Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index af129bb8d..b26242ae9 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -752,13 +752,6 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) { goto ERROR; } - // Stack-smashing Protection - if (file->issues & PAKFIRE_FILE_MISSING_SSP) { - r = asprintf(&buffer, "%s [MISSING-SSP]", buffer); - if (r < 0) - goto ERROR; - } - // Executable Stack if (file->issues & PAKFIRE_FILE_EXECSTACK) { r = asprintf(&buffer, "%s [EXECSTACK]", buffer); @@ -2035,88 +2028,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_check_ssp( - struct pakfire_file* file, Elf* elf, void* data) { - Elf_Scn* symtab = NULL; - GElf_Shdr shdr; - Elf_Data* elf_data = NULL; - GElf_Sym symbol; - const char* name = NULL; - int r; - - // Fetch the symbol table - r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data); - if (r) { - ERROR(file->ctx, "%s has no symbol table\n", pakfire_file_get_path(file)); - return 1; - } - - // Count any global functions - size_t counter = 0; - - // Walk through all symbols - for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { - gelf_getsym(elf_data, i, &symbol); - - // Fetch the symbol name - name = elf_strptr(elf, shdr.sh_link, symbol.st_name); - - // Skip empty section names - if (!name || !*name) - continue; - - // Exit if there is a symbol called "__stack_chk_fail" - if (pakfire_string_startswith(name, "__stack_chk_fail")) - return 0; - - // Count any global functions - if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) && - (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC)) - counter++; - } - - // We do not perform the check for libraries that do not contain any functions. - // Some packages use shared libraries to provide data. - if (!counter) { - DEBUG(file->ctx, "%s: File has no functions. Skipping SSP check.\n", - pakfire_file_get_path(file)); - return 0; - } - - // The file does not seem to have SSP enabled - file->issues |= PAKFIRE_FILE_MISSING_SSP; - - return 0; -} - -static int pakfire_file_check_ssp(struct pakfire_file* file) { - // This check will be skipped for these files - static const char* whitelist[] = { - "/usr/lib64/libgcc_s.so.*", - "/usr/lib64/libmvec.so.*", - NULL, - }; - - // Do not perform this check for runtime linkers - if (pakfire_file_matches_class(file, PAKFIRE_FILE_RUNTIME_LINKER)) - return 0; - - // We cannot perform this check if we don't have debuginfo - if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO) - return 0; - - // Check if this file is whitelisted - for (const char** path = whitelist; *path; path++) { - if (pakfire_file_matches(file, *path)) { - DEBUG(file->ctx, "Skipping SSP check for whitelisted file %s\n", - pakfire_file_get_path(file)); - return 0; - } - } - - return pakfire_file_open_elf(file, __pakfire_file_check_ssp, NULL); -} - static int __pakfire_file_check_execstack( struct pakfire_file* file, Elf* elf, void* data) { GElf_Phdr phdr; @@ -2828,11 +2739,6 @@ int pakfire_file_check(struct pakfire_file* file, int* issues) { if (r) return r; - // Check for SSP - r = pakfire_file_check_ssp(file); - if (r) - return r; - // Check for executable stacks r = pakfire_file_check_execstack(file); if (r) diff --git a/src/libpakfire/include/pakfire/file.h b/src/libpakfire/include/pakfire/file.h index 326fd4d3c..d60b8f259 100644 --- a/src/libpakfire/include/pakfire/file.h +++ b/src/libpakfire/include/pakfire/file.h @@ -188,7 +188,6 @@ int pakfire_file_verify(struct pakfire_file* file, int* status); enum pakfire_file_check_issues { PAKFIRE_FILE_FHS_ERROR = (1 << 0), PAKFIRE_FILE_MISSING_DEBUGINFO = (1 << 1), - PAKFIRE_FILE_MISSING_SSP = (1 << 2), PAKFIRE_FILE_EXECSTACK = (1 << 4), PAKFIRE_FILE_NO_RELRO = (1 << 5), PAKFIRE_FILE_HAS_RUNPATH = (1 << 6), diff --git a/src/libpakfire/linter-file.c b/src/libpakfire/linter-file.c index 879d93708..64fa588ed 100644 --- a/src/libpakfire/linter-file.c +++ b/src/libpakfire/linter-file.c @@ -28,6 +28,7 @@ #include #include #include +#include struct pakfire_linter_file { struct pakfire_ctx* ctx; @@ -239,6 +240,41 @@ static int pakfire_linter_file_get_elf_type(struct pakfire_linter_file* lfile) { return type; } +static int pakfire_linter_file_get_elf_section(struct pakfire_linter_file* lfile, + Elf* elf, const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) { + Elf_Scn* s = NULL; + + GElf_Shdr shdr; + + // Walk through all sections + for (;;) { + s = elf_nextscn(elf, s); + if (!s) + break; + + // Fetch the section header + gelf_getshdr(s, &shdr); + + // Return any matching sections + if (shdr.sh_type == type) { + *section = s; + + // Send header if requested + if (header) + gelf_getshdr(s, header); + + // Send data if requested + if (data) + *data = elf_getdata(s, NULL); + + return 0; + } + } + + // No section found + return 1; +} + 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 @@ -253,6 +289,81 @@ static int pakfire_linter_file_check_pie(struct pakfire_linter_file* lfile) { return pakfire_linter_error(lfile->linter, "%s is not PIE", lfile->path); } +static int __pakfire_linter_file_check_ssp( + struct pakfire_linter_file* lfile, Elf* elf, void* data) { + Elf_Scn* symtab = NULL; + GElf_Shdr shdr; + Elf_Data* elf_data = NULL; + GElf_Sym symbol; + const char* name = NULL; + int r; + + // Fetch the symbol table + r = pakfire_linter_file_get_elf_section(lfile, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data); + if (r) { + ERROR(lfile->ctx, "%s has no symbol table\n", lfile->path); + return 1; + } + + // Count any global functions + size_t counter = 0; + + // Walk through all symbols + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { + gelf_getsym(elf_data, i, &symbol); + + // Fetch the symbol name + name = elf_strptr(elf, shdr.sh_link, symbol.st_name); + + // Skip empty section names + if (!name || !*name) + continue; + + // Exit if there is a symbol called "__stack_chk_fail" + if (pakfire_string_startswith(name, "__stack_chk_fail")) + return 0; + + // Count any global functions + if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) && + (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC)) + counter++; + } + + // We do not perform the check for libraries that do not contain any functions. + // Some packages use shared libraries to provide data. + if (!counter) { + DEBUG(lfile->ctx, "%s: File has no functions. Skipping SSP check.\n", lfile->path); + return 0; + } + + // The file does not seem to have SSP enabled + return pakfire_linter_error(lfile->linter, + "%s does not have Stack Smashing Protection", lfile->path); +} + +static int pakfire_linter_file_check_ssp(struct pakfire_linter_file* lfile) { + // This check will be skipped for these files + static const char* whitelist[] = { + "/usr/lib64/libgcc_s.so.*", + "/usr/lib64/libmvec.so.*", + NULL, + }; + + // Do not perform this check for runtime linkers + if (pakfire_file_matches(lfile->file, "/usr/lib*/ld-*.so*")) + return 0; + + // Check if this file is whitelisted + for (const char** path = whitelist; *path; path++) { + if (pakfire_file_matches(lfile->file, *path)) { + DEBUG(lfile->ctx, "Skipping SSP check for whitelisted file %s\n", lfile->path); + return 0; + } + } + + return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_ssp, NULL); +} + int pakfire_linter_file_lint(struct pakfire_linter_file* lfile) { int r = 0; @@ -262,6 +373,11 @@ int pakfire_linter_file_lint(struct pakfire_linter_file* lfile) { r = pakfire_linter_file_check_pie(lfile); if (r < 0) return r; + + // Check SSP + r = pakfire_linter_file_check_ssp(lfile); + if (r < 0) + return r; } return 0;