]> git.ipfire.org Git - pakfire.git/commitdiff
linter: Try to lint some ELF stuff
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 25 Oct 2024 14:19:47 +0000 (14:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 25 Oct 2024 14:19:47 +0000 (14:19 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/linter.c

index ae796e027bbb746bfb7019cef9e7f0e84d1cbe7b..fd8e193b18c71d76df710bb32fdd0742e7eed35f 100644 (file)
@@ -28,6 +28,9 @@
 #include <archive.h>
 #include <archive_entry.h>
 
+// libelf
+#include <gelf.h>
+
 #include <pakfire/archive.h>
 #include <pakfire/fhs.h>
 #include <pakfire/file.h>
@@ -220,6 +223,154 @@ void pakfire_linter_set_result_callback(struct pakfire_linter* linter,
        linter->result_data     = data;
 }
 
+/*
+       ELF Stuff
+*/
+
+static int pakfire_linter_init_libelf(struct pakfire_linter* linter) {
+       // Initialize libelf
+       if (elf_version(EV_CURRENT) == EV_NONE) {
+               CTX_ERROR(linter->ctx, "Could not initialize libelf: %s\n", elf_errmsg(-1));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pakfire_linter_file_is_elf(
+               struct pakfire_linter* linter, struct pakfire_file* file) {
+       Elf* elf = NULL;
+       int r;
+
+       // Fetch the file descriptor
+       int fd = pakfire_file_get_fd(file);
+
+       // Initialize libelf
+       r = pakfire_linter_init_libelf(linter);
+       if (r < 0)
+               return r;
+
+       // Parse the ELF header
+       elf = elf_begin(fd, ELF_C_READ, NULL);
+       if (!elf) {
+               CTX_ERROR(linter->ctx, "Could not open ELF file: %s\n", elf_errmsg(-1));
+               r = -EINVAL;
+               goto ERROR;
+       }
+
+       switch (elf_kind(elf)) {
+               case ELF_K_ELF:
+                       r = 1;
+                       break;
+
+               // Ignore everything else
+               default:
+                       r = 0;
+                       break;
+       }
+
+ERROR:
+       if (elf)
+               elf_end(elf);
+
+       return r;
+}
+
+/*
+       A helper function that opens an ELF file and calls a callback.
+*/
+static int pakfire_linter_elf(struct pakfire_linter* linter, struct pakfire_file* file,
+               int (*callback)(struct pakfire_linter* linter, struct pakfire_file* file, Elf* elf, void* data),
+               void* data) {
+       Elf* elf = NULL;
+       int fd = -EBADF;
+       int r;
+
+       // Initialize libelf
+       r = pakfire_linter_init_libelf(linter);
+       if (r < 0)
+               return r;
+
+       // Fetch file descriptor
+       fd = pakfire_file_get_fd(file);
+       if (fd < 0)
+               return fd;
+
+       // Parse the ELF header
+       elf = elf_begin(fd, ELF_C_READ, NULL);
+       if (!elf) {
+               CTX_ERROR(linter->ctx, "Could not open ELF file: %s\n", elf_errmsg(-1));
+               r = -EINVAL;
+               goto ERROR;
+       }
+
+       // Check if this is an ELF file
+       switch (elf_kind(elf)) {
+               case ELF_K_ELF:
+                       break;
+
+               default:
+                       CTX_ERROR(linter->ctx, "%s is not an ELF object\n", pakfire_file_get_path(file));
+                       r = -EINVAL;
+                       goto ERROR;
+       }
+
+       // Call the callback
+       r = callback(linter, file, elf, data);
+
+ERROR:
+       if (elf)
+               elf_end(elf);
+
+       return r;
+}
+
+static int __pakfire_linter_get_elf_type(struct pakfire_linter* linter,
+               struct pakfire_file* file, Elf* elf, void* data) {
+       GElf_Ehdr ehdr = {};
+
+       int* type = data;
+
+       // Fetch the ELF header
+       if (!gelf_getehdr(elf, &ehdr)) {
+               CTX_ERROR(linter->ctx, "Could not parse ELF header: %s\n", elf_errmsg(-1));
+               return -EINVAL;
+       }
+
+       // Store the type
+       *type = ehdr.e_type;
+
+       return 0;
+}
+
+static int pakfire_linter_get_elf_type(
+               struct pakfire_linter* linter, struct pakfire_file* file) {
+       int type = ET_NONE;
+       int r;
+
+       // Fetch the type
+       r = pakfire_linter_elf(linter, file, __pakfire_linter_get_elf_type, &type);
+       if (r < 0)
+               return r;
+
+       return type;
+}
+
+static int pakfire_linter_check_pie(
+               struct pakfire_linter* linter, struct pakfire_file* file) {
+       switch (pakfire_linter_get_elf_type(linter, file)) {
+               // Shared Object files are good
+               case ET_DYN:
+                       return 0;
+
+               // Everything else is bad
+               default:
+                       break;
+       }
+
+       return pakfire_linter_error(linter, "%s is not PIE", pakfire_file_get_path(file));
+}
+
 static int pakfire_linter_read_file(
                struct pakfire_linter* linter, struct pakfire_file* file, struct archive* a) {
        int fd = -EBADF;
@@ -295,7 +446,10 @@ static int pakfire_linter_read_file(
                goto ERROR;
        }
 
-       return fd;
+       // Store the file descriptor
+       r = pakfire_file_set_fd(file, fd);
+       if (r < 0)
+               goto ERROR;
 
 ERROR:
        if (fd >= 0)
@@ -306,7 +460,6 @@ ERROR:
 
 static int pakfire_linter_payload(
                struct pakfire_linter* linter, struct pakfire_file* file, struct archive* a) {
-       int fd = -EBADF;
        int r;
 
        // Fetch path
@@ -315,18 +468,21 @@ static int pakfire_linter_payload(
        CTX_DEBUG(linter->ctx, "Checking payload of %s\n", path);
 
        // Read the file
-       fd = pakfire_linter_read_file(linter, file, a);
-       if (fd < 0) {
-               r = fd;
+       r = pakfire_linter_read_file(linter, file, a);
+       if (r < 0)
                goto ERROR;
-       }
 
-       r = 0;
+       // Check ELF files
+       if (pakfire_linter_file_is_elf(linter, file)) {
+               // Check PIE
+               r = pakfire_linter_check_pie(linter, file);
+               if (r < 0)
+                       goto ERROR;
 
-ERROR:
-       if (fd >= 0)
-               close(fd);
+               // TODO
+       }
 
+ERROR:
        return r;
 }
 
@@ -350,6 +506,11 @@ static int pakfire_linter_name(struct pakfire_linter* linter) {
        return 0;
 }
 
+static int pakfire_linter_lint_source(
+               struct pakfire_linter* linter, struct pakfire_file* file) {
+       return 0;
+}
+
 static int pakfire_linter_lint_fhs(
                struct pakfire_linter* linter, struct pakfire_file* file) {
        int r;
@@ -414,7 +575,14 @@ static int pakfire_linter_file(struct pakfire_archive* archive,
 
        CTX_DEBUG(linter->ctx, "Linting %s...\n", pakfire_file_get_path(file));
 
-       if (!pakfire_package_is_source(linter->pkg)) {
+       // Source Packages
+       if (pakfire_package_is_source(linter->pkg)) {
+               r = pakfire_linter_lint_source(linter, file);
+               if (r < 0)
+                       goto ERROR;
+
+       // Binary Packages
+       } else {
                // Checking against FHS
                r = pakfire_linter_lint_fhs(linter, file);
                if (r < 0)