]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
file: Check if ELF files have an executable stack
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 7 Mar 2023 11:40:42 +0000 (11:40 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Mar 2023 13:44:41 +0000 (13:44 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/file.c
src/libpakfire/include/pakfire/file.h
src/scripts/check-hardening

index e1922dcb67e6e9f37312f2644d55cc69158e05aa..0d3ddb6ba0b4868e5bcd4fed2ec59592a6fbef7b 100644 (file)
@@ -1579,6 +1579,57 @@ static int pakfire_file_hardening_check_pie(struct pakfire_file* file) {
        return pakfire_file_open_elf(file, __pakfire_file_hardening_check_pie, NULL);
 }
 
+static int __pakfire_file_hardening_check_execstack(
+               struct pakfire_file* file, Elf* elf, void* data) {
+       GElf_Phdr phdr;
+       int r;
+
+       size_t phnum = 0;
+
+       // Fetch the total numbers of program headers
+       r = elf_getphdrnum(elf, &phnum);
+       if (r) {
+               ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
+                       elf_errmsg(-1));
+               return 1;
+       }
+
+       // Walk through all program headers
+       for (unsigned int i = 0; i < phnum; i++) {
+               if (!gelf_getphdr(elf, i, &phdr)) {
+                       ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
+                       return 1;
+               }
+
+               switch (phdr.p_type) {
+                       case PT_GNU_STACK:
+                               DEBUG(file->pakfire,
+                                       "%s: GNU_STACK flags: %c%c%c\n",
+                                       file->path,
+                                       (phdr.p_flags & PF_R) ? 'R' : '-',
+                                       (phdr.p_flags & PF_W) ? 'W' : '-',
+                                       (phdr.p_flags & PF_X) ? 'X' : '-'
+                               );
+
+                               // The stack cannot be writable and executable
+                               if ((phdr.p_flags & PF_W) && (phdr.p_flags & PF_X))
+                                       file->hardening_issues |= PAKFIRE_FILE_EXECSTACK;
+
+                               // Done
+                               return 0;
+
+                       default:
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+static int pakfire_file_hardening_check_execstack(struct pakfire_file* file) {
+       return pakfire_file_open_elf(file, __pakfire_file_hardening_check_execstack, NULL);
+}
+
 int pakfire_file_check_hardening(struct pakfire_file* file, int* issues) {
        int r;
 
@@ -1594,6 +1645,11 @@ int pakfire_file_check_hardening(struct pakfire_file* file, int* issues) {
                if (r)
                        return r;
 
+               // Check for executable stacks
+               r = pakfire_file_hardening_check_execstack(file);
+               if (r)
+                       return r;
+
                // All checks done
                file->hardening_check_done = 1;
        }
index 206d3d46e0f48fbf672344e7ba9cf41890f019d5..9b8a294022a6f9e7d6fc5d4628133faef5b66414 100644 (file)
@@ -157,6 +157,7 @@ int pakfire_file_verify(struct pakfire_file* file, int* status);
 enum pakfire_file_hardening_flags {
        PAKFIRE_FILE_NO_SSP          = (1 << 0),
        PAKFIRE_FILE_NO_PIE          = (1 << 1),
+       PAKFIRE_FILE_EXECSTACK       = (1 << 2),
 };
 
 int pakfire_file_check_hardening(struct pakfire_file* file, int* issues);
index 2db5aa7eadbef0983f70daacb8e3224b06fe8ea3..b37d62c2e7a44aaa571040ec5e05981399805f3f 100644 (file)
@@ -33,7 +33,6 @@ main() {
                return 1
        fi
 
-       local exec_stack=()
        local not_relro=()
        local partly_relro=()
 
@@ -56,11 +55,6 @@ main() {
                        continue
                fi
 
-               # Does this file have an executable stack?
-               if readelf -l "${file}" 2>/dev/null | grep -A1 "GNU_STACK" | grep -q "RWE"; then
-                       exec_stack+=( "${file}" )
-               fi
-
                # Perform more checks for shared objects (i.e. libraries)
                if file "${file}" | grep -q "shared object"; then
                        # Is this file partly RELRO?
@@ -78,16 +72,6 @@ main() {
 
        local r=0
 
-       # Log files with an executable stack
-       if [ "${#exec_stack[@]}" -gt 0 ]; then
-               error "The following files have an executable stack:"
-               for file in ${exec_stack[@]}; do
-                       error "  ${file/${buildroot}/}"
-               done
-
-               r=1
-       fi
-
        # Log files which are not RELRO
        if [ "${#not_relro[@]}" -gt 0 ]; then
                error "The following files are not fully RELRO:"