]> git.ipfire.org Git - pakfire.git/commitdiff
build: Move SSP check into the build process
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 5 Mar 2023 15:48:20 +0000 (15:48 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 5 Mar 2023 15:48:20 +0000 (15:48 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/build.c
src/libpakfire/file.c
src/libpakfire/include/pakfire/file.h
src/scripts/check-hardening

index 7b05b7b67fa7cd56884b9b0aeeb5136391695f63..5a9718171b9c7f3c86271c5fd285675a4c96b7a2 100644 (file)
@@ -1134,6 +1134,42 @@ static int pakfire_build_post_check_broken_symlinks(
                PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY);
 }
 
+static int __pakfire_build_post_check_stack_smashing_protection(
+               struct pakfire* pakfire, struct pakfire_file* file, void* data) {
+       struct pakfire_filelist* broken = (struct pakfire_filelist*)data;
+       int r;
+
+       // Skip anything that isn't an ELF file
+       if (!pakfire_file_matches_class(file, PAKFIRE_FILE_ELF))
+               return 0;
+
+       if (!pakfire_file_has_stack_smashing_protection(file)) {
+               r = pakfire_filelist_add(broken, file);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+static int pakfire_build_post_check_stack_smashing_protection(
+               struct pakfire_build* build, struct pakfire_filelist* filelist) {
+       return pakfire_build_post_process_files(build, filelist,
+               "Stack-smashing Protection is missing:",
+               __pakfire_build_post_check_stack_smashing_protection,
+               PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY);
+}
+
+static int pakfire_build_post_check_hardening(
+               struct pakfire_build* build, struct pakfire_filelist* filelist) {
+       int r;
+
+       // Stack-smashing Protector
+       r = pakfire_build_post_check_stack_smashing_protection(build, filelist);
+       if (r)
+               return r;
+
+       return 0;
 }
 
 static int pakfire_build_run_post_build_checks(struct pakfire_build* build) {
@@ -1174,6 +1210,11 @@ static int pakfire_build_run_post_build_checks(struct pakfire_build* build) {
        if (r)
                goto ERROR;
 
+       // Check hardening
+       r = pakfire_build_post_check_hardening(build, filelist);
+       if (r)
+               goto ERROR;
+
 ERROR:
        if (filelist)
                pakfire_filelist_unref(filelist);
index d1cedb9065e00d67540355bd49b240cdbeb34e6b..a0ed895dd27ed4fa3230d7d203e72e2e3368eb47 100644 (file)
@@ -1383,3 +1383,110 @@ PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* p
                        return -1;
        }
 }
+
+/*
+       ELF Stuff
+*/
+
+static int pakfire_file_open_elf(struct pakfire_file* file,
+               int (*callback)(struct pakfire_file* file, Elf* elf, void* data), void* data) {
+       FILE* f = NULL;
+       Elf* elf = NULL;
+       int r;
+
+       // Don't run this for non-ELF files
+       if (!pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Setup libelf
+       r = setup_libelf(file->pakfire);
+       if (r)
+               return r;
+
+       // Open the file
+       f = fopen(file->abspath, "r");
+       if (!f) {
+               ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
+               return 1;
+       }
+
+       // Parse the ELF header
+       elf = elf_begin(fileno(f), ELF_C_READ, NULL);
+       if (!elf) {
+               ERROR(file->pakfire, "Could not open ELF file: %s\n", elf_errmsg(-1));
+               r = 1;
+               goto ERROR;
+       }
+
+       // Check if this is an ELF file
+       switch (elf_kind(elf)) {
+               case ELF_K_ELF:
+                       break;
+
+               default:
+                       ERROR(file->pakfire, "%s is not an ELF object\n", file->path);
+                       r = 1;
+                       goto ERROR;
+       }
+
+       // Call the callback
+       r = callback(file, elf, data);
+
+ERROR:
+       if (elf)
+               elf_end(elf);
+       if (f)
+               fclose(f);
+
+       return r;
+}
+
+static int __pakfire_file_has_stack_smashing_protection(
+               struct pakfire_file* file, Elf* elf, void* data) {
+       Elf_Scn* section = NULL;
+       GElf_Shdr section_header;
+       Elf_Data* elf_data = NULL;
+       GElf_Sym symbol;
+       const char* name = NULL;
+
+       // Walk through all sections
+       for (;;) {
+               section = elf_nextscn(elf, section);
+               if (!section)
+                       return 0;
+
+               // Fetch the section header
+               gelf_getshdr(section, &section_header);
+
+               // Break if we found the symbol table
+               if (section_header.sh_type == SHT_SYMTAB)
+                       break;
+       }
+
+       // Fetch a pointer to the section data
+       elf_data = elf_getdata(section, NULL);
+
+       // Walk through all symbols
+       for (unsigned int i = 0; i < section_header.sh_size / section_header.sh_entsize; i++) {
+               gelf_getsym(elf_data, i, &symbol);
+
+               // Fetch the symbol name
+               name = elf_strptr(elf, section_header.sh_link, symbol.st_name);
+
+               // Skip empty section names
+               if (!name || !*name)
+                       continue;
+
+               // Check if there is a symbol called "__stack_chk_fail"
+               if (pakfire_string_startswith(name, "__stack_chk_fail"))
+                       return 1;
+       }
+
+       return 0;
+}
+
+int pakfire_file_has_stack_smashing_protection(struct pakfire_file* file) {
+       return pakfire_file_open_elf(file, __pakfire_file_has_stack_smashing_protection, NULL);
+}
index dc26fa84f1032d25ce56201e05d02a99cd8380e3..ae10cd2cbe8fcb5bc59ed70b27c88e0ed51ab05b 100644 (file)
@@ -135,6 +135,11 @@ int pakfire_file_matches_class(struct pakfire_file* file, const int class);
 
 int pakfire_file_verify(struct pakfire_file* file, int* status);
 
+/*
+       Hardening Checks
+*/
+int pakfire_file_has_stack_smashing_protection(struct pakfire_file* file);
+
 #endif
 
 #endif /* PAKFIRE_FILE_H */
index 50bb6c31dbe9c9868c2b2d93dfbb6d9ec217bce3..fe392ea8f429d722b354b4fa6627a290848b2cde 100644 (file)
@@ -33,7 +33,6 @@ main() {
                return 1
        fi
 
-       local missing_ssp=()
        local no_pie=()
        local exec_stack=()
        local not_relro=()
@@ -58,11 +57,6 @@ main() {
                        continue
                fi
 
-               # Does this file have stack smashing protection enabled?
-               if ! readelf -s "${file}" 2>/dev/null | grep -q "__stack_chk_fail"; then
-                       missing_ssp+=( "${file}" )
-               fi
-
                # Is this file built with -fPIC?
                if readelf -h "${file}" 2>/dev/null | grep -qE "Type:[[:space:]]*EXEC"; then
                        no_pie+=( "${file}" )
@@ -90,16 +84,6 @@ main() {
 
        local r=0
 
-       # Log files without SSP
-       if [ "${#missing_ssp[@]}" -gt 0 ]; then
-               error "The following files do not have stack-smashing protection enabled:"
-               for file in ${missing_ssp[@]}; do
-                       error "  ${file/${buildroot}/}"
-               done
-
-               r=1
-       fi
-
        # Log files without PIE
        if [ "${#no_pie[@]}" -gt 0 ]; then
                error "The following files have not been compiled as place-independent executables:"