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