]> git.proxmox.com Git - efi-boot-shim.git/blob - pe.c
New upstream version 15.4
[efi-boot-shim.git] / pe.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * pe.c - helper functions for pe binaries.
4 * Copyright Peter Jones <pjones@redhat.com>
5 */
6
7 #include "shim.h"
8
9 #include <openssl/err.h>
10 #include <openssl/bn.h>
11 #include <openssl/dh.h>
12 #include <openssl/ocsp.h>
13 #include <openssl/pkcs12.h>
14 #include <openssl/rand.h>
15 #include <openssl/crypto.h>
16 #include <openssl/ssl.h>
17 #include <openssl/x509.h>
18 #include <openssl/x509v3.h>
19 #include <openssl/rsa.h>
20 #include <openssl/dso.h>
21
22 #include <Library/BaseCryptLib.h>
23
24 /*
25 * Perform basic bounds checking of the intra-image pointers
26 */
27 void *
28 ImageAddress (void *image, uint64_t size, uint64_t address)
29 {
30 /* ensure our local pointer isn't bigger than our size */
31 if (address > size)
32 return NULL;
33
34 /* Insure our math won't overflow */
35 if (UINT64_MAX - address < (uint64_t)(intptr_t)image)
36 return NULL;
37
38 /* return the absolute pointer */
39 return image + address;
40 }
41
42 /*
43 * Perform the actual relocation
44 */
45 EFI_STATUS
46 relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
47 EFI_IMAGE_SECTION_HEADER *Section,
48 void *orig, void *data)
49 {
50 EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
51 UINT64 Adjust;
52 UINT16 *Reloc, *RelocEnd;
53 char *Fixup, *FixupBase;
54 UINT16 *Fixup16;
55 UINT32 *Fixup32;
56 UINT64 *Fixup64;
57 int size = context->ImageSize;
58 void *ImageEnd = (char *)orig + size;
59 int n = 0;
60
61 /* Alright, so here's how this works:
62 *
63 * context->RelocDir gives us two things:
64 * - the VA the table of base relocation blocks are (maybe) to be
65 * mapped at (RelocDir->VirtualAddress)
66 * - the virtual size (RelocDir->Size)
67 *
68 * The .reloc section (Section here) gives us some other things:
69 * - the name! kind of. (Section->Name)
70 * - the virtual size (Section->VirtualSize), which should be the same
71 * as RelocDir->Size
72 * - the virtual address (Section->VirtualAddress)
73 * - the file section size (Section->SizeOfRawData), which is
74 * a multiple of OptHdr->FileAlignment. Only useful for image
75 * validation, not really useful for iteration bounds.
76 * - the file address (Section->PointerToRawData)
77 * - a bunch of stuff we don't use that's 0 in our binaries usually
78 * - Flags (Section->Characteristics)
79 *
80 * and then the thing that's actually at the file address is an array
81 * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
82 * them. The SizeOfBlock field of this structure includes the
83 * structure itself, and adding it to that structure's address will
84 * yield the next entry in the array.
85 */
86 RelocBase = ImageAddress(orig, size, Section->PointerToRawData);
87 /* RelocBaseEnd here is the address of the first entry /past/ the
88 * table. */
89 RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData +
90 Section->Misc.VirtualSize);
91
92 if (!RelocBase && !RelocBaseEnd)
93 return EFI_SUCCESS;
94
95 if (!RelocBase || !RelocBaseEnd) {
96 perror(L"Reloc table overflows binary\n");
97 return EFI_UNSUPPORTED;
98 }
99
100 Adjust = (UINTN)data - context->ImageAddress;
101
102 if (Adjust == 0)
103 return EFI_SUCCESS;
104
105 while (RelocBase < RelocBaseEnd) {
106 Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
107
108 if (RelocBase->SizeOfBlock == 0) {
109 perror(L"Reloc %d block size 0 is invalid\n", n);
110 return EFI_UNSUPPORTED;
111 } else if (RelocBase->SizeOfBlock > context->RelocDir->Size) {
112 perror(L"Reloc %d block size %d greater than reloc dir"
113 "size %d, which is invalid\n", n,
114 RelocBase->SizeOfBlock,
115 context->RelocDir->Size);
116 return EFI_UNSUPPORTED;
117 }
118
119 RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
120 if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) {
121 perror(L"Reloc %d entry overflows binary\n", n);
122 return EFI_UNSUPPORTED;
123 }
124
125 FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
126 if (!FixupBase) {
127 perror(L"Reloc %d Invalid fixupbase\n", n);
128 return EFI_UNSUPPORTED;
129 }
130
131 while (Reloc < RelocEnd) {
132 Fixup = FixupBase + (*Reloc & 0xFFF);
133 switch ((*Reloc) >> 12) {
134 case EFI_IMAGE_REL_BASED_ABSOLUTE:
135 break;
136
137 case EFI_IMAGE_REL_BASED_HIGH:
138 Fixup16 = (UINT16 *) Fixup;
139 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
140 break;
141
142 case EFI_IMAGE_REL_BASED_LOW:
143 Fixup16 = (UINT16 *) Fixup;
144 *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
145 break;
146
147 case EFI_IMAGE_REL_BASED_HIGHLOW:
148 Fixup32 = (UINT32 *) Fixup;
149 *Fixup32 = *Fixup32 + (UINT32) Adjust;
150 break;
151
152 case EFI_IMAGE_REL_BASED_DIR64:
153 Fixup64 = (UINT64 *) Fixup;
154 *Fixup64 = *Fixup64 + (UINT64) Adjust;
155 break;
156
157 default:
158 perror(L"Reloc %d Unknown relocation\n", n);
159 return EFI_UNSUPPORTED;
160 }
161 Reloc += 1;
162 }
163 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
164 n++;
165 }
166
167 return EFI_SUCCESS;
168 }
169
170 #define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \
171 if ((unsigned long)hashbase > \
172 (unsigned long)data + datasize_in) { \
173 efi_status = EFI_INVALID_PARAMETER; \
174 perror(L"shim.c:%d Invalid hash base 0x%016x\n", l, \
175 hashbase); \
176 goto done; \
177 } \
178 if ((unsigned long)hashbase + hashsize > \
179 (unsigned long)data + datasize_in) { \
180 efi_status = EFI_INVALID_PARAMETER; \
181 perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \
182 hashsize); \
183 goto done; \
184 } \
185 })
186 #define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__)
187
188 EFI_STATUS
189 get_section_vma (UINTN section_num,
190 char *buffer, size_t bufsz UNUSED,
191 PE_COFF_LOADER_IMAGE_CONTEXT *context,
192 char **basep, size_t *sizep,
193 EFI_IMAGE_SECTION_HEADER **sectionp)
194 {
195 EFI_IMAGE_SECTION_HEADER *sections = context->FirstSection;
196 EFI_IMAGE_SECTION_HEADER *section;
197 char *base = NULL, *end = NULL;
198
199 if (section_num >= context->NumberOfSections)
200 return EFI_NOT_FOUND;
201
202 if (context->FirstSection == NULL) {
203 perror(L"Invalid section %d requested\n", section_num);
204 return EFI_UNSUPPORTED;
205 }
206
207 section = &sections[section_num];
208
209 base = ImageAddress (buffer, context->ImageSize, section->VirtualAddress);
210 end = ImageAddress (buffer, context->ImageSize,
211 section->VirtualAddress + section->Misc.VirtualSize - 1);
212
213 if (!(section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE)) {
214 if (!base) {
215 perror(L"Section %d has invalid base address\n", section_num);
216 return EFI_UNSUPPORTED;
217 }
218 if (!end) {
219 perror(L"Section %d has zero size\n", section_num);
220 return EFI_UNSUPPORTED;
221 }
222 }
223
224 if (!(section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) &&
225 (section->VirtualAddress < context->SizeOfHeaders ||
226 section->PointerToRawData < context->SizeOfHeaders)) {
227 perror(L"Section %d is inside image headers\n", section_num);
228 return EFI_UNSUPPORTED;
229 }
230
231 if (end < base) {
232 perror(L"Section %d has negative size\n", section_num);
233 return EFI_UNSUPPORTED;
234 }
235
236 *basep = base;
237 *sizep = end - base;
238 *sectionp = section;
239 return EFI_SUCCESS;
240 }
241
242 EFI_STATUS
243 get_section_vma_by_name (char *name, size_t namesz,
244 char *buffer, size_t bufsz,
245 PE_COFF_LOADER_IMAGE_CONTEXT *context,
246 char **basep, size_t *sizep,
247 EFI_IMAGE_SECTION_HEADER **sectionp)
248 {
249 UINTN i;
250 char namebuf[9];
251
252 if (!name || namesz == 0 || !buffer || bufsz < namesz || !context
253 || !basep || !sizep || !sectionp)
254 return EFI_INVALID_PARAMETER;
255
256 /*
257 * This code currently is only used for ".reloc\0\0" and
258 * ".sbat\0\0\0", and it doesn't know how to look up longer section
259 * names.
260 */
261 if (namesz > 8)
262 return EFI_UNSUPPORTED;
263
264 SetMem(namebuf, sizeof(namebuf), 0);
265 CopyMem(namebuf, name, MIN(namesz, 8));
266
267 /*
268 * Copy the executable's sections to their desired offsets
269 */
270 for (i = 0; i < context->NumberOfSections; i++) {
271 EFI_STATUS status;
272 EFI_IMAGE_SECTION_HEADER *section = NULL;
273 char *base = NULL;
274 size_t size = 0;
275
276 status = get_section_vma(i, buffer, bufsz, context, &base, &size, &section);
277 if (!EFI_ERROR(status)) {
278 if (CompareMem(section->Name, namebuf, 8) == 0) {
279 *basep = base;
280 *sizep = size;
281 *sectionp = section;
282 return EFI_SUCCESS;
283 }
284 continue;
285 }
286
287 switch(status) {
288 case EFI_NOT_FOUND:
289 break;
290 }
291 }
292
293 return EFI_NOT_FOUND;
294 }
295
296 /*
297 * Calculate the SHA1 and SHA256 hashes of a binary
298 */
299
300 EFI_STATUS
301 generate_hash(char *data, unsigned int datasize_in,
302 PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash,
303 UINT8 *sha1hash)
304 {
305 unsigned int sha256ctxsize, sha1ctxsize;
306 unsigned int size = datasize_in;
307 void *sha256ctx = NULL, *sha1ctx = NULL;
308 char *hashbase;
309 unsigned int hashsize;
310 unsigned int SumOfBytesHashed, SumOfSectionBytes;
311 unsigned int index, pos;
312 unsigned int datasize;
313 EFI_IMAGE_SECTION_HEADER *Section;
314 EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
315 EFI_STATUS efi_status = EFI_SUCCESS;
316 EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
317 unsigned int PEHdr_offset = 0;
318
319 size = datasize = datasize_in;
320
321 if (datasize <= sizeof (*DosHdr) ||
322 DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
323 perror(L"Invalid signature\n");
324 return EFI_INVALID_PARAMETER;
325 }
326 PEHdr_offset = DosHdr->e_lfanew;
327
328 sha256ctxsize = Sha256GetContextSize();
329 sha256ctx = AllocatePool(sha256ctxsize);
330
331 sha1ctxsize = Sha1GetContextSize();
332 sha1ctx = AllocatePool(sha1ctxsize);
333
334 if (!sha256ctx || !sha1ctx) {
335 perror(L"Unable to allocate memory for hash context\n");
336 return EFI_OUT_OF_RESOURCES;
337 }
338
339 if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) {
340 perror(L"Unable to initialise hash\n");
341 efi_status = EFI_OUT_OF_RESOURCES;
342 goto done;
343 }
344
345 /* Hash start to checksum */
346 hashbase = data;
347 hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
348 hashbase;
349 check_size(data, datasize_in, hashbase, hashsize);
350
351 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
352 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
353 perror(L"Unable to generate hash\n");
354 efi_status = EFI_OUT_OF_RESOURCES;
355 goto done;
356 }
357
358 /* Hash post-checksum to start of certificate table */
359 hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
360 sizeof (int);
361 hashsize = (char *)context->SecDir - hashbase;
362 check_size(data, datasize_in, hashbase, hashsize);
363
364 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
365 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
366 perror(L"Unable to generate hash\n");
367 efi_status = EFI_OUT_OF_RESOURCES;
368 goto done;
369 }
370
371 /* Hash end of certificate table to end of image header */
372 EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1;
373 hashbase = (char *)dd;
374 hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
375 if (hashsize > datasize_in) {
376 perror(L"Data Directory size %d is invalid\n", hashsize);
377 efi_status = EFI_INVALID_PARAMETER;
378 goto done;
379 }
380 check_size(data, datasize_in, hashbase, hashsize);
381
382 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
383 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
384 perror(L"Unable to generate hash\n");
385 efi_status = EFI_OUT_OF_RESOURCES;
386 goto done;
387 }
388
389 /* Sort sections */
390 SumOfBytesHashed = context->SizeOfHeaders;
391
392 /*
393 * XXX Do we need this here, or is it already done in all cases?
394 */
395 if (context->NumberOfSections == 0 ||
396 context->FirstSection == NULL) {
397 uint16_t opthdrsz;
398 uint64_t addr;
399 uint16_t nsections;
400 EFI_IMAGE_SECTION_HEADER *section0, *sectionN;
401
402 nsections = context->PEHdr->Pe32.FileHeader.NumberOfSections;
403 opthdrsz = context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
404
405 /* Validate section0 is within image */
406 addr = PEHdr_offset + sizeof(UINT32)
407 + sizeof(EFI_IMAGE_FILE_HEADER)
408 + opthdrsz;
409 section0 = ImageAddress(data, datasize, addr);
410 if (!section0) {
411 perror(L"Malformed file header.\n");
412 perror(L"Image address for Section Header 0 is 0x%016llx\n",
413 addr);
414 perror(L"File size is 0x%016llx\n", datasize);
415 efi_status = EFI_INVALID_PARAMETER;
416 goto done;
417 }
418
419 /* Validate sectionN is within image */
420 addr += (uint64_t)(intptr_t)&section0[nsections-1] -
421 (uint64_t)(intptr_t)section0;
422 sectionN = ImageAddress(data, datasize, addr);
423 if (!sectionN) {
424 perror(L"Malformed file header.\n");
425 perror(L"Image address for Section Header %d is 0x%016llx\n",
426 nsections - 1, addr);
427 perror(L"File size is 0x%016llx\n", datasize);
428 efi_status = EFI_INVALID_PARAMETER;
429 goto done;
430 }
431
432 context->NumberOfSections = nsections;
433 context->FirstSection = section0;
434 }
435
436 /*
437 * Allocate a new section table so we can sort them without
438 * modifying the image.
439 */
440 SectionHeader = AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER)
441 * context->NumberOfSections);
442 if (SectionHeader == NULL) {
443 perror(L"Unable to allocate section header\n");
444 efi_status = EFI_OUT_OF_RESOURCES;
445 goto done;
446 }
447
448 /*
449 * Validate section locations and sizes, and sort the table into
450 * our newly allocated header table
451 */
452 SumOfSectionBytes = 0;
453 Section = context->FirstSection;
454 for (index = 0; index < context->NumberOfSections; index++) {
455 EFI_IMAGE_SECTION_HEADER *SectionPtr;
456 char *base;
457 size_t size;
458
459 efi_status = get_section_vma(index, data, datasize, context,
460 &base, &size, &SectionPtr);
461 if (efi_status == EFI_NOT_FOUND)
462 break;
463 if (EFI_ERROR(efi_status)) {
464 perror(L"Malformed section header\n");
465 goto done;
466 }
467
468 /* Validate section size is within image. */
469 if (SectionPtr->SizeOfRawData >
470 datasize - SumOfBytesHashed - SumOfSectionBytes) {
471 perror(L"Malformed section %d size\n", index);
472 efi_status = EFI_INVALID_PARAMETER;
473 goto done;
474 }
475 SumOfSectionBytes += SectionPtr->SizeOfRawData;
476
477 pos = index;
478 while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) {
479 CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
480 pos--;
481 }
482 CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
483 Section += 1;
484
485 }
486
487 /* Hash the sections */
488 for (index = 0; index < context->NumberOfSections; index++) {
489 Section = &SectionHeader[index];
490 if (Section->SizeOfRawData == 0) {
491 continue;
492 }
493
494 hashbase = ImageAddress(data, size, Section->PointerToRawData);
495 if (!hashbase) {
496 perror(L"Malformed section header\n");
497 efi_status = EFI_INVALID_PARAMETER;
498 goto done;
499 }
500
501 /* Verify hashsize within image. */
502 if (Section->SizeOfRawData >
503 datasize - Section->PointerToRawData) {
504 perror(L"Malformed section raw size %d\n", index);
505 efi_status = EFI_INVALID_PARAMETER;
506 goto done;
507 }
508 hashsize = (unsigned int) Section->SizeOfRawData;
509 check_size(data, datasize_in, hashbase, hashsize);
510
511 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
512 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
513 perror(L"Unable to generate hash\n");
514 efi_status = EFI_OUT_OF_RESOURCES;
515 goto done;
516 }
517 SumOfBytesHashed += Section->SizeOfRawData;
518 }
519
520 /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */
521 if (datasize > SumOfBytesHashed && context->SecDir->Size) {
522 hashbase = data + SumOfBytesHashed;
523 hashsize = datasize - context->SecDir->Size - SumOfBytesHashed;
524
525 if ((datasize - SumOfBytesHashed < context->SecDir->Size) ||
526 (SumOfBytesHashed + hashsize != context->SecDir->VirtualAddress)) {
527 perror(L"Malformed binary after Attribute Certificate Table\n");
528 console_print(L"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n",
529 datasize, SumOfBytesHashed, context->SecDir->Size);
530 console_print(L"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n",
531 hashsize, context->SecDir->VirtualAddress);
532 efi_status = EFI_INVALID_PARAMETER;
533 goto done;
534 }
535 check_size(data, datasize_in, hashbase, hashsize);
536
537 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
538 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
539 perror(L"Unable to generate hash\n");
540 efi_status = EFI_OUT_OF_RESOURCES;
541 goto done;
542 }
543
544 #if 1
545 }
546 #else // we have to migrate to doing this later :/
547 SumOfBytesHashed += hashsize;
548 }
549
550 /* Hash all remaining data */
551 if (datasize > SumOfBytesHashed) {
552 hashbase = data + SumOfBytesHashed;
553 hashsize = datasize - SumOfBytesHashed;
554
555 check_size(data, datasize_in, hashbase, hashsize);
556
557 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
558 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
559 perror(L"Unable to generate hash\n");
560 efi_status = EFI_OUT_OF_RESOURCES;
561 goto done;
562 }
563
564 SumOfBytesHashed += hashsize;
565 }
566 #endif
567
568 if (!(Sha256Final(sha256ctx, sha256hash)) ||
569 !(Sha1Final(sha1ctx, sha1hash))) {
570 perror(L"Unable to finalise hash\n");
571 efi_status = EFI_OUT_OF_RESOURCES;
572 goto done;
573 }
574
575 dprint(L"sha1 authenticode hash:\n");
576 dhexdumpat(sha1hash, SHA1_DIGEST_SIZE, 0);
577 dprint(L"sha256 authenticode hash:\n");
578 dhexdumpat(sha256hash, SHA256_DIGEST_SIZE, 0);
579
580 done:
581 if (SectionHeader)
582 FreePool(SectionHeader);
583 if (sha1ctx)
584 FreePool(sha1ctx);
585 if (sha256ctx)
586 FreePool(sha256ctx);
587
588 return efi_status;
589 }
590
591 /* here's a chart:
592 * i686 x86_64 aarch64
593 * 64-on-64: nyet yes yes
594 * 64-on-32: nyet yes nyet
595 * 32-on-32: yes yes no
596 */
597 static int
598 allow_64_bit(void)
599 {
600 #if defined(__x86_64__) || defined(__aarch64__)
601 return 1;
602 #elif defined(__i386__) || defined(__i686__)
603 /* Right now blindly assuming the kernel will correctly detect this
604 * and /halt the system/ if you're not really on a 64-bit cpu */
605 if (in_protocol)
606 return 1;
607 return 0;
608 #else /* assuming everything else is 32-bit... */
609 return 0;
610 #endif
611 }
612
613 static int
614 allow_32_bit(void)
615 {
616 #if defined(__x86_64__)
617 #if defined(ALLOW_32BIT_KERNEL_ON_X64)
618 if (in_protocol)
619 return 1;
620 return 0;
621 #else
622 return 0;
623 #endif
624 #elif defined(__i386__) || defined(__i686__)
625 return 1;
626 #elif defined(__aarch64__)
627 return 0;
628 #else /* assuming everything else is 32-bit... */
629 return 1;
630 #endif
631 }
632
633 static int
634 image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
635 {
636 /* .Magic is the same offset in all cases */
637 if (PEHdr->Pe32Plus.OptionalHeader.Magic
638 == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
639 return 1;
640 return 0;
641 }
642
643 static const UINT16 machine_type =
644 #if defined(__x86_64__)
645 IMAGE_FILE_MACHINE_X64;
646 #elif defined(__aarch64__)
647 IMAGE_FILE_MACHINE_ARM64;
648 #elif defined(__arm__)
649 IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
650 #elif defined(__i386__) || defined(__i486__) || defined(__i686__)
651 IMAGE_FILE_MACHINE_I386;
652 #elif defined(__ia64__)
653 IMAGE_FILE_MACHINE_IA64;
654 #else
655 #error this architecture is not supported by shim
656 #endif
657
658 static int
659 image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
660 {
661 /* If the machine type doesn't match the binary, bail, unless
662 * we're in an allowed 64-on-32 scenario */
663 if (PEHdr->Pe32.FileHeader.Machine != machine_type) {
664 if (!(machine_type == IMAGE_FILE_MACHINE_I386 &&
665 PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 &&
666 allow_64_bit())) {
667 return 0;
668 }
669 }
670
671 /* If it's not a header type we recognize at all, bail */
672 switch (PEHdr->Pe32Plus.OptionalHeader.Magic) {
673 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
674 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
675 break;
676 default:
677 return 0;
678 }
679
680 /* and now just check for general 64-vs-32 compatibility */
681 if (image_is_64_bit(PEHdr)) {
682 if (allow_64_bit())
683 return 1;
684 } else {
685 if (allow_32_bit())
686 return 1;
687 }
688 return 0;
689 }
690
691 /*
692 * Read the binary header and grab appropriate information from it
693 */
694 EFI_STATUS
695 read_header(void *data, unsigned int datasize,
696 PE_COFF_LOADER_IMAGE_CONTEXT *context)
697 {
698 EFI_IMAGE_DOS_HEADER *DosHdr = data;
699 EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
700 unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
701 unsigned long FileAlignment = 0;
702
703 if (datasize < sizeof (PEHdr->Pe32)) {
704 perror(L"Invalid image\n");
705 return EFI_UNSUPPORTED;
706 }
707
708 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
709 PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
710
711 if (!image_is_loadable(PEHdr)) {
712 perror(L"Platform does not support this image\n");
713 return EFI_UNSUPPORTED;
714 }
715
716 if (image_is_64_bit(PEHdr)) {
717 context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
718 context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
719 context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
720 context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
721 FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
722 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
723 } else {
724 context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
725 context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
726 context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
727 context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment;
728 FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
729 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
730 }
731
732 if (FileAlignment % 2 != 0) {
733 perror(L"File Alignment is invalid (%d)\n", FileAlignment);
734 return EFI_UNSUPPORTED;
735 }
736 if (FileAlignment == 0)
737 FileAlignment = 0x200;
738 if (context->SectionAlignment == 0)
739 context->SectionAlignment = PAGE_SIZE;
740 if (context->SectionAlignment < FileAlignment)
741 context->SectionAlignment = FileAlignment;
742
743 context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
744
745 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
746 perror(L"Image header too small\n");
747 return EFI_UNSUPPORTED;
748 }
749
750 HeaderWithoutDataDir = OptHeaderSize
751 - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
752 if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
753 context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
754 perror(L"Image header overflows data directory\n");
755 return EFI_UNSUPPORTED;
756 }
757
758 SectionHeaderOffset = DosHdr->e_lfanew
759 + sizeof (UINT32)
760 + sizeof (EFI_IMAGE_FILE_HEADER)
761 + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
762 if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
763 <= context->NumberOfSections) {
764 perror(L"Image sections overflow image size\n");
765 return EFI_UNSUPPORTED;
766 }
767
768 if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
769 < (UINT32)context->NumberOfSections) {
770 perror(L"Image sections overflow section headers\n");
771 return EFI_UNSUPPORTED;
772 }
773
774 if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) {
775 perror(L"Invalid image\n");
776 return EFI_UNSUPPORTED;
777 }
778
779 if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
780 perror(L"Unsupported image type\n");
781 return EFI_UNSUPPORTED;
782 }
783
784 if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
785 perror(L"Unsupported image - Relocations have been stripped\n");
786 return EFI_UNSUPPORTED;
787 }
788
789 context->PEHdr = PEHdr;
790
791 if (image_is_64_bit(PEHdr)) {
792 context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
793 context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
794 context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
795 context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
796 } else {
797 context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
798 context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
799 context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
800 context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
801 }
802
803 context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
804
805 if (context->ImageSize < context->SizeOfHeaders) {
806 perror(L"Invalid image\n");
807 return EFI_UNSUPPORTED;
808 }
809
810 if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) >
811 (datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) {
812 perror(L"Invalid image\n");
813 return EFI_UNSUPPORTED;
814 }
815
816 if (context->SecDir->VirtualAddress > datasize ||
817 (context->SecDir->VirtualAddress == datasize &&
818 context->SecDir->Size > 0)) {
819 perror(L"Malformed security header\n");
820 return EFI_INVALID_PARAMETER;
821 }
822 return EFI_SUCCESS;
823 }
824
825 EFI_STATUS
826 handle_sbat(char *SBATBase, size_t SBATSize)
827 {
828 unsigned int i;
829 EFI_STATUS efi_status;
830 size_t n;
831 struct sbat_section_entry **entries = NULL;
832 char *sbat_data;
833 size_t sbat_size;
834
835 if (list_empty(&sbat_var))
836 return EFI_SUCCESS;
837
838 if (SBATBase == NULL || SBATSize == 0) {
839 dprint(L"No .sbat section data\n");
840 return EFI_SECURITY_VIOLATION;
841 }
842
843 sbat_size = SBATSize + 1;
844 sbat_data = AllocatePool(sbat_size);
845 if (!sbat_data) {
846 console_print(L"Failed to allocate .sbat section buffer\n");
847 return EFI_OUT_OF_RESOURCES;
848 }
849 CopyMem(sbat_data, SBATBase, SBATSize);
850 sbat_data[SBATSize] = '\0';
851
852 efi_status = parse_sbat_section(sbat_data, sbat_size, &n, &entries);
853 if (EFI_ERROR(efi_status)) {
854 perror(L"Could not parse .sbat section data: %r\n", efi_status);
855 goto err;
856 }
857
858 dprint(L"SBAT section data\n");
859 for (i = 0; i < n; i++) {
860 dprint(L"%a, %a, %a, %a, %a, %a\n",
861 entries[i]->component_name,
862 entries[i]->component_generation,
863 entries[i]->vendor_name,
864 entries[i]->vendor_package_name,
865 entries[i]->vendor_version,
866 entries[i]->vendor_url);
867 }
868
869 efi_status = verify_sbat(n, entries);
870
871 cleanup_sbat_section_entries(n, entries);
872
873 err:
874 FreePool(sbat_data);
875
876 return efi_status;
877 }
878
879 /*
880 * Once the image has been loaded it needs to be validated and relocated
881 */
882 EFI_STATUS
883 handle_image (void *data, unsigned int datasize,
884 EFI_LOADED_IMAGE *li,
885 EFI_IMAGE_ENTRY_POINT *entry_point,
886 EFI_PHYSICAL_ADDRESS *alloc_address,
887 UINTN *alloc_pages)
888 {
889 EFI_STATUS efi_status;
890 char *buffer;
891 int i;
892 EFI_IMAGE_SECTION_HEADER *Section;
893 char *base, *end;
894 PE_COFF_LOADER_IMAGE_CONTEXT context;
895 unsigned int alignment, alloc_size;
896 int found_entry_point = 0;
897 UINT8 sha1hash[SHA1_DIGEST_SIZE];
898 UINT8 sha256hash[SHA256_DIGEST_SIZE];
899
900 /*
901 * The binary header contains relevant context and section pointers
902 */
903 efi_status = read_header(data, datasize, &context);
904 if (EFI_ERROR(efi_status)) {
905 perror(L"Failed to read header: %r\n", efi_status);
906 return efi_status;
907 }
908
909 /*
910 * We only need to verify the binary if we're in secure mode
911 */
912 efi_status = generate_hash(data, datasize, &context, sha256hash,
913 sha1hash);
914 if (EFI_ERROR(efi_status))
915 return efi_status;
916
917 /* Measure the binary into the TPM */
918 #ifdef REQUIRE_TPM
919 efi_status =
920 #endif
921 tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
922 (EFI_PHYSICAL_ADDRESS)(UINTN)context.ImageAddress,
923 li->FilePath, sha1hash, 4);
924 #ifdef REQUIRE_TPM
925 if (efi_status != EFI_SUCCESS) {
926 return efi_status;
927 }
928 #endif
929
930 /* The spec says, uselessly, of SectionAlignment:
931 * =====
932 * The alignment (in bytes) of sections when they are loaded into
933 * memory. It must be greater than or equal to FileAlignment. The
934 * default is the page size for the architecture.
935 * =====
936 * Which doesn't tell you whose responsibility it is to enforce the
937 * "default", or when. It implies that the value in the field must
938 * be > FileAlignment (also poorly defined), but it appears visual
939 * studio will happily write 512 for FileAlignment (its default) and
940 * 0 for SectionAlignment, intending to imply PAGE_SIZE.
941 *
942 * We only support one page size, so if it's zero, nerf it to 4096.
943 */
944 alignment = context.SectionAlignment;
945 if (!alignment)
946 alignment = 4096;
947
948 alloc_size = ALIGN_VALUE(context.ImageSize + context.SectionAlignment,
949 PAGE_SIZE);
950 *alloc_pages = alloc_size / PAGE_SIZE;
951
952 efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
953 *alloc_pages, alloc_address);
954 if (EFI_ERROR(efi_status)) {
955 perror(L"Failed to allocate image buffer\n");
956 return EFI_OUT_OF_RESOURCES;
957 }
958
959 buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment);
960
961 CopyMem(buffer, data, context.SizeOfHeaders);
962
963 *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
964 if (!*entry_point) {
965 perror(L"Entry point is invalid\n");
966 gBS->FreePages(*alloc_address, *alloc_pages);
967 return EFI_UNSUPPORTED;
968 }
969
970 char *RelocBase, *RelocBaseEnd;
971 /*
972 * These are relative virtual addresses, so we have to check them
973 * against the image size, not the data size.
974 */
975 RelocBase = ImageAddress(buffer, context.ImageSize,
976 context.RelocDir->VirtualAddress);
977 /*
978 * RelocBaseEnd here is the address of the last byte of the table
979 */
980 RelocBaseEnd = ImageAddress(buffer, context.ImageSize,
981 context.RelocDir->VirtualAddress +
982 context.RelocDir->Size - 1);
983
984 EFI_IMAGE_SECTION_HEADER *RelocSection = NULL;
985
986 char *SBATBase = NULL;
987 size_t SBATSize = 0;
988
989 /*
990 * Copy the executable's sections to their desired offsets
991 */
992 Section = context.FirstSection;
993 for (i = 0; i < context.NumberOfSections; i++, Section++) {
994 /* Don't try to copy discardable sections with zero size */
995 if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
996 !Section->Misc.VirtualSize)
997 continue;
998
999 base = ImageAddress (buffer, context.ImageSize,
1000 Section->VirtualAddress);
1001 end = ImageAddress (buffer, context.ImageSize,
1002 Section->VirtualAddress
1003 + Section->Misc.VirtualSize - 1);
1004
1005 if (end < base) {
1006 perror(L"Section %d has negative size\n", i);
1007 gBS->FreePages(*alloc_address, *alloc_pages);
1008 return EFI_UNSUPPORTED;
1009 }
1010
1011 if (Section->VirtualAddress <= context.EntryPoint &&
1012 (Section->VirtualAddress + Section->SizeOfRawData - 1)
1013 > context.EntryPoint)
1014 found_entry_point++;
1015
1016 /* We do want to process .reloc, but it's often marked
1017 * discardable, so we don't want to memcpy it. */
1018 if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) {
1019 if (RelocSection) {
1020 perror(L"Image has multiple relocation sections\n");
1021 return EFI_UNSUPPORTED;
1022 }
1023 /* If it has nonzero sizes, and our bounds check
1024 * made sense, and the VA and size match RelocDir's
1025 * versions, then we believe in this section table. */
1026 if (Section->SizeOfRawData &&
1027 Section->Misc.VirtualSize &&
1028 base && end &&
1029 RelocBase == base &&
1030 RelocBaseEnd == end) {
1031 RelocSection = Section;
1032 }
1033 } else if (CompareMem(Section->Name, ".sbat\0\0\0", 8) == 0) {
1034 if (SBATBase || SBATSize) {
1035 perror(L"Image has multiple SBAT sections\n");
1036 return EFI_UNSUPPORTED;
1037 }
1038
1039 if (Section->NumberOfRelocations != 0 ||
1040 Section->PointerToRelocations != 0) {
1041 perror(L"SBAT section has relocations\n");
1042 return EFI_UNSUPPORTED;
1043 }
1044
1045 /* The virtual size corresponds to the size of the SBAT
1046 * metadata and isn't necessarily a multiple of the file
1047 * alignment. The on-disk size is a multiple of the file
1048 * alignment and is zero padded. Make sure that the
1049 * on-disk size is at least as large as virtual size,
1050 * and ignore the section if it isn't. */
1051 if (Section->SizeOfRawData &&
1052 Section->SizeOfRawData >= Section->Misc.VirtualSize &&
1053 base && end) {
1054 SBATBase = base;
1055 /* +1 because of size vs last byte location */
1056 SBATSize = end - base + 1;
1057 dprint(L"sbat section base:0x%lx size:0x%lx\n",
1058 SBATBase, SBATSize);
1059 }
1060 }
1061
1062 if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) {
1063 continue;
1064 }
1065
1066 if (!base) {
1067 perror(L"Section %d has invalid base address\n", i);
1068 return EFI_UNSUPPORTED;
1069 }
1070 if (!end) {
1071 perror(L"Section %d has zero size\n", i);
1072 return EFI_UNSUPPORTED;
1073 }
1074
1075 if (!(Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) &&
1076 (Section->VirtualAddress < context.SizeOfHeaders ||
1077 Section->PointerToRawData < context.SizeOfHeaders)) {
1078 perror(L"Section %d is inside image headers\n", i);
1079 return EFI_UNSUPPORTED;
1080 }
1081
1082 if (Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
1083 ZeroMem(base, Section->Misc.VirtualSize);
1084 } else {
1085 if (Section->PointerToRawData < context.SizeOfHeaders) {
1086 perror(L"Section %d is inside image headers\n", i);
1087 return EFI_UNSUPPORTED;
1088 }
1089
1090 if (Section->SizeOfRawData > 0)
1091 CopyMem(base, data + Section->PointerToRawData,
1092 Section->SizeOfRawData);
1093
1094 if (Section->SizeOfRawData < Section->Misc.VirtualSize)
1095 ZeroMem(base + Section->SizeOfRawData,
1096 Section->Misc.VirtualSize - Section->SizeOfRawData);
1097 }
1098 }
1099
1100 if (secure_mode ()) {
1101 efi_status = handle_sbat(SBATBase, SBATSize);
1102
1103 if (!EFI_ERROR(efi_status))
1104 efi_status = verify_buffer(data, datasize,
1105 &context, sha256hash, sha1hash);
1106
1107 if (EFI_ERROR(efi_status)) {
1108 if (verbose)
1109 console_print(L"Verification failed: %r\n", efi_status);
1110 else
1111 console_error(L"Verification failed", efi_status);
1112 return efi_status;
1113 } else {
1114 if (verbose)
1115 console_print(L"Verification succeeded\n");
1116 }
1117 }
1118
1119 if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1120 perror(L"Image has no relocation entry\n");
1121 FreePool(buffer);
1122 return EFI_UNSUPPORTED;
1123 }
1124
1125 if (context.RelocDir->Size && RelocSection) {
1126 /*
1127 * Run the relocation fixups
1128 */
1129 efi_status = relocate_coff(&context, RelocSection, data,
1130 buffer);
1131
1132 if (EFI_ERROR(efi_status)) {
1133 perror(L"Relocation failed: %r\n", efi_status);
1134 FreePool(buffer);
1135 return efi_status;
1136 }
1137 }
1138
1139 /*
1140 * grub needs to know its location and size in memory, so fix up
1141 * the loaded image protocol values
1142 */
1143 li->ImageBase = buffer;
1144 li->ImageSize = context.ImageSize;
1145
1146 /* Pass the load options to the second stage loader */
1147 if ( load_options ) {
1148 li->LoadOptions = load_options;
1149 li->LoadOptionsSize = load_options_size;
1150 }
1151
1152 if (!found_entry_point) {
1153 perror(L"Entry point is not within sections\n");
1154 return EFI_UNSUPPORTED;
1155 }
1156 if (found_entry_point > 1) {
1157 perror(L"%d sections contain entry point\n");
1158 return EFI_UNSUPPORTED;
1159 }
1160
1161 return EFI_SUCCESS;
1162 }
1163
1164 // vim:fenc=utf-8:tw=75:noet