]> git.ipfire.org Git - pakfire.git/commitdiff
ELF: Base the SSP check on the dynamic section
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 2 Jan 2025 16:19:40 +0000 (16:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 2 Jan 2025 16:19:40 +0000 (16:19 +0000)
This works even if we have fully stripped the binary.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/elf.c

index 1a495c5ecca94a1aef83a2a83d2b26eefdc28c4a..d0faadb507f3b0ccabe2150d6b2c04ad590173e1 100644 (file)
@@ -261,9 +261,20 @@ const char* pakfire_elf_debuglink(struct pakfire_elf* self) {
 }
 
 static int pakfire_elf_get_section(struct pakfire_elf* self,
-               const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
+               const Elf64_Word type, const char* name, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
+       const char* sname = NULL;
        Elf_Scn* s = NULL;
        GElf_Shdr shdr;
+       int r;
+
+       size_t shstrndx = 0;
+
+       // Find the strings
+       r = elf_getshdrstrndx(self->elf, &shstrndx);
+       if (r < 0) {
+               ERROR(self->ctx, "elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1));
+               return r;
+       }
 
        // Walk through all sections
        for (;;) {
@@ -276,6 +287,18 @@ static int pakfire_elf_get_section(struct pakfire_elf* self,
 
                // Return any matching sections
                if (shdr.sh_type == type) {
+                       // If we have a name, check it too
+                       if (name) {
+                               sname = elf_strptr(self->elf, shstrndx, shdr.sh_name);
+                               if (!sname)
+                                       continue;
+
+                               // Skip if the name does not match
+                               if (!pakfire_string_equals(name, sname))
+                                       continue;
+                       }
+
+                       // Return a pointer to the section
                        *section = s;
 
                        // Send header if requested
@@ -341,7 +364,7 @@ static int pakfire_elf_dyn_walk(struct pakfire_elf* self,
        int r;
 
        // Find the dynamic linking information
-       r = pakfire_elf_get_section(self, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
+       r = pakfire_elf_get_section(self, SHT_DYNAMIC, NULL, &dynamic, &shdr, &elf_data);
        if (r) {
                DEBUG(self->ctx, "%s does not have a dynamic section\n", self->path);
                return r;
@@ -377,17 +400,30 @@ int pakfire_elf_is_pie(struct pakfire_elf* self) {
 }
 
 int pakfire_elf_has_ssp(struct pakfire_elf* self) {
-       const char* name = NULL;
-       Elf_Scn* symtab = NULL;
-       GElf_Shdr shdr;
-       Elf_Data* data = NULL;
-       GElf_Sym symbol;
+       GElf_Sym symbol = {};
        int r;
 
-       // Fetch the symbol table
-       r = pakfire_elf_get_section(self, SHT_SYMTAB, &symtab, &shdr, &data);
+       // .dynsym
+       Elf_Scn* dynsym = NULL;
+       GElf_Shdr symhdr = {};
+       Elf_Data* symdata = NULL;
+
+       // .dynstr
+       Elf_Scn* dynstr = NULL;
+       GElf_Shdr strhdr = {};
+       Elf_Data* strdata = NULL;
+
+       // Fetch .dynsym
+       r = pakfire_elf_get_section(self, SHT_DYNSYM, NULL, &dynsym, &symhdr, &symdata);
+       if (r) {
+               DEBUG(self->ctx, "%s has no .dynsym section\n", self->path);
+               return 0;
+       }
+
+       // Fetch .dynstr
+       r = pakfire_elf_get_section(self, SHT_STRTAB, ".dynstr", &dynstr, &strhdr, &strdata);
        if (r) {
-               DEBUG(self->ctx, "%s has no symbol table\n", self->path);
+               DEBUG(self->ctx, "%s has no .dynstr section\n", self->path);
                return 0;
        }
 
@@ -395,11 +431,11 @@ int pakfire_elf_has_ssp(struct pakfire_elf* self) {
        size_t counter = 0;
 
        // Walk through all symbols
-       for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
-               gelf_getsym(data, i, &symbol);
+       for (unsigned int i = 0; i < symhdr.sh_size / symhdr.sh_entsize; i++) {
+               gelf_getsym(symdata, i, &symbol);
 
                // Fetch the symbol name
-               name = elf_strptr(self->elf, shdr.sh_link, symbol.st_name);
+               const char* name = elf_strptr(self->elf, elf_ndxscn(dynstr), symbol.st_name);
 
                // Skip empty section names
                if (!name || !*name)
@@ -769,5 +805,5 @@ int pakfire_elf_is_stripped(struct pakfire_elf* self) {
        }
 
        // Fetch the symbol table
-       return pakfire_elf_get_section(self, SHT_SYMTAB, &symtab, NULL, NULL);
+       return pakfire_elf_get_section(self, SHT_SYMTAB, NULL, &symtab, NULL, NULL);
 }