]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/pe.c
Merge pull request #18863 from keszybz/cmdline-escaping
[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 #define PE_HEADER_MACHINE_ARM 0x01c2
35 #define PE_HEADER_MACHINE_RISCV64 0x5064
36 struct PeFileHeader {
37 UINT16 Machine;
38 UINT16 NumberOfSections;
39 UINT32 TimeDateStamp;
40 UINT32 PointerToSymbolTable;
41 UINT32 NumberOfSymbols;
42 UINT16 SizeOfOptionalHeader;
43 UINT16 Characteristics;
44 } __attribute__((packed));
45
46 struct PeHeader {
47 UINT8 Magic[4];
48 struct PeFileHeader FileHeader;
49 } __attribute__((packed));
50
51 struct PeSectionHeader {
52 UINT8 Name[8];
53 UINT32 VirtualSize;
54 UINT32 VirtualAddress;
55 UINT32 SizeOfRawData;
56 UINT32 PointerToRawData;
57 UINT32 PointerToRelocations;
58 UINT32 PointerToLinenumbers;
59 UINT16 NumberOfRelocations;
60 UINT16 NumberOfLinenumbers;
61 UINT32 Characteristics;
62 } __attribute__((packed));
63
64 EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
65 struct DosFileHeader *dos;
66 struct PeHeader *pe;
67 UINTN offset;
68
69 dos = (struct DosFileHeader *)base;
70
71 if (CompareMem(dos->Magic, "MZ", 2) != 0)
72 return EFI_LOAD_ERROR;
73
74 pe = (struct PeHeader *)&base[dos->ExeHeader];
75 if (CompareMem(pe->Magic, "PE\0\0", 4) != 0)
76 return EFI_LOAD_ERROR;
77
78 /* PE32+ Subsystem type */
79 if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 &&
80 pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM64 &&
81 pe->FileHeader.Machine != PE_HEADER_MACHINE_I386 &&
82 pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM &&
83 pe->FileHeader.Machine != PE_HEADER_MACHINE_RISCV64)
84 return EFI_LOAD_ERROR;
85
86 if (pe->FileHeader.NumberOfSections > 96)
87 return EFI_LOAD_ERROR;
88
89 offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader;
90
91 for (UINTN i = 0; i < pe->FileHeader.NumberOfSections; i++) {
92 struct PeSectionHeader *sect;
93
94 sect = (struct PeSectionHeader *)&base[offset];
95 for (UINTN j = 0; sections[j]; j++) {
96 if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0)
97 continue;
98
99 if (addrs)
100 addrs[j] = (UINTN)sect->VirtualAddress;
101 if (offsets)
102 offsets[j] = (UINTN)sect->PointerToRawData;
103 if (sizes)
104 sizes[j] = (UINTN)sect->VirtualSize;
105 }
106 offset += sizeof(*sect);
107 }
108
109 return EFI_SUCCESS;
110 }
111
112 EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
113 EFI_FILE_HANDLE handle;
114 struct DosFileHeader dos;
115 struct PeHeader pe;
116 UINTN len;
117 UINTN headerlen;
118 EFI_STATUS err;
119 _cleanup_freepool_ CHAR8 *header = NULL;
120
121 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
122 if (EFI_ERROR(err))
123 return err;
124
125 /* MS-DOS stub */
126 len = sizeof(dos);
127 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
128 if (EFI_ERROR(err))
129 goto out;
130 if (len != sizeof(dos)) {
131 err = EFI_LOAD_ERROR;
132 goto out;
133 }
134
135 err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
136 if (EFI_ERROR(err))
137 goto out;
138
139 len = sizeof(pe);
140 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
141 if (EFI_ERROR(err))
142 goto out;
143 if (len != sizeof(pe)) {
144 err = EFI_LOAD_ERROR;
145 goto out;
146 }
147
148 headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
149 header = AllocatePool(headerlen);
150 if (!header) {
151 err = EFI_OUT_OF_RESOURCES;
152 goto out;
153 }
154 len = headerlen;
155 err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
156 if (EFI_ERROR(err))
157 goto out;
158
159 err = uefi_call_wrapper(handle->Read, 3, handle, &len, header);
160 if (EFI_ERROR(err))
161 goto out;
162
163 if (len != headerlen) {
164 err = EFI_LOAD_ERROR;
165 goto out;
166 }
167
168 err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes);
169 out:
170 uefi_call_wrapper(handle->Close, 1, handle);
171 return err;
172 }