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