]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: Fix PE section parsing
authorJan Janssen <medhefgo@web.de>
Fri, 13 Aug 2021 16:55:32 +0000 (18:55 +0200)
committerJan Janssen <medhefgo@web.de>
Mon, 16 Aug 2021 08:49:12 +0000 (10:49 +0200)
We only need the PE header offset from the DOS header, not
its size. Previously, the section table could be cut off in the middle.

While we are at it, also modernize the remaining code.

src/basic/macro.h
src/boot/efi/boot.c
src/boot/efi/linux.h
src/boot/efi/measure.c
src/boot/efi/missing_efi.h
src/boot/efi/pe.c
src/boot/efi/pe.h
src/boot/efi/splash.c
src/boot/efi/stub.c
src/fundamental/macro-fundamental.h

index 645f93096f293a64bb272ecba34e916c74efa481..280f3028643ecdded3768cc229eceb03c54caaeb 100644 (file)
@@ -20,7 +20,6 @@
 #define _sentinel_ __attribute__((__sentinel__))
 #define _destructor_ __attribute__((__destructor__))
 #define _deprecated_ __attribute__((__deprecated__))
-#define _packed_ __attribute__((__packed__))
 #define _malloc_ __attribute__((__malloc__))
 #define _weak_ __attribute__((__weak__))
 #define _public_ __attribute__((__visibility__("default")))
index 638070d77a1e3c15eae57d717a5914da36c3414f..9a81af42ac6e9cafb3db21fac89ca4fb176f8c62 100644 (file)
@@ -1897,14 +1897,13 @@ static VOID config_entry_add_linux(
                 CHAR16 buf[256];
                 UINTN bufsize = sizeof buf;
                 EFI_FILE_INFO *f;
-                CHAR8 *sections[] = {
+                const CHAR8 *sections[] = {
                         (CHAR8 *)".osrel",
                         (CHAR8 *)".cmdline",
                         NULL
                 };
                 UINTN offs[ELEMENTSOF(sections)-1] = {};
                 UINTN szs[ELEMENTSOF(sections)-1] = {};
-                UINTN addrs[ELEMENTSOF(sections)-1] = {};
                 CHAR8 *content = NULL;
                 CHAR8 *line;
                 UINTN pos = 0;
@@ -1931,7 +1930,7 @@ static VOID config_entry_add_linux(
                         continue;
 
                 /* look for .osrel and .cmdline sections in the .efi binary */
-                err = pe_file_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs);
+                err = pe_file_locate_sections(linux_dir, f->FileName, sections, offs, szs);
                 if (EFI_ERROR(err))
                         continue;
 
index 09be2de27b36a9a4cc7655d748dbe7bbe48eab18..7fdef9990b20298fca4d7a9ef859a5e8375e7332 100644 (file)
@@ -2,6 +2,7 @@
 #pragma once
 
 #include <efi.h>
+#include "macro-fundamental.h"
 
 #define SETUP_MAGIC             0x53726448      /* "HdrS" */
 
@@ -44,7 +45,7 @@ struct setup_header {
         UINT64 pref_address;
         UINT32 init_size;
         UINT32 handover_offset;
-} __attribute__((packed));
+} _packed_;
 
 /* adapted from linux' bootparam.h */
 struct boot_params {
@@ -81,7 +82,7 @@ struct boot_params {
         UINT8  _pad8[48];
         UINT8  eddbuf[6*82];            // was: struct edd_info eddbuf[EDDMAXNR]
         UINT8  _pad9[276];
-} __attribute__((packed));
+} _packed_;
 
 EFI_STATUS linux_exec(EFI_HANDLE *image,
                       CHAR8 *cmdline, UINTN cmdline_size,
index 429e82657b19d9cb689012a147db00587cb837d9..1d19366f73a27f3c1953a1252a00c8a1c70a5ea4 100644 (file)
@@ -133,13 +133,13 @@ typedef struct {
         UINT16 HeaderVersion;
         UINT32 PCRIndex;
         UINT32 EventType;
-} __attribute__((packed)) EFI_TCG2_EVENT_HEADER;
+} _packed_ EFI_TCG2_EVENT_HEADER;
 
 typedef struct tdEFI_TCG2_EVENT {
         UINT32 Size;
         EFI_TCG2_EVENT_HEADER Header;
         UINT8 Event[1];
-} __attribute__((packed)) EFI_TCG2_EVENT;
+} _packed_ EFI_TCG2_EVENT;
 
 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This,
                                                       IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability);
index b983931348b2dc1dc1ea6e7cf4992cd36dfe761a..37c468f2ab077a654a901f8688d65d04b9bddb18 100644 (file)
@@ -120,3 +120,7 @@ typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
 } EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
 
 #endif
+
+#ifndef EFI_IMAGE_MACHINE_RISCV64
+        #define EFI_IMAGE_MACHINE_RISCV64 0x5064
+#endif
index 5c20acc9f3ae639143978e53ff6e95cdd020dcd1..04b4504c2ee3babdbd6ff2714c8b8445b55ea804 100644 (file)
@@ -6,6 +6,24 @@
 #include "pe.h"
 #include "util.h"
 
+#define DOS_FILE_MAGIC "MZ"
+#define PE_FILE_MAGIC  "PE\0\0"
+#define MAX_SECTIONS 96
+
+#if defined(__i386__)
+        #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_IA32
+#elif defined(__x86_64__)
+        #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_X64
+#elif defined(__aarch64__)
+        #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_AARCH64
+#elif defined(__arm__)
+        #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_ARMTHUMB_MIXED
+#elif defined(__riscv) && __riscv_xlen == 64
+        #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_RISCV64
+#else
+        #error Unknown EFI arch
+#endif
+
 struct DosFileHeader {
         UINT8   Magic[2];
         UINT16  LastSize;
@@ -26,14 +44,9 @@ struct DosFileHeader {
         UINT16  OEMInfo;
         UINT16  reserved2[10];
         UINT32  ExeHeader;
-} __attribute__((packed));
+} _packed_;
 
-#define PE_HEADER_MACHINE_I386          0x014c
-#define PE_HEADER_MACHINE_X64           0x8664
-#define PE_HEADER_MACHINE_ARM64         0xaa64
-#define PE_HEADER_MACHINE_ARM           0x01c2
-#define PE_HEADER_MACHINE_RISCV64       0x5064
-struct PeFileHeader {
+struct CoffFileHeader {
         UINT16  Machine;
         UINT16  NumberOfSections;
         UINT32  TimeDateStamp;
@@ -41,12 +54,13 @@ struct PeFileHeader {
         UINT32  NumberOfSymbols;
         UINT16  SizeOfOptionalHeader;
         UINT16  Characteristics;
-} __attribute__((packed));
+} _packed_;
 
-struct PeHeader {
+struct PeFileHeader {
         UINT8   Magic[4];
-        struct PeFileHeader FileHeader;
-} __attribute__((packed));
+        struct CoffFileHeader FileHeader;
+        /* OptionalHeader omitted */
+} _packed_;
 
 struct PeSectionHeader {
         UINT8   Name[8];
@@ -59,120 +73,143 @@ struct PeSectionHeader {
         UINT16  NumberOfRelocations;
         UINT16  NumberOfLinenumbers;
         UINT32  Characteristics;
-} __attribute__((packed));
+} _packed_;
 
-EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
-        struct DosFileHeader *dos;
-        struct PeHeader *pe;
-        UINTN offset;
-
-        assert(base);
-        assert(sections);
-
-        dos = (struct DosFileHeader *)base;
-
-        if (CompareMem(dos->Magic, "MZ", 2) != 0)
-                return EFI_LOAD_ERROR;
+static inline BOOLEAN verify_dos(const struct DosFileHeader *dos) {
+        assert(dos);
+        return CompareMem(dos->Magic, DOS_FILE_MAGIC, STRLEN(DOS_FILE_MAGIC)) == 0;
+}
 
-        pe = (struct PeHeader *)&base[dos->ExeHeader];
-        if (CompareMem(pe->Magic, "PE\0\0", 4) != 0)
-                return EFI_LOAD_ERROR;
+static inline BOOLEAN verify_pe(const struct PeFileHeader *pe) {
+        assert(pe);
+        return CompareMem(pe->Magic, PE_FILE_MAGIC, STRLEN(PE_FILE_MAGIC)) == 0 &&
+               pe->FileHeader.Machine == TARGET_MACHINE_TYPE &&
+               pe->FileHeader.NumberOfSections > 0 &&
+               pe->FileHeader.NumberOfSections <= MAX_SECTIONS;
+}
 
-        /* PE32+ Subsystem type */
-        if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 &&
-            pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM64 &&
-            pe->FileHeader.Machine != PE_HEADER_MACHINE_I386 &&
-            pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM &&
-            pe->FileHeader.Machine != PE_HEADER_MACHINE_RISCV64)
-                return EFI_LOAD_ERROR;
+static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) {
+        assert(dos);
+        assert(pe);
+        return dos->ExeHeader + sizeof(struct PeFileHeader) + pe->FileHeader.SizeOfOptionalHeader;
+}
 
-        if (pe->FileHeader.NumberOfSections > 96)
-                return EFI_LOAD_ERROR;
+static VOID locate_sections(
+                const struct PeSectionHeader section_table[],
+                UINTN n_table,
+                const CHAR8 **sections,
+                UINTN *addrs,
+                UINTN *offsets,
+                UINTN *sizes) {
 
-        offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader;
+        assert(section_table);
+        assert(sections);
+        assert(sizes);
 
-        for (UINTN i = 0; i < pe->FileHeader.NumberOfSections; i++) {
-                struct PeSectionHeader *sect;
+        for (UINTN i = 0; i < n_table; i++) {
+                const struct PeSectionHeader *sect = section_table + i;
 
-                sect = (struct PeSectionHeader *)&base[offset];
                 for (UINTN j = 0; sections[j]; j++) {
                         if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0)
                                 continue;
 
                         if (addrs)
-                                addrs[j] = (UINTN)sect->VirtualAddress;
+                                addrs[j] = sect->VirtualAddress;
                         if (offsets)
-                                offsets[j] = (UINTN)sect->PointerToRawData;
-                        if (sizes)
-                                sizes[j] = (UINTN)sect->VirtualSize;
+                                offsets[j] = sect->PointerToRawData;
+                        sizes[j] = sect->VirtualSize;
                 }
-                offset += sizeof(*sect);
         }
+}
+
+EFI_STATUS pe_memory_locate_sections(
+                const CHAR8 *base,
+                const CHAR8 **sections,
+                UINTN *addrs,
+                UINTN *sizes) {
+        const struct DosFileHeader *dos;
+        const struct PeFileHeader *pe;
+        UINTN offset;
+
+        assert(base);
+        assert(sections);
+        assert(addrs);
+        assert(sizes);
+
+        dos = (const struct DosFileHeader*)base;
+        if (!verify_dos(dos))
+                return EFI_LOAD_ERROR;
+
+        pe = (const struct PeFileHeader*)&base[dos->ExeHeader];
+        if (!verify_pe(pe))
+                return EFI_LOAD_ERROR;
+
+        offset = section_table_offset(dos, pe);
+        locate_sections((struct PeSectionHeader*)&base[offset], pe->FileHeader.NumberOfSections,
+                        sections, addrs, NULL, sizes);
 
         return EFI_SUCCESS;
 }
 
-EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
-        EFI_FILE_HANDLE handle;
+EFI_STATUS pe_file_locate_sections(
+                EFI_FILE *dir,
+                const CHAR16 *path,
+                const CHAR8 **sections,
+                UINTN *offsets,
+                UINTN *sizes) {
+        _cleanup_freepool_ struct PeSectionHeader *section_table = NULL;
+        _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
         struct DosFileHeader dos;
-        struct PeHeader pe;
-        UINTN len;
-        UINTN headerlen;
+        struct PeFileHeader pe;
+        UINTN len, section_table_len;
         EFI_STATUS err;
-        _cleanup_freepool_ CHAR8 *header = NULL;
 
         assert(dir);
         assert(path);
+        assert(sections);
+        assert(offsets);
+        assert(sizes);
 
-        err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
+        err = uefi_call_wrapper(dir->Open, 5, dir, &handle, (CHAR16*)path, EFI_FILE_MODE_READ, 0ULL);
         if (EFI_ERROR(err))
                 return err;
 
-        /* MS-DOS stub */
         len = sizeof(dos);
         err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
         if (EFI_ERROR(err))
-                goto out;
-        if (len != sizeof(dos)) {
-                err = EFI_LOAD_ERROR;
-                goto out;
-        }
+                return err;
+        if (len != sizeof(dos) || !verify_dos(&dos))
+                return EFI_LOAD_ERROR;
 
         err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
         if (EFI_ERROR(err))
-                goto out;
+                return err;
 
         len = sizeof(pe);
         err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
         if (EFI_ERROR(err))
-                goto out;
-        if (len != sizeof(pe)) {
-                err = EFI_LOAD_ERROR;
-                goto out;
-        }
+                return err;
+        if (len != sizeof(pe) || !verify_pe(&pe))
+                return EFI_LOAD_ERROR;
 
-        headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
-        header = AllocatePool(headerlen);
-        if (!header) {
-                err = EFI_OUT_OF_RESOURCES;
-                goto out;
-        }
-        len = headerlen;
-        err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
+        section_table_len = pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
+        section_table = AllocatePool(section_table_len);
+        if (!section_table)
+                return EFI_OUT_OF_RESOURCES;
+
+        err = uefi_call_wrapper(handle->SetPosition, 2, handle, section_table_offset(&dos, &pe));
         if (EFI_ERROR(err))
-                goto out;
+                return err;
 
-        err = uefi_call_wrapper(handle->Read, 3, handle, &len, header);
+        len = section_table_len;
+        err = uefi_call_wrapper(handle->Read, 3, handle, &len, section_table);
         if (EFI_ERROR(err))
-                goto out;
+                return err;
+        if (len != section_table_len)
+                return EFI_LOAD_ERROR;
 
-        if (len != headerlen) {
-                err = EFI_LOAD_ERROR;
-                goto out;
-        }
+        locate_sections(section_table, pe.FileHeader.NumberOfSections,
+                        sections, NULL, offsets, sizes);
 
-        err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes);
-out:
-        uefi_call_wrapper(handle->Close, 1, handle);
-        return err;
+        return EFI_SUCCESS;
 }
index 06a0fcd70c6b9c3dc6703ac52d13432183175041..e35521122353571a63e7b85b64586b5f09b4547f 100644 (file)
@@ -1,9 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#include <efi.h>
+#include <efidef.h>
 
-EFI_STATUS pe_memory_locate_sections(CHAR8 *base,
-                                     CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes);
-EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path,
-                                   CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes);
+EFI_STATUS pe_memory_locate_sections(
+                const CHAR8 *base,
+                const CHAR8 **sections,
+                UINTN *addrs,
+                UINTN *sizes);
+
+EFI_STATUS pe_file_locate_sections(
+                EFI_FILE *dir,
+                const CHAR16 *path,
+                const CHAR8 **sections,
+                UINTN *offsets,
+                UINTN *sizes);
index 920b440825e9d633c6315c4a5742b23b3cd3758f..23627a794e7c803b5a8f211c5acb6581452870a3 100644 (file)
@@ -12,7 +12,7 @@ struct bmp_file {
         UINT32 size;
         UINT16 reserved[2];
         UINT32 offset;
-} __attribute__((packed));
+} _packed_;
 
 /* we require at least BITMAPINFOHEADER, later versions are
    accepted, but their features ignored */
@@ -28,14 +28,14 @@ struct bmp_dib {
         INT32 y_pixel_meter;
         UINT32 colors_used;
         UINT32 colors_important;
-} __attribute__((packed));
+} _packed_;
 
 struct bmp_map {
         UINT8 blue;
         UINT8 green;
         UINT8 red;
         UINT8 reserved;
-} __attribute__((packed));
+} _packed_;
 
 static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
                             struct bmp_map **ret_map, UINT8 **pixmap) {
index 82da1d3ec47597a37c47ab0aecc6fb2b4908ef50..5758b5cd9481e3021bde2427598ec766addf2ccb 100644 (file)
@@ -17,7 +17,7 @@ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub
 
 EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         EFI_LOADED_IMAGE *loaded_image;
-        CHAR8 *sections[] = {
+        const CHAR8 *sections[] = {
                 (CHAR8 *)".cmdline",
                 (CHAR8 *)".linux",
                 (CHAR8 *)".initrd",
@@ -25,7 +25,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
                 NULL
         };
         UINTN addrs[ELEMENTSOF(sections)-1] = {};
-        UINTN offs[ELEMENTSOF(sections)-1] = {};
         UINTN szs[ELEMENTSOF(sections)-1] = {};
         CHAR8 *cmdline = NULL;
         UINTN cmdline_len;
@@ -39,7 +38,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         if (EFI_ERROR(err))
                 return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
 
-        err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, offs, szs);
+        err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, szs);
         if (EFI_ERROR(err))
                 return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
 
index 461d37fa9e19a77f02740e5e503cb0e47fcd3f2a..20d8dabf296fd5bbfcd96f58fd5a90f97be08de4 100644 (file)
@@ -11,6 +11,7 @@
 #define _const_ __attribute__((__const__))
 #define _pure_ __attribute__((__pure__))
 #define _section_(x) __attribute__((__section__(x)))
+#define _packed_ __attribute__((__packed__))
 #define _used_ __attribute__((__used__))
 #define _unused_ __attribute__((__unused__))
 #define _cleanup_(x) __attribute__((__cleanup__(x)))