]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/pefile.c
gummiboot/sd-boot/systemd-boot: rename galore
[thirdparty/systemd.git] / src / boot / efi / pefile.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /*
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
15 */
16
17 #include <efi.h>
18 #include <efilib.h>
19
20 #include "util.h"
21 #include "pefile.h"
22
23 struct DosFileHeader {
24 UINT8 Magic[2];
25 UINT16 LastSize;
26 UINT16 nBlocks;
27 UINT16 nReloc;
28 UINT16 HdrSize;
29 UINT16 MinAlloc;
30 UINT16 MaxAlloc;
31 UINT16 ss;
32 UINT16 sp;
33 UINT16 Checksum;
34 UINT16 ip;
35 UINT16 cs;
36 UINT16 RelocPos;
37 UINT16 nOverlay;
38 UINT16 reserved[4];
39 UINT16 OEMId;
40 UINT16 OEMInfo;
41 UINT16 reserved2[10];
42 UINT32 ExeHeader;
43 } __attribute__((packed));
44
45 #define PE_HEADER_MACHINE_I386 0x014c
46 #define PE_HEADER_MACHINE_X64 0x8664
47 struct PeFileHeader {
48 UINT16 Machine;
49 UINT16 NumberOfSections;
50 UINT32 TimeDateStamp;
51 UINT32 PointerToSymbolTable;
52 UINT32 NumberOfSymbols;
53 UINT16 SizeOfOptionalHeader;
54 UINT16 Characteristics;
55 } __attribute__((packed));
56
57 struct PeSectionHeader {
58 UINT8 Name[8];
59 UINT32 VirtualSize;
60 UINT32 VirtualAddress;
61 UINT32 SizeOfRawData;
62 UINT32 PointerToRawData;
63 UINT32 PointerToRelocations;
64 UINT32 PointerToLinenumbers;
65 UINT16 NumberOfRelocations;
66 UINT16 NumberOfLinenumbers;
67 UINT32 Characteristics;
68 } __attribute__((packed));
69
70
71 EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
72 EFI_FILE_HANDLE handle;
73 struct DosFileHeader dos;
74 uint8_t magic[4];
75 struct PeFileHeader pe;
76 UINTN len;
77 UINTN i;
78 EFI_STATUS err;
79
80 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
81 if (EFI_ERROR(err))
82 return err;
83
84 /* MS-DOS stub */
85 len = sizeof(dos);
86 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
87 if (EFI_ERROR(err))
88 goto out;
89 if (len != sizeof(dos)) {
90 err = EFI_LOAD_ERROR;
91 goto out;
92 }
93
94 if (CompareMem(dos.Magic, "MZ", 2) != 0) {
95 err = EFI_LOAD_ERROR;
96 goto out;
97 }
98
99 err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
100 if (EFI_ERROR(err))
101 goto out;
102
103 /* PE header */
104 len = sizeof(magic);
105 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &magic);
106 if (EFI_ERROR(err))
107 goto out;
108 if (len != sizeof(magic)) {
109 err = EFI_LOAD_ERROR;
110 goto out;
111 }
112
113 if (CompareMem(magic, "PE\0\0", 2) != 0) {
114 err = EFI_LOAD_ERROR;
115 goto out;
116 }
117
118 len = sizeof(pe);
119 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
120 if (EFI_ERROR(err))
121 goto out;
122 if (len != sizeof(pe)) {
123 err = EFI_LOAD_ERROR;
124 goto out;
125 }
126
127 /* PE32+ Subsystem type */
128 if (pe.Machine != PE_HEADER_MACHINE_X64 &&
129 pe.Machine != PE_HEADER_MACHINE_I386) {
130 err = EFI_LOAD_ERROR;
131 goto out;
132 }
133
134 if (pe.NumberOfSections > 96) {
135 err = EFI_LOAD_ERROR;
136 goto out;
137 }
138
139 /* the sections start directly after the headers */
140 err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader + sizeof(magic) + sizeof(pe) + pe.SizeOfOptionalHeader);
141 if (EFI_ERROR(err))
142 goto out;
143
144 for (i = 0; i < pe.NumberOfSections; i++) {
145 struct PeSectionHeader sect;
146 UINTN j;
147
148 len = sizeof(sect);
149 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &sect);
150 if (EFI_ERROR(err))
151 goto out;
152 if (len != sizeof(sect)) {
153 err = EFI_LOAD_ERROR;
154 goto out;
155 }
156 for (j = 0; sections[j]; j++) {
157 if (CompareMem(sect.Name, sections[j], strlena(sections[j])) != 0)
158 continue;
159
160 if (addrs)
161 addrs[j] = (UINTN)sect.VirtualAddress;
162 if (offsets)
163 offsets[j] = (UINTN)sect.PointerToRawData;
164 if (sizes)
165 sizes[j] = (UINTN)sect.VirtualSize;
166 }
167 }
168
169 out:
170 uefi_call_wrapper(handle->Close, 1, handle);
171 return err;
172 }