]> git.ipfire.org Git - pakfire.git/commitdiff
ELF: Move RUNPATH check
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 2 Jan 2025 15:43:01 +0000 (15:43 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 2 Jan 2025 15:43:01 +0000 (15:43 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/elf.c
src/libpakfire/include/pakfire/elf.h
src/libpakfire/include/pakfire/string.h
src/libpakfire/linter-file.c

index c5f70e96680ab6500803ed153cbf024234731af1..1a495c5ecca94a1aef83a2a83d2b26eefdc28c4a 100644 (file)
@@ -697,6 +697,64 @@ int pakfire_elf_has_cf_protection(struct pakfire_elf* self) {
        return pakfire_elf_foreach_section(self, SHT_NOTE, pakfire_elf_check_cf_protection);
 }
 
+static int pakfire_elf_check_runpath(struct pakfire_elf* self,
+               const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
+       const char* runpath = NULL;
+       const char* value = NULL;
+       char buffer[PATH_MAX];
+       char* p = NULL;
+       int r;
+
+       // The result
+       char*** runpaths = data;
+
+       switch (dyn->d_tag) {
+               case DT_RUNPATH:
+               case DT_RPATH:
+                       // Fetch the value
+                       value = elf_strptr(self->elf, shdr->sh_link, dyn->d_un.d_val);
+                       if (!value)
+                               return 1;
+
+                       DEBUG(self->ctx, "%s has a RUNPATH: %s\n", self->path, value);
+
+                       // Copy the value into a buffer we can modify
+                       r = pakfire_string_set(buffer, value);
+                       if (r < 0)
+                               goto ERROR;
+
+                       // Split the value by :
+                       runpath = strtok_r(buffer, ":", &p);
+
+                       // Iterate over all elements
+                       while (runpath) {
+                               r = pakfire_strings_append(runpaths, runpath);
+                               if (r < 0)
+                                       goto ERROR;
+
+                               // Move on to the next RUNPATH
+                               runpath = strtok_r(NULL, ":", &p);
+                       }
+
+               default:
+                       break;
+       }
+
+       return 0;
+
+ERROR:
+       if (*runpaths) {
+               pakfire_strings_free(*runpaths);
+               *runpaths = NULL;
+       }
+
+       return r;
+}
+
+int pakfire_elf_has_runpaths(struct pakfire_elf* self, char*** runpaths) {
+       return pakfire_elf_dyn_walk(self, pakfire_elf_check_runpath, runpaths);
+}
+
 int pakfire_elf_is_stripped(struct pakfire_elf* self) {
        Elf_Scn* symtab = NULL;
 
index 9f6261e21cb15c8d199146c2fd6d7a028cf27226..02de846d1f50eaf4d5c55951936a19a2249942ec 100644 (file)
@@ -50,6 +50,7 @@ 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_has_cf_protection(struct pakfire_elf* self);
+int pakfire_elf_has_runpaths(struct pakfire_elf* self, char*** runpaths);
 int pakfire_elf_is_stripped(struct pakfire_elf* self);
 
 // Return bitmap for pakfire_elf_has_cf_protection()
index e3974e90aae7d2e2a9584b4c13e41b4bb74e0bc5..809bb30ec5d881416990c0306024cc9d7deceae7 100644 (file)
@@ -80,6 +80,20 @@ static inline int pakfire_string_contains_whitespace(const char* s) {
        Cleanup Stuff
 */
 
+inline size_t pakfire_strings_length(char** array) {
+       size_t length = 0;
+
+       // If we have received NULL, we will return zero
+       if (!array)
+               return 0;
+
+       // Count all elements
+       for (char** s = array; *s; s++)
+               length++;
+
+       return length;
+}
+
 inline void pakfire_strings_free(char** array) {
        for (char** s = array; *s; s++)
                free(*s);
@@ -87,6 +101,30 @@ inline void pakfire_strings_free(char** array) {
        free(array);
 }
 
+inline int pakfire_strings_append(char*** array, const char* s) {
+       if (!array)
+               return -EINVAL;
+
+       // Fetch the length
+       size_t length = pakfire_strings_length(*array);
+
+       // Resize the array
+       *array = reallocarray(*array, length + 2, sizeof(**array));
+       if (!*array)
+               return -errno;
+
+       // Copy the string
+       char* p = *array[length++] = strdup(s);
+       if (!p)
+               return -errno;
+
+       // Terminate the array
+       *array[length] = NULL;
+
+       // Return the total length of the array
+       return length;
+}
+
 #define TIME_STRING_MAX 32
 
 #define pakfire_format_size(dst, value) \
index f8ff6a501151036f0099da10ed90d13f2d177d97..340823080dab8bd2ff9383d83ed2f01509b82a8d 100644 (file)
@@ -346,71 +346,6 @@ static int pakfire_linter_check_script_interpreter(struct pakfire_linter_file* l
        return 0;
 }
 
-static int pakfire_linter_file_get_elf_section(struct pakfire_linter_file* lfile,
-               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(lfile->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_elf_dyn_walk(struct pakfire_linter_file* lfile,
-               int (*callback)(struct pakfire_linter_file* lfile,
-                       const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data), 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_linter_file_get_elf_section(lfile, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
-       if (r) {
-               DEBUG(lfile->ctx, "%s does not have a dynamic section\n", lfile->path);
-               return 0;
-       }
-
-       // 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(lfile, &shdr, &dyn, data);
-               if (r)
-                       return r;
-       }
-
-       return 0;
-}
-
 static int pakfire_linter_file_check_pie(struct pakfire_linter_file* lfile) {
        if (!pakfire_elf_is_pie(lfile->_elf))
                return pakfire_linter_file_error(lfile, "Missing PIE");
@@ -465,74 +400,40 @@ static int pakfire_linter_file_check_relro(struct pakfire_linter_file* lfile) {
        return pakfire_linter_file_error(lfile, "Is not RELRO");
 }
 
-/*
-       RPATH/RUNPATH
-*/
-static int __pakfire_linter_file_process_runpath(struct pakfire_linter_file* lfile,
-               const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
-       const char* value = NULL;
-       const char* runpath = NULL;
-       char buffer[PATH_MAX];
-       char* p = NULL;
+static int pakfire_linter_file_check_runpath(struct pakfire_linter_file* lfile) {
+       char** runpaths = NULL;
        int r;
 
-       switch (dyn->d_tag) {
-               case DT_RUNPATH:
-               case DT_RPATH:
-                       // Fetch the value
-                       value = elf_strptr(lfile->elf, shdr->sh_link, dyn->d_un.d_val);
-                       if (!value)
-                               return 1;
-
-                       DEBUG(lfile->ctx, "%s has a RUNPATH: %s\n", lfile->path, value);
-
-                       // Copy the value into a buffer we can modify
-                       r = pakfire_string_set(buffer, value);
-                       if (r < 0)
-                               return r;
-
-                       // Split the value by :
-                       runpath = strtok_r(buffer, ":", &p);
-
-                       // Iterate over all elements
-                       while (runpath) {
-                               DEBUG(lfile->ctx, "Checking RUNPATH %s\n", runpath);
-
-                               // We do not allow any relative RUNPATHs
-                               if (pakfire_path_match(runpath, "**/../**"))
-                                       goto RUNPATH_DENIED;
-
-                               // We allow /usr/lib64 as libtool seems to link it in quite a lot
-                               if (pakfire_path_match("/usr/lib64", runpath))
-                                       goto RUNPATH_PERMITTED;
+       // Fetch any runpaths
+       r = pakfire_elf_has_runpaths(lfile->_elf, &runpaths);
+       if (r < 0)
+               goto ERROR;
 
-                               // We allow any subdirectories of /usr/lib64
-                               if (pakfire_path_match( "/usr/lib64/**", runpath))
-                                       goto RUNPATH_PERMITTED;
+       // Report any invalid runpaths
+       if (runpaths) {
+               for (char** runpath = runpaths; *runpath; runpath++) {
+                       DEBUG(lfile->ctx, "Checking RUNPATH %s\n", *runpath);
 
-RUNPATH_DENIED:
-                               // If we make it here, this check has failed
-                               r = pakfire_linter_file_error(lfile, "Has illegal RPATH/RUNPATH %s", runpath);
-                               if (r < 0)
-                                       return r;
+                       // We allow /usr/lib64 as libtool seems to link it in quite a lot
+                       if (pakfire_path_match("/usr/lib64", *runpath))
+                               continue;
 
-                               break;
+                       // We allow any subdirectories of /usr/lib64
+                       if (pakfire_path_match( "/usr/lib64/**", *runpath))
+                               continue;
 
-RUNPATH_PERMITTED:
-                               // Move on to the next RUNPATH
-                               runpath = strtok_r(NULL, ":", &p);
-                       }
-
-               default:
-                       break;
+                       // This seems to be an illegal runpath
+                       r = pakfire_linter_file_error(lfile, "Has illegal RPATH/RUNPATH %s", *runpath);
+                       if (r < 0)
+                               goto ERROR;
+               }
        }
 
-       return 0;
-}
+ERROR:
+       if (runpaths)
+               pakfire_strings_free(runpaths);
 
-static int pakfire_linter_file_check_runpath(struct pakfire_linter_file* lfile) {
-       return pakfire_linter_file_elf_dyn_walk(
-               lfile, __pakfire_linter_file_process_runpath, NULL);
+       return r;
 }
 
 static int pakfire_linter_file_check_cf_protection(struct pakfire_linter_file* lfile) {