From: Lennart Poettering Date: Thu, 24 Aug 2023 13:41:09 +0000 (+0200) Subject: shared: port bootspec.c over to new common PE parser X-Git-Tag: v255-rc1~620^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8bc9d1aa9f34c2dd5143e5138dc21dd4b480c0f6;p=thirdparty%2Fsystemd.git shared: port bootspec.c over to new common PE parser --- diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 8d16b36be15..d23eab38df1 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -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(§ions[i].PointerToRawData); - size = unaligned_read_le32(§ions[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, §ions); + 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);