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