]> git.ipfire.org Git - pakfire.git/commitdiff
ELF: Move RELRO check
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Jan 2025 17:56:45 +0000 (17:56 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Jan 2025 17:56:45 +0000 (17:56 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/elf.c
src/libpakfire/include/pakfire/elf.h
src/libpakfire/linter-file.c

index 9f69f6c573e52c48f05e83aec349e8b618975d25..268c2b3a55490adb50dd0cc35a25644c49c3d006 100644 (file)
@@ -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;
 
index f34e405e1cb964a98bbf950d6c733d9a1ec68b25..d36f52b48539ade4253d6059f8c2842af5cdc7e3 100644 (file)
@@ -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 */
index 3f416433722cb995dab67b363bd4e1e276865610..fb2f7ace55d7edcbb5d176c76f79ee19e2925969 100644 (file)
@@ -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");
 }