]> git.proxmox.com Git - efi-boot-shim.git/blob - pe.c
New upstream version 15.6
[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,
302 PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash,
303 UINT8 *sha1hash)
304 {
305 unsigned int sha256ctxsize, sha1ctxsize;
306 void *sha256ctx = NULL, *sha1ctx = NULL;
307 char *hashbase;
308 unsigned int hashsize;
309 unsigned int SumOfBytesHashed, SumOfSectionBytes;
310 unsigned int index, pos;
311 EFI_IMAGE_SECTION_HEADER *Section;
312 EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
313 EFI_STATUS efi_status = EFI_SUCCESS;
314 EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
315 unsigned int PEHdr_offset = 0;
316
317 if (datasize <= sizeof (*DosHdr) ||
318 DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
319 perror(L"Invalid signature\n");
320 return EFI_INVALID_PARAMETER;
321 }
322 PEHdr_offset = DosHdr->e_lfanew;
323
324 sha256ctxsize = Sha256GetContextSize();
325 sha256ctx = AllocatePool(sha256ctxsize);
326
327 sha1ctxsize = Sha1GetContextSize();
328 sha1ctx = AllocatePool(sha1ctxsize);
329
330 if (!sha256ctx || !sha1ctx) {
331 perror(L"Unable to allocate memory for hash context\n");
332 return EFI_OUT_OF_RESOURCES;
333 }
334
335 if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) {
336 perror(L"Unable to initialise hash\n");
337 efi_status = EFI_OUT_OF_RESOURCES;
338 goto done;
339 }
340
341 /* Hash start to checksum */
342 hashbase = data;
343 hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
344 hashbase;
345 check_size(data, datasize, hashbase, hashsize);
346
347 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
348 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
349 perror(L"Unable to generate hash\n");
350 efi_status = EFI_OUT_OF_RESOURCES;
351 goto done;
352 }
353
354 /* Hash post-checksum to start of certificate table */
355 hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
356 sizeof (int);
357 hashsize = (char *)context->SecDir - hashbase;
358 check_size(data, datasize, hashbase, hashsize);
359
360 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
361 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
362 perror(L"Unable to generate hash\n");
363 efi_status = EFI_OUT_OF_RESOURCES;
364 goto done;
365 }
366
367 /* Hash end of certificate table to end of image header */
368 EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1;
369 hashbase = (char *)dd;
370 hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
371 if (hashsize > datasize) {
372 perror(L"Data Directory size %d is invalid\n", hashsize);
373 efi_status = EFI_INVALID_PARAMETER;
374 goto done;
375 }
376 check_size(data, datasize, hashbase, hashsize);
377
378 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
379 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
380 perror(L"Unable to generate hash\n");
381 efi_status = EFI_OUT_OF_RESOURCES;
382 goto done;
383 }
384
385 /* Sort sections */
386 SumOfBytesHashed = context->SizeOfHeaders;
387
388 /*
389 * XXX Do we need this here, or is it already done in all cases?
390 */
391 if (context->NumberOfSections == 0 ||
392 context->FirstSection == NULL) {
393 uint16_t opthdrsz;
394 uint64_t addr;
395 uint16_t nsections;
396 EFI_IMAGE_SECTION_HEADER *section0, *sectionN;
397
398 nsections = context->PEHdr->Pe32.FileHeader.NumberOfSections;
399 opthdrsz = context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
400
401 /* Validate section0 is within image */
402 addr = PEHdr_offset + sizeof(UINT32)
403 + sizeof(EFI_IMAGE_FILE_HEADER)
404 + opthdrsz;
405 section0 = ImageAddress(data, datasize, addr);
406 if (!section0) {
407 perror(L"Malformed file header.\n");
408 perror(L"Image address for Section Header 0 is 0x%016llx\n",
409 addr);
410 perror(L"File size is 0x%016llx\n", datasize);
411 efi_status = EFI_INVALID_PARAMETER;
412 goto done;
413 }
414
415 /* Validate sectionN is within image */
416 addr += (uint64_t)(intptr_t)&section0[nsections-1] -
417 (uint64_t)(intptr_t)section0;
418 sectionN = ImageAddress(data, datasize, addr);
419 if (!sectionN) {
420 perror(L"Malformed file header.\n");
421 perror(L"Image address for Section Header %d is 0x%016llx\n",
422 nsections - 1, addr);
423 perror(L"File size is 0x%016llx\n", datasize);
424 efi_status = EFI_INVALID_PARAMETER;
425 goto done;
426 }
427
428 context->NumberOfSections = nsections;
429 context->FirstSection = section0;
430 }
431
432 /*
433 * Allocate a new section table so we can sort them without
434 * modifying the image.
435 */
436 SectionHeader = AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER)
437 * context->NumberOfSections);
438 if (SectionHeader == NULL) {
439 perror(L"Unable to allocate section header\n");
440 efi_status = EFI_OUT_OF_RESOURCES;
441 goto done;
442 }
443
444 /*
445 * Validate section locations and sizes, and sort the table into
446 * our newly allocated header table
447 */
448 SumOfSectionBytes = 0;
449 Section = context->FirstSection;
450 for (index = 0; index < context->NumberOfSections; index++) {
451 EFI_IMAGE_SECTION_HEADER *SectionPtr;
452 char *base;
453 size_t size;
454
455 efi_status = get_section_vma(index, data, datasize, context,
456 &base, &size, &SectionPtr);
457 if (efi_status == EFI_NOT_FOUND)
458 break;
459 if (EFI_ERROR(efi_status)) {
460 perror(L"Malformed section header\n");
461 goto done;
462 }
463
464 /* Validate section size is within image. */
465 if (SectionPtr->SizeOfRawData >
466 datasize - SumOfBytesHashed - SumOfSectionBytes) {
467 perror(L"Malformed section %d size\n", index);
468 efi_status = EFI_INVALID_PARAMETER;
469 goto done;
470 }
471 SumOfSectionBytes += SectionPtr->SizeOfRawData;
472
473 pos = index;
474 while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) {
475 CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
476 pos--;
477 }
478 CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
479 Section += 1;
480
481 }
482
483 /* Hash the sections */
484 for (index = 0; index < context->NumberOfSections; index++) {
485 Section = &SectionHeader[index];
486 if (Section->SizeOfRawData == 0) {
487 continue;
488 }
489
490 hashbase = ImageAddress(data, datasize,
491 Section->PointerToRawData);
492 if (!hashbase) {
493 perror(L"Malformed section header\n");
494 efi_status = EFI_INVALID_PARAMETER;
495 goto done;
496 }
497
498 /* Verify hashsize within image. */
499 if (Section->SizeOfRawData >
500 datasize - Section->PointerToRawData) {
501 perror(L"Malformed section raw size %d\n", index);
502 efi_status = EFI_INVALID_PARAMETER;
503 goto done;
504 }
505 hashsize = (unsigned int) Section->SizeOfRawData;
506 check_size(data, datasize, hashbase, hashsize);
507
508 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
509 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
510 perror(L"Unable to generate hash\n");
511 efi_status = EFI_OUT_OF_RESOURCES;
512 goto done;
513 }
514 SumOfBytesHashed += Section->SizeOfRawData;
515 }
516
517 /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */
518 if (datasize > SumOfBytesHashed && context->SecDir->Size) {
519 hashbase = data + SumOfBytesHashed;
520 hashsize = datasize - context->SecDir->Size - SumOfBytesHashed;
521
522 if ((datasize - SumOfBytesHashed < context->SecDir->Size) ||
523 (SumOfBytesHashed + hashsize != context->SecDir->VirtualAddress)) {
524 perror(L"Malformed binary after Attribute Certificate Table\n");
525 console_print(L"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n",
526 datasize, SumOfBytesHashed, context->SecDir->Size);
527 console_print(L"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n",
528 hashsize, context->SecDir->VirtualAddress);
529 efi_status = EFI_INVALID_PARAMETER;
530 goto done;
531 }
532 check_size(data, datasize, hashbase, hashsize);
533
534 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
535 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
536 perror(L"Unable to generate hash\n");
537 efi_status = EFI_OUT_OF_RESOURCES;
538 goto done;
539 }
540
541 #if 1
542 }
543 #else // we have to migrate to doing this later :/
544 SumOfBytesHashed += hashsize;
545 }
546
547 /* Hash all remaining data */
548 if (datasize > SumOfBytesHashed) {
549 hashbase = data + SumOfBytesHashed;
550 hashsize = datasize - SumOfBytesHashed;
551
552 check_size(data, datasize, hashbase, hashsize);
553
554 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
555 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
556 perror(L"Unable to generate hash\n");
557 efi_status = EFI_OUT_OF_RESOURCES;
558 goto done;
559 }
560
561 SumOfBytesHashed += hashsize;
562 }
563 #endif
564
565 if (!(Sha256Final(sha256ctx, sha256hash)) ||
566 !(Sha1Final(sha1ctx, sha1hash))) {
567 perror(L"Unable to finalise hash\n");
568 efi_status = EFI_OUT_OF_RESOURCES;
569 goto done;
570 }
571
572 dprint(L"sha1 authenticode hash:\n");
573 dhexdumpat(sha1hash, SHA1_DIGEST_SIZE, 0);
574 dprint(L"sha256 authenticode hash:\n");
575 dhexdumpat(sha256hash, SHA256_DIGEST_SIZE, 0);
576
577 done:
578 if (SectionHeader)
579 FreePool(SectionHeader);
580 if (sha1ctx)
581 FreePool(sha1ctx);
582 if (sha256ctx)
583 FreePool(sha256ctx);
584
585 return efi_status;
586 }
587
588 /* here's a chart:
589 * i686 x86_64 aarch64
590 * 64-on-64: nyet yes yes
591 * 64-on-32: nyet yes nyet
592 * 32-on-32: yes yes no
593 */
594 static int
595 allow_64_bit(void)
596 {
597 #if defined(__x86_64__) || defined(__aarch64__)
598 return 1;
599 #elif defined(__i386__) || defined(__i686__)
600 /* Right now blindly assuming the kernel will correctly detect this
601 * and /halt the system/ if you're not really on a 64-bit cpu */
602 if (in_protocol)
603 return 1;
604 return 0;
605 #else /* assuming everything else is 32-bit... */
606 return 0;
607 #endif
608 }
609
610 static int
611 allow_32_bit(void)
612 {
613 #if defined(__x86_64__)
614 #if defined(ALLOW_32BIT_KERNEL_ON_X64)
615 if (in_protocol)
616 return 1;
617 return 0;
618 #else
619 return 0;
620 #endif
621 #elif defined(__i386__) || defined(__i686__)
622 return 1;
623 #elif defined(__aarch64__)
624 return 0;
625 #else /* assuming everything else is 32-bit... */
626 return 1;
627 #endif
628 }
629
630 static int
631 image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
632 {
633 /* .Magic is the same offset in all cases */
634 if (PEHdr->Pe32Plus.OptionalHeader.Magic
635 == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
636 return 1;
637 return 0;
638 }
639
640 static const UINT16 machine_type =
641 #if defined(__x86_64__)
642 IMAGE_FILE_MACHINE_X64;
643 #elif defined(__aarch64__)
644 IMAGE_FILE_MACHINE_ARM64;
645 #elif defined(__arm__)
646 IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
647 #elif defined(__i386__) || defined(__i486__) || defined(__i686__)
648 IMAGE_FILE_MACHINE_I386;
649 #elif defined(__ia64__)
650 IMAGE_FILE_MACHINE_IA64;
651 #else
652 #error this architecture is not supported by shim
653 #endif
654
655 static int
656 image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
657 {
658 /* If the machine type doesn't match the binary, bail, unless
659 * we're in an allowed 64-on-32 scenario */
660 if (PEHdr->Pe32.FileHeader.Machine != machine_type) {
661 if (!(machine_type == IMAGE_FILE_MACHINE_I386 &&
662 PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 &&
663 allow_64_bit())) {
664 return 0;
665 }
666 }
667
668 /* If it's not a header type we recognize at all, bail */
669 switch (PEHdr->Pe32Plus.OptionalHeader.Magic) {
670 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
671 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
672 break;
673 default:
674 return 0;
675 }
676
677 /* and now just check for general 64-vs-32 compatibility */
678 if (image_is_64_bit(PEHdr)) {
679 if (allow_64_bit())
680 return 1;
681 } else {
682 if (allow_32_bit())
683 return 1;
684 }
685 return 0;
686 }
687
688 /*
689 * Read the binary header and grab appropriate information from it
690 */
691 EFI_STATUS
692 read_header(void *data, unsigned int datasize,
693 PE_COFF_LOADER_IMAGE_CONTEXT *context)
694 {
695 EFI_IMAGE_DOS_HEADER *DosHdr = data;
696 EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
697 unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
698 unsigned long FileAlignment = 0;
699 UINT16 DllFlags;
700
701 if (datasize < sizeof (PEHdr->Pe32)) {
702 perror(L"Invalid image\n");
703 return EFI_UNSUPPORTED;
704 }
705
706 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
707 PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
708
709 if (!image_is_loadable(PEHdr)) {
710 perror(L"Platform does not support this image\n");
711 return EFI_UNSUPPORTED;
712 }
713
714 if (image_is_64_bit(PEHdr)) {
715 context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
716 context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
717 context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
718 context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
719 FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
720 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
721 } else {
722 context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
723 context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
724 context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
725 context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment;
726 FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
727 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
728 }
729
730 if (FileAlignment % 2 != 0) {
731 perror(L"File Alignment is invalid (%d)\n", FileAlignment);
732 return EFI_UNSUPPORTED;
733 }
734 if (FileAlignment == 0)
735 FileAlignment = 0x200;
736 if (context->SectionAlignment == 0)
737 context->SectionAlignment = PAGE_SIZE;
738 if (context->SectionAlignment < FileAlignment)
739 context->SectionAlignment = FileAlignment;
740
741 context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
742
743 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
744 perror(L"Image header too small\n");
745 return EFI_UNSUPPORTED;
746 }
747
748 HeaderWithoutDataDir = OptHeaderSize
749 - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
750 if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
751 context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
752 perror(L"Image header overflows data directory\n");
753 return EFI_UNSUPPORTED;
754 }
755
756 SectionHeaderOffset = DosHdr->e_lfanew
757 + sizeof (UINT32)
758 + sizeof (EFI_IMAGE_FILE_HEADER)
759 + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
760 if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
761 <= context->NumberOfSections) {
762 perror(L"Image sections overflow image size\n");
763 return EFI_UNSUPPORTED;
764 }
765
766 if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
767 < (UINT32)context->NumberOfSections) {
768 perror(L"Image sections overflow section headers\n");
769 return EFI_UNSUPPORTED;
770 }
771
772 if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) {
773 perror(L"Invalid image\n");
774 return EFI_UNSUPPORTED;
775 }
776
777 if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
778 perror(L"Unsupported image type\n");
779 return EFI_UNSUPPORTED;
780 }
781
782 if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
783 perror(L"Unsupported image - Relocations have been stripped\n");
784 return EFI_UNSUPPORTED;
785 }
786
787 context->PEHdr = PEHdr;
788
789 if (image_is_64_bit(PEHdr)) {
790 context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
791 context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
792 context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
793 context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
794 DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
795 } else {
796 context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
797 context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
798 context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
799 context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
800 DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics;
801 }
802
803 if ((mok_policy & MOK_POLICY_REQUIRE_NX) &&
804 !(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) {
805 perror(L"Policy requires NX, but image does not support NX\n");
806 return EFI_UNSUPPORTED;
807 }
808
809 context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
810
811 if (context->ImageSize < context->SizeOfHeaders) {
812 perror(L"Invalid image\n");
813 return EFI_UNSUPPORTED;
814 }
815
816 if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) >
817 (datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) {
818 perror(L"Invalid image\n");
819 return EFI_UNSUPPORTED;
820 }
821
822 if (context->SecDir->VirtualAddress > datasize ||
823 (context->SecDir->VirtualAddress == datasize &&
824 context->SecDir->Size > 0)) {
825 perror(L"Malformed security header\n");
826 return EFI_INVALID_PARAMETER;
827 }
828 return EFI_SUCCESS;
829 }
830
831 EFI_STATUS
832 verify_sbat_section(char *SBATBase, size_t SBATSize)
833 {
834 unsigned int i;
835 EFI_STATUS efi_status;
836 size_t n;
837 struct sbat_section_entry **entries = NULL;
838 char *sbat_data;
839 size_t sbat_size;
840
841 if (list_empty(&sbat_var))
842 return EFI_SUCCESS;
843
844 if (SBATBase == NULL || SBATSize == 0) {
845 dprint(L"No .sbat section data\n");
846 /*
847 * SBAT is mandatory for binaries loaded by shim, but optional
848 * for binaries loaded outside of shim but verified via the
849 * protocol.
850 */
851 return in_protocol ? EFI_SUCCESS : EFI_SECURITY_VIOLATION;
852 }
853
854 sbat_size = SBATSize + 1;
855 sbat_data = AllocatePool(sbat_size);
856 if (!sbat_data) {
857 console_print(L"Failed to allocate .sbat section buffer\n");
858 return EFI_OUT_OF_RESOURCES;
859 }
860 CopyMem(sbat_data, SBATBase, SBATSize);
861 sbat_data[SBATSize] = '\0';
862
863 efi_status = parse_sbat_section(sbat_data, sbat_size, &n, &entries);
864 if (EFI_ERROR(efi_status)) {
865 perror(L"Could not parse .sbat section data: %r\n", efi_status);
866 goto err;
867 }
868
869 dprint(L"SBAT section data\n");
870 for (i = 0; i < n; i++) {
871 dprint(L"%a, %a, %a, %a, %a, %a\n",
872 entries[i]->component_name,
873 entries[i]->component_generation,
874 entries[i]->vendor_name,
875 entries[i]->vendor_package_name,
876 entries[i]->vendor_version,
877 entries[i]->vendor_url);
878 }
879
880 efi_status = verify_sbat(n, entries);
881
882 cleanup_sbat_section_entries(n, entries);
883
884 err:
885 FreePool(sbat_data);
886
887 return efi_status;
888 }
889
890 static inline uint64_t
891 shim_mem_attrs_to_uefi_mem_attrs (uint64_t attrs)
892 {
893 uint64_t ret = EFI_MEMORY_RP |
894 EFI_MEMORY_RO |
895 EFI_MEMORY_XP;
896
897 if (attrs & MEM_ATTR_R)
898 ret &= ~EFI_MEMORY_RP;
899
900 if (attrs & MEM_ATTR_W)
901 ret &= ~EFI_MEMORY_RO;
902
903 if (attrs & MEM_ATTR_X)
904 ret &= ~EFI_MEMORY_XP;
905
906 return ret;
907 }
908
909 static inline uint64_t
910 uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs)
911 {
912 uint64_t ret = MEM_ATTR_R |
913 MEM_ATTR_W |
914 MEM_ATTR_X;
915
916 if (attrs & EFI_MEMORY_RP)
917 ret &= ~MEM_ATTR_R;
918
919 if (attrs & EFI_MEMORY_RO)
920 ret &= ~MEM_ATTR_W;
921
922 if (attrs & EFI_MEMORY_XP)
923 ret &= ~MEM_ATTR_X;
924
925 return ret;
926 }
927
928 static EFI_STATUS
929 get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs)
930 {
931 EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL;
932 EFI_PHYSICAL_ADDRESS physaddr = addr;
933 EFI_STATUS efi_status;
934
935 efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID,
936 (VOID **)&proto);
937 if (EFI_ERROR(efi_status) || !proto)
938 return efi_status;
939
940 if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) {
941 dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n",
942 __func__, (unsigned long long)physaddr,
943 (unsigned long long)(physaddr+size-1),
944 attrs);
945 return EFI_SUCCESS;
946 }
947
948 efi_status = proto->GetMemoryAttributes(proto, physaddr, size, attrs);
949 *attrs = uefi_mem_attrs_to_shim_mem_attrs (*attrs);
950
951 return efi_status;
952 }
953
954 static EFI_STATUS
955 update_mem_attrs(uintptr_t addr, uint64_t size,
956 uint64_t set_attrs, uint64_t clear_attrs)
957 {
958 EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL;
959 EFI_PHYSICAL_ADDRESS physaddr = addr;
960 EFI_STATUS efi_status, ret;
961 uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
962
963 efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID,
964 (VOID **)&proto);
965 if (EFI_ERROR(efi_status) || !proto)
966 return efi_status;
967
968 efi_status = get_mem_attrs (addr, size, &before);
969 if (EFI_ERROR(efi_status))
970 dprint(L"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n",
971 (unsigned long long)addr, (unsigned long long)size,
972 &before, efi_status);
973
974 if (physaddr & 0xfff || size & 0xfff || size == 0) {
975 dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n",
976 __func__, (unsigned long long)physaddr,
977 (unsigned long long)(physaddr + size - 1),
978 (unsigned long long)size,
979 (set_attrs & MEM_ATTR_R) ? "r" : "",
980 (set_attrs & MEM_ATTR_W) ? "w" : "",
981 (set_attrs & MEM_ATTR_X) ? "x" : "",
982 (clear_attrs & MEM_ATTR_R) ? "r" : "",
983 (clear_attrs & MEM_ATTR_W) ? "w" : "",
984 (clear_attrs & MEM_ATTR_X) ? "x" : "");
985 return 0;
986 }
987
988 uefi_set_attrs = shim_mem_attrs_to_uefi_mem_attrs (set_attrs);
989 dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs);
990 uefi_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs (clear_attrs);
991 dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
992 efi_status = EFI_SUCCESS;
993 if (uefi_set_attrs)
994 efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs);
995 if (!EFI_ERROR(efi_status) && uefi_clear_attrs)
996 efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs);
997 ret = efi_status;
998
999 efi_status = get_mem_attrs (addr, size, &after);
1000 if (EFI_ERROR(efi_status))
1001 dprint(L"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n",
1002 (unsigned long long)addr, (unsigned long long)size,
1003 &after, efi_status);
1004
1005 dprint(L"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n",
1006 (set_attrs & MEM_ATTR_R) ? "r" : "",
1007 (set_attrs & MEM_ATTR_W) ? "w" : "",
1008 (set_attrs & MEM_ATTR_X) ? "x" : "",
1009 (clear_attrs & MEM_ATTR_R) ? "r" : "",
1010 (clear_attrs & MEM_ATTR_W) ? "w" : "",
1011 (clear_attrs & MEM_ATTR_X) ? "x" : "",
1012 (unsigned long long)addr, (unsigned long long)(addr + size - 1),
1013 (before & MEM_ATTR_R) ? 'r' : '-',
1014 (before & MEM_ATTR_W) ? 'w' : '-',
1015 (before & MEM_ATTR_X) ? 'x' : '-',
1016 (after & MEM_ATTR_R) ? 'r' : '-',
1017 (after & MEM_ATTR_W) ? 'w' : '-',
1018 (after & MEM_ATTR_X) ? 'x' : '-');
1019
1020 return ret;
1021 }
1022
1023 EFI_STATUS verify_image(void *data, unsigned int datasize,
1024 EFI_LOADED_IMAGE *li,
1025 PE_COFF_LOADER_IMAGE_CONTEXT *context)
1026 {
1027 EFI_STATUS efi_status;
1028 UINT8 sha1hash[SHA1_DIGEST_SIZE];
1029 UINT8 sha256hash[SHA256_DIGEST_SIZE];
1030
1031 /*
1032 * The binary header contains relevant context and section pointers
1033 */
1034 efi_status = read_header(data, datasize, context);
1035 if (EFI_ERROR(efi_status)) {
1036 perror(L"Failed to read header: %r\n", efi_status);
1037 return efi_status;
1038 }
1039
1040 /*
1041 * Perform the image verification before we start copying data around
1042 * in order to load it.
1043 */
1044 if (secure_mode()) {
1045 efi_status = verify_buffer(data, datasize,
1046 context, sha256hash, sha1hash);
1047 if (EFI_ERROR(efi_status)) {
1048 if (verbose)
1049 console_print(L"Verification failed: %r\n", efi_status);
1050 else
1051 console_error(L"Verification failed", efi_status);
1052 return efi_status;
1053 } else if (verbose)
1054 console_print(L"Verification succeeded\n");
1055 }
1056
1057 /*
1058 * Calculate the hash for the TPM measurement.
1059 * XXX: We're computing these twice in secure boot mode when the
1060 * buffers already contain the previously computed hashes. Also,
1061 * this is only useful for the TPM1.2 case. We should try to fix
1062 * this in a follow-up.
1063 */
1064 efi_status = generate_hash(data, datasize, context, sha256hash,
1065 sha1hash);
1066 if (EFI_ERROR(efi_status))
1067 return efi_status;
1068
1069 /* Measure the binary into the TPM */
1070 #ifdef REQUIRE_TPM
1071 efi_status =
1072 #endif
1073 tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
1074 (EFI_PHYSICAL_ADDRESS)(UINTN)context->ImageAddress,
1075 li->FilePath, sha1hash, 4);
1076 #ifdef REQUIRE_TPM
1077 if (efi_status != EFI_SUCCESS) {
1078 return efi_status;
1079 }
1080 #endif
1081
1082 return EFI_SUCCESS;
1083 }
1084
1085 /*
1086 * Once the image has been loaded it needs to be validated and relocated
1087 */
1088 EFI_STATUS
1089 handle_image (void *data, unsigned int datasize,
1090 EFI_LOADED_IMAGE *li,
1091 EFI_IMAGE_ENTRY_POINT *entry_point,
1092 EFI_PHYSICAL_ADDRESS *alloc_address,
1093 UINTN *alloc_pages)
1094 {
1095 EFI_STATUS efi_status;
1096 char *buffer;
1097 int i;
1098 EFI_IMAGE_SECTION_HEADER *Section;
1099 char *base, *end;
1100 UINT32 size;
1101 PE_COFF_LOADER_IMAGE_CONTEXT context;
1102 unsigned int alignment, alloc_size;
1103 int found_entry_point = 0;
1104 UINT8 sha1hash[SHA1_DIGEST_SIZE];
1105 UINT8 sha256hash[SHA256_DIGEST_SIZE];
1106
1107 /*
1108 * The binary header contains relevant context and section pointers
1109 */
1110 efi_status = read_header(data, datasize, &context);
1111 if (EFI_ERROR(efi_status)) {
1112 perror(L"Failed to read header: %r\n", efi_status);
1113 return efi_status;
1114 }
1115
1116 /*
1117 * Perform the image verification before we start copying data around
1118 * in order to load it.
1119 */
1120 if (secure_mode ()) {
1121 efi_status = verify_buffer(data, datasize, &context, sha256hash,
1122 sha1hash);
1123
1124 if (EFI_ERROR(efi_status)) {
1125 if (verbose)
1126 console_print(L"Verification failed: %r\n", efi_status);
1127 else
1128 console_error(L"Verification failed", efi_status);
1129 return efi_status;
1130 } else {
1131 if (verbose)
1132 console_print(L"Verification succeeded\n");
1133 }
1134 }
1135
1136 /*
1137 * Calculate the hash for the TPM measurement.
1138 * XXX: We're computing these twice in secure boot mode when the
1139 * buffers already contain the previously computed hashes. Also,
1140 * this is only useful for the TPM1.2 case. We should try to fix
1141 * this in a follow-up.
1142 */
1143 efi_status = generate_hash(data, datasize, &context, sha256hash,
1144 sha1hash);
1145 if (EFI_ERROR(efi_status))
1146 return efi_status;
1147
1148 /* Measure the binary into the TPM */
1149 #ifdef REQUIRE_TPM
1150 efi_status =
1151 #endif
1152 tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
1153 (EFI_PHYSICAL_ADDRESS)(UINTN)context.ImageAddress,
1154 li->FilePath, sha1hash, 4);
1155 #ifdef REQUIRE_TPM
1156 if (efi_status != EFI_SUCCESS) {
1157 return efi_status;
1158 }
1159 #endif
1160
1161 /* The spec says, uselessly, of SectionAlignment:
1162 * =====
1163 * The alignment (in bytes) of sections when they are loaded into
1164 * memory. It must be greater than or equal to FileAlignment. The
1165 * default is the page size for the architecture.
1166 * =====
1167 * Which doesn't tell you whose responsibility it is to enforce the
1168 * "default", or when. It implies that the value in the field must
1169 * be > FileAlignment (also poorly defined), but it appears visual
1170 * studio will happily write 512 for FileAlignment (its default) and
1171 * 0 for SectionAlignment, intending to imply PAGE_SIZE.
1172 *
1173 * We only support one page size, so if it's zero, nerf it to 4096.
1174 */
1175 alignment = context.SectionAlignment;
1176 if (!alignment)
1177 alignment = 4096;
1178
1179 alloc_size = ALIGN_VALUE(context.ImageSize + context.SectionAlignment,
1180 PAGE_SIZE);
1181 *alloc_pages = alloc_size / PAGE_SIZE;
1182
1183 efi_status = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
1184 *alloc_pages, alloc_address);
1185 if (EFI_ERROR(efi_status)) {
1186 perror(L"Failed to allocate image buffer\n");
1187 return EFI_OUT_OF_RESOURCES;
1188 }
1189
1190 buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment);
1191 dprint(L"Loading 0x%llx bytes at 0x%llx\n",
1192 (unsigned long long)context.ImageSize,
1193 (unsigned long long)(uintptr_t)buffer);
1194 update_mem_attrs((uintptr_t)buffer, alloc_size, MEM_ATTR_R|MEM_ATTR_W,
1195 MEM_ATTR_X);
1196
1197 CopyMem(buffer, data, context.SizeOfHeaders);
1198
1199 *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
1200 if (!*entry_point) {
1201 perror(L"Entry point is invalid\n");
1202 BS->FreePages(*alloc_address, *alloc_pages);
1203 return EFI_UNSUPPORTED;
1204 }
1205
1206 char *RelocBase, *RelocBaseEnd;
1207 /*
1208 * These are relative virtual addresses, so we have to check them
1209 * against the image size, not the data size.
1210 */
1211 RelocBase = ImageAddress(buffer, context.ImageSize,
1212 context.RelocDir->VirtualAddress);
1213 /*
1214 * RelocBaseEnd here is the address of the last byte of the table
1215 */
1216 RelocBaseEnd = ImageAddress(buffer, context.ImageSize,
1217 context.RelocDir->VirtualAddress +
1218 context.RelocDir->Size - 1);
1219
1220 EFI_IMAGE_SECTION_HEADER *RelocSection = NULL;
1221
1222 /*
1223 * Copy the executable's sections to their desired offsets
1224 */
1225 Section = context.FirstSection;
1226 for (i = 0; i < context.NumberOfSections; i++, Section++) {
1227 /* Don't try to copy discardable sections with zero size */
1228 if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
1229 !Section->Misc.VirtualSize)
1230 continue;
1231
1232 /*
1233 * Skip sections that aren't marked readable.
1234 */
1235 if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ))
1236 continue;
1237
1238 if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
1239 (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) &&
1240 (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) &&
1241 (mok_policy & MOK_POLICY_REQUIRE_NX)) {
1242 perror(L"Section %d is writable and executable\n", i);
1243 return EFI_UNSUPPORTED;
1244 }
1245
1246 base = ImageAddress (buffer, context.ImageSize,
1247 Section->VirtualAddress);
1248 end = ImageAddress (buffer, context.ImageSize,
1249 Section->VirtualAddress
1250 + Section->Misc.VirtualSize - 1);
1251
1252 if (end < base) {
1253 perror(L"Section %d has negative size\n", i);
1254 BS->FreePages(*alloc_address, *alloc_pages);
1255 return EFI_UNSUPPORTED;
1256 }
1257
1258 if (Section->VirtualAddress <= context.EntryPoint &&
1259 (Section->VirtualAddress + Section->SizeOfRawData - 1)
1260 > context.EntryPoint)
1261 found_entry_point++;
1262
1263 /* We do want to process .reloc, but it's often marked
1264 * discardable, so we don't want to memcpy it. */
1265 if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) {
1266 if (RelocSection) {
1267 perror(L"Image has multiple relocation sections\n");
1268 return EFI_UNSUPPORTED;
1269 }
1270 /* If it has nonzero sizes, and our bounds check
1271 * made sense, and the VA and size match RelocDir's
1272 * versions, then we believe in this section table. */
1273 if (Section->SizeOfRawData &&
1274 Section->Misc.VirtualSize &&
1275 base && end &&
1276 RelocBase == base &&
1277 RelocBaseEnd == end) {
1278 RelocSection = Section;
1279 }
1280 }
1281
1282 if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) {
1283 continue;
1284 }
1285
1286 if (!base) {
1287 perror(L"Section %d has invalid base address\n", i);
1288 return EFI_UNSUPPORTED;
1289 }
1290 if (!end) {
1291 perror(L"Section %d has zero size\n", i);
1292 return EFI_UNSUPPORTED;
1293 }
1294
1295 if (!(Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) &&
1296 (Section->VirtualAddress < context.SizeOfHeaders ||
1297 Section->PointerToRawData < context.SizeOfHeaders)) {
1298 perror(L"Section %d is inside image headers\n", i);
1299 return EFI_UNSUPPORTED;
1300 }
1301
1302 if (Section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
1303 ZeroMem(base, Section->Misc.VirtualSize);
1304 } else {
1305 if (Section->PointerToRawData < context.SizeOfHeaders) {
1306 perror(L"Section %d is inside image headers\n", i);
1307 return EFI_UNSUPPORTED;
1308 }
1309
1310 size = Section->Misc.VirtualSize;
1311 if (size > Section->SizeOfRawData)
1312 size = Section->SizeOfRawData;
1313
1314 if (size > 0)
1315 CopyMem(base, data + Section->PointerToRawData, size);
1316
1317 if (size < Section->Misc.VirtualSize)
1318 ZeroMem(base + size, Section->Misc.VirtualSize - size);
1319 }
1320 }
1321
1322 if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1323 perror(L"Image has no relocation entry\n");
1324 FreePool(buffer);
1325 return EFI_UNSUPPORTED;
1326 }
1327
1328 if (context.RelocDir->Size && RelocSection) {
1329 /*
1330 * Run the relocation fixups
1331 */
1332 efi_status = relocate_coff(&context, RelocSection, data,
1333 buffer);
1334
1335 if (EFI_ERROR(efi_status)) {
1336 perror(L"Relocation failed: %r\n", efi_status);
1337 FreePool(buffer);
1338 return efi_status;
1339 }
1340 }
1341
1342 /*
1343 * Now set the page permissions appropriately.
1344 */
1345 Section = context.FirstSection;
1346 for (i = 0; i < context.NumberOfSections; i++, Section++) {
1347 uint64_t set_attrs = MEM_ATTR_R;
1348 uint64_t clear_attrs = MEM_ATTR_W|MEM_ATTR_X;
1349 uintptr_t addr;
1350 uint64_t length;
1351
1352 /*
1353 * Skip discardable sections with zero size
1354 */
1355 if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
1356 !Section->Misc.VirtualSize)
1357 continue;
1358
1359 /*
1360 * Skip sections that aren't marked readable.
1361 */
1362 if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ))
1363 continue;
1364
1365 base = ImageAddress (buffer, context.ImageSize,
1366 Section->VirtualAddress);
1367 end = ImageAddress (buffer, context.ImageSize,
1368 Section->VirtualAddress
1369 + Section->Misc.VirtualSize - 1);
1370
1371 addr = (uintptr_t)base;
1372 length = (uintptr_t)end - (uintptr_t)base + 1;
1373
1374 if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) {
1375 set_attrs |= MEM_ATTR_W;
1376 clear_attrs &= ~MEM_ATTR_W;
1377 }
1378 if (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) {
1379 set_attrs |= MEM_ATTR_X;
1380 clear_attrs &= ~MEM_ATTR_X;
1381 }
1382 update_mem_attrs(addr, length, set_attrs, clear_attrs);
1383 }
1384
1385
1386 /*
1387 * grub needs to know its location and size in memory, so fix up
1388 * the loaded image protocol values
1389 */
1390 li->ImageBase = buffer;
1391 li->ImageSize = context.ImageSize;
1392
1393 /* Pass the load options to the second stage loader */
1394 li->LoadOptions = load_options;
1395 li->LoadOptionsSize = load_options_size;
1396
1397 if (!found_entry_point) {
1398 perror(L"Entry point is not within sections\n");
1399 return EFI_UNSUPPORTED;
1400 }
1401 if (found_entry_point > 1) {
1402 perror(L"%d sections contain entry point\n", found_entry_point);
1403 return EFI_UNSUPPORTED;
1404 }
1405
1406 return EFI_SUCCESS;
1407 }
1408
1409 // vim:fenc=utf-8:tw=75:noet