]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/pe.c
Merge pull request #17549 from yuwata/tiny-fixes
[thirdparty/systemd.git] / src / boot / efi / pe.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <efi.h>
4 #include <efilib.h>
5
6 #include "pe.h"
7 #include "util.h"
8
9 struct DosFileHeader {
10 UINT8 Magic[2];
11 UINT16 LastSize;
12 UINT16 nBlocks;
13 UINT16 nReloc;
14 UINT16 HdrSize;
15 UINT16 MinAlloc;
16 UINT16 MaxAlloc;
17 UINT16 ss;
18 UINT16 sp;
19 UINT16 Checksum;
20 UINT16 ip;
21 UINT16 cs;
22 UINT16 RelocPos;
23 UINT16 nOverlay;
24 UINT16 reserved[4];
25 UINT16 OEMId;
26 UINT16 OEMInfo;
27 UINT16 reserved2[10];
28 UINT32 ExeHeader;
29 } __attribute__((packed));
30
31 #define PE_HEADER_MACHINE_I386 0x014c
32 #define PE_HEADER_MACHINE_X64 0x8664
33 #define PE_HEADER_MACHINE_ARM64 0xaa64
34 struct PeFileHeader {
35 UINT16 Machine;
36 UINT16 NumberOfSections;
37 UINT32 TimeDateStamp;
38 UINT32 PointerToSymbolTable;
39 UINT32 NumberOfSymbols;
40 UINT16 SizeOfOptionalHeader;
41 UINT16 Characteristics;
42 } __attribute__((packed));
43
44 struct PeHeader {
45 UINT8 Magic[4];
46 struct PeFileHeader FileHeader;
47 } __attribute__((packed));
48
49 struct PeSectionHeader {
50 UINT8 Name[8];
51 UINT32 VirtualSize;
52 UINT32 VirtualAddress;
53 UINT32 SizeOfRawData;
54 UINT32 PointerToRawData;
55 UINT32 PointerToRelocations;
56 UINT32 PointerToLinenumbers;
57 UINT16 NumberOfRelocations;
58 UINT16 NumberOfLinenumbers;
59 UINT32 Characteristics;
60 } __attribute__((packed));
61
62 EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
63 struct DosFileHeader *dos;
64 struct PeHeader *pe;
65 UINTN i;
66 UINTN offset;
67
68 dos = (struct DosFileHeader *)base;
69
70 if (CompareMem(dos->Magic, "MZ", 2) != 0)
71 return EFI_LOAD_ERROR;
72
73 pe = (struct PeHeader *)&base[dos->ExeHeader];
74 if (CompareMem(pe->Magic, "PE\0\0", 4) != 0)
75 return EFI_LOAD_ERROR;
76
77 /* PE32+ Subsystem type */
78 if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 &&
79 pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM64 &&
80 pe->FileHeader.Machine != PE_HEADER_MACHINE_I386)
81 return EFI_LOAD_ERROR;
82
83 if (pe->FileHeader.NumberOfSections > 96)
84 return EFI_LOAD_ERROR;
85
86 offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader;
87
88 for (i = 0; i < pe->FileHeader.NumberOfSections; i++) {
89 struct PeSectionHeader *sect;
90 UINTN j;
91
92 sect = (struct PeSectionHeader *)&base[offset];
93 for (j = 0; sections[j]; j++) {
94 if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0)
95 continue;
96
97 if (addrs)
98 addrs[j] = (UINTN)sect->VirtualAddress;
99 if (offsets)
100 offsets[j] = (UINTN)sect->PointerToRawData;
101 if (sizes)
102 sizes[j] = (UINTN)sect->VirtualSize;
103 }
104 offset += sizeof(*sect);
105 }
106
107 return EFI_SUCCESS;
108 }
109
110 EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
111 EFI_FILE_HANDLE handle;
112 struct DosFileHeader dos;
113 struct PeHeader pe;
114 UINTN len;
115 UINTN headerlen;
116 EFI_STATUS err;
117 _cleanup_freepool_ CHAR8 *header = NULL;
118
119 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
120 if (EFI_ERROR(err))
121 return err;
122
123 /* MS-DOS stub */
124 len = sizeof(dos);
125 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
126 if (EFI_ERROR(err))
127 goto out;
128 if (len != sizeof(dos)) {
129 err = EFI_LOAD_ERROR;
130 goto out;
131 }
132
133 err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
134 if (EFI_ERROR(err))
135 goto out;
136
137 len = sizeof(pe);
138 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
139 if (EFI_ERROR(err))
140 goto out;
141 if (len != sizeof(pe)) {
142 err = EFI_LOAD_ERROR;
143 goto out;
144 }
145
146 headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
147 header = AllocatePool(headerlen);
148 if (!header) {
149 err = EFI_OUT_OF_RESOURCES;
150 goto out;
151 }
152 len = headerlen;
153 err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
154 if (EFI_ERROR(err))
155 goto out;
156
157 err = uefi_call_wrapper(handle->Read, 3, handle, &len, header);
158 if (EFI_ERROR(err))
159 goto out;
160
161 if (len != headerlen) {
162 err = EFI_LOAD_ERROR;
163 goto out;
164 }
165
166 err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes);
167 out:
168 uefi_call_wrapper(handle->Close, 1, handle);
169 return err;
170 }