]> git.ipfire.org Git - pakfire.git/commitdiff
file: Implement RPATH/RUNPATH check
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 18 Mar 2023 11:23:32 +0000 (11:23 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 18 Mar 2023 11:23:32 +0000 (11:23 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/file.c
src/libpakfire/include/pakfire/file.h

index b31f04747f5b3c0f03452007f99e02db8ec441e2..d8034b6abbbc1df398068e7b6732b1cf7c38f9bb 100644 (file)
@@ -656,6 +656,13 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) {
                        if (r < 0)
                                goto ERROR;
                }
+
+               // Has RUNPATH?
+               if (file->issues & PAKFIRE_FILE_HAS_RUNPATH) {
+                       r = asprintf(&buffer, "%s [HAS-RUNPATH]", buffer);
+                       if (r < 0)
+                               goto ERROR;
+               }
        }
 
        return buffer;
@@ -1737,6 +1744,42 @@ static int pakfire_file_get_elf_type(struct pakfire_file* file) {
        return type;
 }
 
+static int pakfire_file_elf_dyn_walk(struct pakfire_file* file, Elf* elf,
+               int (*callback)(struct pakfire_file* file, Elf64_Word key, const char* value, void* data),
+               void* data) {
+       Elf_Scn* dynamic = NULL;
+       GElf_Shdr shdr;
+       Elf_Data* elf_data = NULL;
+       int r;
+
+       // Find the dynamic linking information
+       r = pakfire_file_get_elf_section(file, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
+       if (r) {
+               ERROR(file->pakfire, "%s does not have a dynamic section\n", file->path);
+               return 1;
+       }
+
+       GElf_Dyn dyn;
+       const char* value = NULL;
+
+       // Walk through all entries...
+       for (unsigned int i = 0; ; i++)  {
+               // Fetch the next entry
+               if (!gelf_getdyn(elf_data, i, &dyn))
+                       break;
+
+               // Fetch the value
+               value = elf_strptr(elf, shdr.sh_link, dyn.d_un.d_val);
+
+               // Call the callback
+               r = callback(file, dyn.d_tag, value, data);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
 static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, void* data) {
        Elf_Scn* symtab = NULL;
        int r;
@@ -1941,6 +1984,67 @@ static int pakfire_file_check_relro(struct pakfire_file* file) {
        return pakfire_file_open_elf(file, __pakfire_file_check_partially_relro, NULL);
 }
 
+/*
+       RPATH/RUNPATH
+*/
+static int __pakfire_file_process_runpath(struct pakfire_file* file,
+               Elf64_Word key, const char* value, void* data) {
+       const char* runpath = NULL;
+       char buffer[PATH_MAX];
+       char* p = NULL;
+       int r;
+
+       switch (key) {
+               case DT_RUNPATH:
+               case DT_RPATH:
+                       DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", file->path, value);
+
+                       // Copy the value into a buffer we can modify
+                       r = pakfire_string_set(buffer, value);
+                       if (r)
+                               return r;
+
+                       // Split the value by :
+                       runpath = strtok_r(buffer, ":", &p);
+
+                       // Iterate over all elements
+                       while (runpath) {
+                               DEBUG(file->pakfire, "Checking RUNPATH %s\n", runpath);
+
+                               // We do not allow any relative RUNPATHs
+                               if (pakfire_path_match(runpath, "**/../**")) {
+                                       file->issues |= PAKFIRE_FILE_HAS_RUNPATH;
+                                       break;
+                               }
+
+                               /*
+                                       We allow some RUNPATHs where some software is loading some
+                                       modules as shared objects from a private directory in /usr/lib64.
+                               */
+                               if (!pakfire_path_match(runpath, "/usr/lib64")
+                                               && !pakfire_path_match(runpath, "/usr/lib64/**")) {
+                                       file->issues |= PAKFIRE_FILE_HAS_RUNPATH;
+                                       break;
+                               }
+
+                               // Move on to the next RUNPATH
+                               runpath = strtok_r(NULL, ":", &p);
+                       }
+
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+static int __pakfire_file_check_runpath(struct pakfire_file* file, Elf* elf, void* data) {
+       return pakfire_file_elf_dyn_walk(file, elf, __pakfire_file_process_runpath, data);
+}
+
+static int pakfire_file_check_runpath(struct pakfire_file* file) {
+       return pakfire_file_open_elf(file, __pakfire_file_check_runpath, NULL);
+}
 
 int pakfire_file_check(struct pakfire_file* file, int* issues) {
        int r;
@@ -1992,6 +2096,11 @@ int pakfire_file_check(struct pakfire_file* file, int* issues) {
                        r = pakfire_file_check_relro(file);
                        if (r)
                                return r;
+
+                       // Check for RUNPATH
+                       r = pakfire_file_check_runpath(file);
+                       if (r)
+                               return r;
                }
 
 DONE:
index 382c01c1f10498c8b9b5b4e998ef538ad31464cf..0308daf28314e2ffc03b2198f03b7297b35a663e 100644 (file)
@@ -182,6 +182,7 @@ enum pakfire_file_check_issues {
        PAKFIRE_FILE_MISSING_PIE        = (1 << 3),
        PAKFIRE_FILE_EXECSTACK          = (1 << 4),
        PAKFIRE_FILE_NO_PARTIALLY_RELRO = (1 << 5),
+       PAKFIRE_FILE_HAS_RUNPATH        = (1 << 6),
 };
 
 int pakfire_file_check(struct pakfire_file* file, int* issues);