]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared: port bootspec.c over to new common PE parser
authorLennart Poettering <lennart@poettering.net>
Thu, 24 Aug 2023 13:41:09 +0000 (15:41 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 29 Aug 2023 09:25:52 +0000 (11:25 +0200)
src/shared/bootspec.c

index 8d16b36be156dab35432a7c6ba0ef25906cb7514..d23eab38df11aa707b59fffcd163b890e85f0ddc 100644 (file)
@@ -15,7 +15,7 @@
 #include "fileio.h"
 #include "find-esp.h"
 #include "path-util.h"
-#include "pe-header.h"
+#include "pe-binary.h"
 #include "pretty-print.h"
 #include "recurse-dir.h"
 #include "sort-util.h"
@@ -757,92 +757,36 @@ static int find_sections(
                 char **ret_osrelease,
                 char **ret_cmdline) {
 
-        _cleanup_free_ struct PeSectionHeader *sections = NULL;
-        _cleanup_free_ char *osrelease = NULL, *cmdline = NULL;
-        ssize_t n;
-
-        struct DosFileHeader dos;
-        n = pread(fd, &dos, sizeof(dos), 0);
-        if (n < 0)
-                return log_warning_errno(errno, "%s: Failed to read DOS header, ignoring: %m", path);
-        if (n != sizeof(dos))
-                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "%s: Short read while reading DOS header, ignoring.", path);
-
-        if (dos.Magic[0] != 'M' || dos.Magic[1] != 'Z')
-                return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: DOS executable magic missing, ignoring.", path);
-
-        uint64_t start = unaligned_read_le32(&dos.ExeHeader);
-
-        struct PeHeader pe;
-        n = pread(fd, &pe, sizeof(pe), start);
-        if (n < 0)
-                return log_warning_errno(errno, "%s: Failed to read PE header, ignoring: %m", path);
-        if (n != sizeof(pe))
-                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "%s: Short read while reading PE header, ignoring.", path);
-
-        if (pe.Magic[0] != 'P' || pe.Magic[1] != 'E' || pe.Magic[2] != 0 || pe.Magic[3] != 0)
-                return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: PE executable magic missing, ignoring.", path);
-
-        size_t n_sections = unaligned_read_le16(&pe.FileHeader.NumberOfSections);
-        if (n_sections > 96)
-                return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: PE header has too many sections, ignoring.", path);
-
-        sections = new(struct PeSectionHeader, n_sections);
-        if (!sections)
-                return log_oom();
-
-        n = pread(fd, sections,
-                  n_sections * sizeof(struct PeSectionHeader),
-                  start + sizeof(pe) + unaligned_read_le16(&pe.FileHeader.SizeOfOptionalHeader));
-        if (n < 0)
-                return log_warning_errno(errno, "%s: Failed to read section data, ignoring: %m", path);
-        if ((size_t) n != n_sections * sizeof(struct PeSectionHeader))
-                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "%s: Short read while reading sections, ignoring.", path);
-
-        for (size_t i = 0; i < n_sections; i++) {
-                _cleanup_free_ char *k = NULL;
-                uint32_t offset, size;
-                char **b;
-
-                if (strneq((char*) sections[i].Name, ".osrel", sizeof(sections[i].Name)))
-                        b = &osrelease;
-                else if (strneq((char*) sections[i].Name, ".cmdline", sizeof(sections[i].Name)))
-                        b = &cmdline;
-                else
-                        continue;
-
-                if (*b)
-                        return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: Duplicate section %s, ignoring.", path, sections[i].Name);
-
-                offset = unaligned_read_le32(&sections[i].PointerToRawData);
-                size = unaligned_read_le32(&sections[i].VirtualSize);
+        _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
+        _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
+        _cleanup_free_ char *osrel = NULL, *cmdline = NULL;
+        _cleanup_free_ PeHeader *pe_header = NULL;
+        int r;
 
-                if (size > PE_SECTION_SIZE_MAX)
-                        return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: Section %s too large, ignoring.", path, sections[i].Name);
+        assert(fd >= 0);
+        assert(path);
 
-                k = new(char, size+1);
-                if (!k)
-                        return log_oom();
+        r = pe_load_headers(fd, &dos_header, &pe_header);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse PE file '%s': %m", path);
 
-                n = pread(fd, k, size, offset);
-                if (n < 0)
-                        return log_warning_errno(errno, "%s: Failed to read section payload, ignoring: %m", path);
-                if ((size_t) n != size)
-                        return log_warning_errno(SYNTHETIC_ERRNO(EIO), "%s: Short read while reading section payload, ignoring:", path);
+        r = pe_load_sections(fd, dos_header, pe_header, &sections);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse PE sections of '%s': %m", path);
 
-                /* Allow one trailing NUL byte, but nothing more. */
-                if (size > 0 && memchr(k, 0, size - 1))
-                        return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: Section contains embedded NUL byte, ignoring.", path);
+        if (!pe_is_uki(pe_header, sections))
+                return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Parsed PE file '%s' is not a UKI.", path);
 
-                k[size] = 0;
-                *b = TAKE_PTR(k);
-        }
+        r = pe_read_section_data(fd, pe_header, sections, ".osrel", PE_SECTION_SIZE_MAX, (void**) &osrel, NULL);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to read .osrel section of '%s': %m", path);
 
-        if (!osrelease)
-                return log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "%s: Image lacks .osrel section, ignoring.", path);
+        r = pe_read_section_data(fd, pe_header, sections, ".cmdline", PE_SECTION_SIZE_MAX, (void**) &cmdline, NULL);
+        if (r < 0 && r != -ENXIO) /* cmdline is optional */
+                return log_warning_errno(r, "Failed to read .cmdline section of '%s': %m", path);
 
         if (ret_osrelease)
-                *ret_osrelease = TAKE_PTR(osrelease);
+                *ret_osrelease = TAKE_PTR(osrel);
         if (ret_cmdline)
                 *ret_cmdline = TAKE_PTR(cmdline);