]> git.ipfire.org Git - pakfire.git/commitdiff
linter: Read the payload into memory
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 24 Oct 2024 16:52:02 +0000 (16:52 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 24 Oct 2024 16:52:02 +0000 (16:52 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/file.c
src/libpakfire/include/pakfire/file.h
src/libpakfire/linter.c

index c162fa3b9b78125e4514e3d27cec587c2fc8766f..05c84181f12174c47882cfc177172b62e789e981 100644 (file)
@@ -993,6 +993,20 @@ PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t tim
        archive_entry_set_mtime(file->entry, time, 0);
 }
 
+int pakfire_file_has_payload(struct pakfire_file* file) {
+       // File must be a regular file
+       switch (pakfire_file_get_type(file)) {
+               case S_IFREG:
+                       break;
+
+               default:
+                       return 0;
+       }
+
+       // File must be larger than zero
+       return pakfire_file_get_size(file) > 0;
+}
+
 PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
                struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
 
index a175c91ff07912df373f20b5f782978ed124deb3..468fb865735d90380b97f51e8d9b07c62ff4df2a 100644 (file)
@@ -132,6 +132,7 @@ enum pakfire_file_classes {
        PAKFIRE_FILE_RUNTIME_LINKER  = (1 << 14),
 };
 
+int pakfire_file_has_payload(struct pakfire_file* file);
 
 int pakfire_file_read(struct pakfire_file* file, struct archive* reader, const char* path);
 
index 99119b4ef5def47d3857c80aac2f417ce6e8457e..3f033ae1540f35cf4475c227f146df318646fc58 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <sys/queue.h>
 
 // libarchive
@@ -218,6 +219,107 @@ void pakfire_linter_set_result_callback(struct pakfire_linter* linter,
        linter->result_data     = data;
 }
 
+static int pakfire_linter_read_file(
+               struct pakfire_linter* linter, struct pakfire_file* file, struct archive* a) {
+       int fd = -EBADF;
+       int r;
+
+       // Fetch path
+       const char* path = pakfire_file_get_path(file);
+
+       // Allocate a new buffer
+       fd = memfd_create(path, MFD_CLOEXEC);
+       if (fd < 0) {
+               CTX_ERROR(linter->ctx, "memfd_create() failed: %m\n");
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Fetch file size
+       size_t size = pakfire_file_get_size(file);
+
+       // Tell the kernel how large the file would be
+       r = ftruncate(fd, size);
+       if (r < 0) {
+               CTX_ERROR(linter->ctx, "fallocate() failed: %m\n");
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Read the payload into the file descriptor
+       r = archive_read_data_into_fd(a, fd);
+       if (r) {
+               CTX_ERROR(linter->ctx, "Could not read %s: %s\n", path, archive_error_string(a));
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Check how much data we have read
+       off_t offset = lseek(fd, 0, SEEK_CUR);
+       if (offset < 0) {
+               CTX_ERROR(linter->ctx, "lseek() failed: %m\n");
+               r = -errno;
+               goto ERROR;
+       }
+
+       CTX_DEBUG(linter->ctx, "Read %jd byte(s)\n", offset);
+
+       // Check if we didn't read too little data
+       if ((size_t)offset < size) {
+               r = pakfire_linter_error(linter, "%s is actually smaller than %zu byte(s)", path, size);
+               if (r < 0)
+                       goto ERROR;
+
+       // Check if we have not read more data
+       } else if ((size_t)offset > size) {
+               r = pakfire_linter_error(linter, "/%s is actually larger than %zu byte(s)", path, size);
+               if (r < 0)
+                       goto ERROR;
+       }
+
+       // Rewind
+       offset = lseek(fd, 0, SEEK_SET);
+       if (offset) {
+               CTX_ERROR(linter->ctx, "Could not rewind: %m\n");
+               r = -errno;
+               goto ERROR;
+       }
+
+       return fd;
+
+ERROR:
+       if (fd >= 0)
+               close(fd);
+
+       return r;
+}
+
+static int pakfire_linter_payload(
+               struct pakfire_linter* linter, struct pakfire_file* file, struct archive* a) {
+       int fd = -EBADF;
+       int r;
+
+       // Fetch path
+       const char* path = pakfire_file_get_path(file);
+
+       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;
+               goto ERROR;
+       }
+
+       r = 0;
+
+ERROR:
+       if (fd >= 0)
+               close(fd);
+
+       return r;
+}
+
 static int pakfire_linter_name(struct pakfire_linter* linter) {
        int r;
 
@@ -289,7 +391,7 @@ static int pakfire_linter_lint_fhs(
        return 0;
 }
 
-static int pakfire_linter_payload(struct pakfire_archive* archive,
+static int pakfire_linter_file(struct pakfire_archive* archive,
                struct archive* a, struct archive_entry* e, void* data) {
        struct pakfire_linter* linter = data;
        struct pakfire_file* file = NULL;
@@ -309,6 +411,13 @@ static int pakfire_linter_payload(struct pakfire_archive* archive,
                         goto ERROR;
        }
 
+       // Lint the payload for regular files
+       if (pakfire_file_has_payload(file)) {
+               r = pakfire_linter_payload(linter, file, a);
+               if (r < 0)
+                       goto ERROR;
+       }
+
 ERROR:
        if (file)
                pakfire_file_unref(file);
@@ -325,7 +434,7 @@ int pakfire_linter_lint(struct pakfire_linter* linter) {
                return r;
 
        // Lint the payload
-       r = pakfire_archive_walk_payload(linter->archive, pakfire_linter_payload, linter);
+       r = pakfire_archive_walk_payload(linter->archive, pakfire_linter_file, linter);
        if (r < 0)
                return r;