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 #include "efi.h"
24 #include "efi/pe.h"
25
26 #if defined(__arm__) || defined (__aarch64__)
27 #define PE_HEADER_MACHINE 0xaa64
28 #elif defined(__x86_64__)
29 #define PE_HEADER_MACHINE 0x8664
30 #else
31 #error "Unknown architecture"
32 #endif
33
pe_name_compare(const struct section_header * sect,const CHAR16 * name)34 static bool __init pe_name_compare(const struct section_header *sect,
35 const CHAR16 *name)
36 {
37 size_t i;
38
39 if ( sect->name[0] != '.' )
40 return false;
41
42 for ( i = 1; i < sizeof(sect->name); i++ )
43 {
44 const char c = sect->name[i];
45
46 if ( c != name[i - 1] )
47 return false;
48 if ( c == '\0' )
49 return true;
50 }
51
52 return name[i - 1] == L'\0';
53 }
54
pe_find_section(const void * image,const UINTN image_size,const CHAR16 * section_name,UINTN * size_out)55 const void *__init pe_find_section(const void *image, const UINTN image_size,
56 const CHAR16 *section_name, UINTN *size_out)
57 {
58 const struct mz_hdr *mz = image;
59 const struct pe_hdr *pe;
60 const struct section_header *sect;
61 UINTN offset, i;
62
63 if ( image_size < sizeof(*mz) ||
64 mz->magic != MZ_MAGIC )
65 return NULL;
66
67 offset = mz->peaddr;
68 pe = image + offset;
69
70 offset += sizeof(*pe);
71 if ( image_size < offset ||
72 pe->magic != PE_MAGIC )
73 return NULL;
74
75 if ( pe->machine != PE_HEADER_MACHINE )
76 return NULL;
77
78 offset += pe->opt_hdr_size;
79
80 for ( i = 0; i < pe->sections; i++ )
81 {
82 sect = image + offset;
83 if ( image_size < offset + sizeof(*sect) )
84 return NULL;
85
86 if ( !pe_name_compare(sect, section_name) )
87 {
88 offset += sizeof(*sect);
89 continue;
90 }
91
92 if ( image_size < sect->virtual_size + sect->rva )
93 blexit(L"PE invalid section size + address");
94
95 if ( size_out )
96 *size_out = sect->virtual_size;
97
98 return image + sect->rva;
99 }
100
101 return NULL;
102 }
103