1 /*
2 * xen/common/efi/pe.c
3 *
4 * PE executable header parser.
5 *
6 * Derived from https://github.com/systemd/systemd/blob/master/src/boot/efi/pe.c
7 * commit 07d5ed536ec0a76b08229c7a80b910cb9acaf6b1
8 *
9 * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
10 * Copyright (C) 2020 Trammell Hudson <hudson@trmm.net>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 */
22
23
24 #include "efi.h"
25
26 struct DosFileHeader {
27 UINT8 Magic[2];
28 UINT16 LastSize;
29 UINT16 nBlocks;
30 UINT16 nReloc;
31 UINT16 HdrSize;
32 UINT16 MinAlloc;
33 UINT16 MaxAlloc;
34 UINT16 ss;
35 UINT16 sp;
36 UINT16 Checksum;
37 UINT16 ip;
38 UINT16 cs;
39 UINT16 RelocPos;
40 UINT16 nOverlay;
41 UINT16 reserved[4];
42 UINT16 OEMId;
43 UINT16 OEMInfo;
44 UINT16 reserved2[10];
45 UINT32 ExeHeader;
46 };
47
48 #if defined(__arm__) || defined (__aarch64__)
49 #define PE_HEADER_MACHINE 0xaa64
50 #elif defined(__x86_64__)
51 #define PE_HEADER_MACHINE 0x8664
52 #else
53 #error "Unknown architecture"
54 #endif
55
56 struct PeFileHeader {
57 UINT16 Machine;
58 UINT16 NumberOfSections;
59 UINT32 TimeDateStamp;
60 UINT32 PointerToSymbolTable;
61 UINT32 NumberOfSymbols;
62 UINT16 SizeOfOptionalHeader;
63 UINT16 Characteristics;
64 };
65
66 struct PeHeader {
67 UINT8 Magic[4];
68 struct PeFileHeader FileHeader;
69 };
70
71 struct PeSectionHeader {
72 CHAR8 Name[8];
73 UINT32 VirtualSize;
74 UINT32 VirtualAddress;
75 UINT32 SizeOfRawData;
76 UINT32 PointerToRawData;
77 UINT32 PointerToRelocations;
78 UINT32 PointerToLinenumbers;
79 UINT16 NumberOfRelocations;
80 UINT16 NumberOfLinenumbers;
81 UINT32 Characteristics;
82 };
83
pe_name_compare(const struct PeSectionHeader * sect,const CHAR16 * name)84 static bool __init pe_name_compare(const struct PeSectionHeader *sect,
85 const CHAR16 *name)
86 {
87 size_t i;
88
89 if ( sect->Name[0] != '.' )
90 return false;
91
92 for ( i = 1; i < sizeof(sect->Name); i++ )
93 {
94 const char c = sect->Name[i];
95
96 if ( c != name[i - 1] )
97 return false;
98 if ( c == '\0' )
99 return true;
100 }
101
102 return name[i - 1] == L'\0';
103 }
104
pe_find_section(const void * image,const UINTN image_size,const CHAR16 * section_name,UINTN * size_out)105 const void *__init pe_find_section(const void *image, const UINTN image_size,
106 const CHAR16 *section_name, UINTN *size_out)
107 {
108 const struct DosFileHeader *dos = image;
109 const struct PeHeader *pe;
110 const struct PeSectionHeader *sect;
111 UINTN offset, i;
112
113 if ( image_size < sizeof(*dos) ||
114 dos->Magic[0] != 'M' ||
115 dos->Magic[1] != 'Z' )
116 return NULL;
117
118 offset = dos->ExeHeader;
119 pe = image + offset;
120
121 offset += sizeof(*pe);
122 if ( image_size < offset ||
123 pe->Magic[0] != 'P' ||
124 pe->Magic[1] != 'E' ||
125 pe->Magic[2] != '\0' ||
126 pe->Magic[3] != '\0' )
127 return NULL;
128
129 if ( pe->FileHeader.Machine != PE_HEADER_MACHINE )
130 return NULL;
131
132 offset += pe->FileHeader.SizeOfOptionalHeader;
133
134 for ( i = 0; i < pe->FileHeader.NumberOfSections; i++ )
135 {
136 sect = image + offset;
137 if ( image_size < offset + sizeof(*sect) )
138 return NULL;
139
140 if ( !pe_name_compare(sect, section_name) )
141 {
142 offset += sizeof(*sect);
143 continue;
144 }
145
146 if ( image_size < sect->VirtualSize + sect->VirtualAddress )
147 blexit(L"PE invalid section size + address");
148
149 if ( size_out )
150 *size_out = sect->VirtualSize;
151
152 return image + sect->VirtualAddress;
153 }
154
155 return NULL;
156 }
157