]> git.proxmox.com Git - efi-boot-shim.git/blob - shim.c
73b2feb79f6da76999660ec60b33c418279d1097
[efi-boot-shim.git] / shim.c
1 /*
2 * shim - trivial UEFI first-stage bootloader
3 *
4 * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Significant portions of this code are derived from Tianocore
32 * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
33 * Corporation.
34 */
35
36 #include <efi.h>
37 #include <efilib.h>
38 #include <Library/BaseCryptLib.h>
39 #include "PeImage.h"
40 #include "shim.h"
41 #include "signature.h"
42
43 #define SECOND_STAGE L"\\grub.efi"
44 #define MOK_MANAGER L"\\MokManager.efi"
45
46 static EFI_SYSTEM_TABLE *systab;
47 static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
48
49 /*
50 * The vendor certificate used for validating the second stage loader
51 */
52 extern UINT8 vendor_cert[];
53 extern UINT32 vendor_cert_size;
54
55 #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
56
57 typedef enum {
58 DATA_FOUND,
59 DATA_NOT_FOUND,
60 VAR_NOT_FOUND
61 } CHECK_STATUS;
62
63 typedef struct {
64 UINT32 MokSize;
65 UINT8 *Mok;
66 } MokListNode;
67
68 static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes,
69 UINTN *size, void **buffer)
70 {
71 EFI_STATUS efi_status;
72 char allocate = !(*size);
73
74 efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid,
75 attributes, size, buffer);
76
77 if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) {
78 return efi_status;
79 }
80
81 if (allocate)
82 *buffer = AllocatePool(*size);
83
84 if (!*buffer) {
85 Print(L"Unable to allocate variable buffer\n");
86 return EFI_OUT_OF_RESOURCES;
87 }
88
89 efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid,
90 attributes, size, *buffer);
91
92 return efi_status;
93 }
94
95 static EFI_STATUS delete_variable (CHAR16 *name, EFI_GUID guid)
96 {
97 EFI_STATUS efi_status;
98
99 efi_status = uefi_call_wrapper(RT->SetVariable, 5, name, &guid,
100 0, 0, (UINT8 *)NULL);
101
102 return efi_status;
103 }
104
105 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
106 MokListNode *list;
107 int i, remain = DataSize;
108 void *ptr;
109
110 list = AllocatePool(sizeof(MokListNode) * num);
111
112 if (!list) {
113 Print(L"Unable to allocate MOK list\n");
114 return NULL;
115 }
116
117 ptr = Data;
118 for (i = 0; i < num; i++) {
119 CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
120 remain -= sizeof(UINT32) + list[i].MokSize;
121
122 if (remain < 0) {
123 Print(L"MOK list was corrupted\n");
124 FreePool(list);
125 return NULL;
126 }
127
128 ptr += sizeof(UINT32);
129 list[i].Mok = ptr;
130 ptr += list[i].MokSize;
131 }
132
133 return list;
134 }
135
136 /*
137 * Perform basic bounds checking of the intra-image pointers
138 */
139 static void *ImageAddress (void *image, int size, unsigned int address)
140 {
141 if (address > size)
142 return NULL;
143
144 return image + address;
145 }
146
147 /*
148 * Perform the actual relocation
149 */
150 static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
151 void *data)
152 {
153 EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
154 UINT64 Adjust;
155 UINT16 *Reloc, *RelocEnd;
156 char *Fixup, *FixupBase, *FixupData = NULL;
157 UINT16 *Fixup16;
158 UINT32 *Fixup32;
159 UINT64 *Fixup64;
160 int size = context->ImageSize;
161 void *ImageEnd = (char *)data + size;
162
163 context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)data;
164
165 if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
166 Print(L"Image has no relocation entry\n");
167 return EFI_UNSUPPORTED;
168 }
169
170 RelocBase = ImageAddress(data, size, context->RelocDir->VirtualAddress);
171 RelocBaseEnd = ImageAddress(data, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
172
173 if (!RelocBase || !RelocBaseEnd) {
174 Print(L"Reloc table overflows binary\n");
175 return EFI_UNSUPPORTED;
176 }
177
178 Adjust = (UINT64)data - context->ImageAddress;
179
180 while (RelocBase < RelocBaseEnd) {
181 Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
182 RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
183
184 if ((void *)RelocEnd < data || (void *)RelocEnd > ImageEnd) {
185 Print(L"Reloc entry overflows binary\n");
186 return EFI_UNSUPPORTED;
187 }
188
189 FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
190 if (!FixupBase) {
191 Print(L"Invalid fixupbase\n");
192 return EFI_UNSUPPORTED;
193 }
194
195 while (Reloc < RelocEnd) {
196 Fixup = FixupBase + (*Reloc & 0xFFF);
197 switch ((*Reloc) >> 12) {
198 case EFI_IMAGE_REL_BASED_ABSOLUTE:
199 break;
200
201 case EFI_IMAGE_REL_BASED_HIGH:
202 Fixup16 = (UINT16 *) Fixup;
203 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
204 if (FixupData != NULL) {
205 *(UINT16 *) FixupData = *Fixup16;
206 FixupData = FixupData + sizeof (UINT16);
207 }
208 break;
209
210 case EFI_IMAGE_REL_BASED_LOW:
211 Fixup16 = (UINT16 *) Fixup;
212 *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
213 if (FixupData != NULL) {
214 *(UINT16 *) FixupData = *Fixup16;
215 FixupData = FixupData + sizeof (UINT16);
216 }
217 break;
218
219 case EFI_IMAGE_REL_BASED_HIGHLOW:
220 Fixup32 = (UINT32 *) Fixup;
221 *Fixup32 = *Fixup32 + (UINT32) Adjust;
222 if (FixupData != NULL) {
223 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
224 *(UINT32 *)FixupData = *Fixup32;
225 FixupData = FixupData + sizeof (UINT32);
226 }
227 break;
228
229 case EFI_IMAGE_REL_BASED_DIR64:
230 Fixup64 = (UINT64 *) Fixup;
231 *Fixup64 = *Fixup64 + (UINT64) Adjust;
232 if (FixupData != NULL) {
233 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
234 *(UINT64 *)(FixupData) = *Fixup64;
235 FixupData = FixupData + sizeof(UINT64);
236 }
237 break;
238
239 default:
240 Print(L"Unknown relocation\n");
241 return EFI_UNSUPPORTED;
242 }
243 Reloc += 1;
244 }
245 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
246 }
247
248 return EFI_SUCCESS;
249 }
250
251 static CHECK_STATUS check_db_cert(CHAR16 *dbname, WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash)
252 {
253 EFI_STATUS efi_status;
254 EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
255 EFI_SIGNATURE_LIST *CertList;
256 EFI_SIGNATURE_DATA *Cert;
257 UINTN dbsize = 0;
258 UINTN CertCount, Index;
259 UINT32 attributes;
260 BOOLEAN IsFound = FALSE;
261 void *db;
262 EFI_GUID CertType = EfiCertX509Guid;
263
264 efi_status = get_variable(dbname, secure_var, &attributes, &dbsize, &db);
265
266 if (efi_status != EFI_SUCCESS)
267 return VAR_NOT_FOUND;
268
269 CertList = db;
270
271 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
272 if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
273 CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
274 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
275 for (Index = 0; Index < CertCount; Index++) {
276 IsFound = AuthenticodeVerify (data->CertData,
277 data->Hdr.dwLength - sizeof(data->Hdr),
278 Cert->SignatureData,
279 CertList->SignatureSize,
280 hash, SHA256_DIGEST_SIZE);
281 if (IsFound)
282 break;
283 }
284
285 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
286 }
287
288 dbsize -= CertList->SignatureListSize;
289 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
290 }
291
292 FreePool(db);
293
294 if (IsFound)
295 return DATA_FOUND;
296
297 return DATA_NOT_FOUND;
298 }
299
300 static CHECK_STATUS check_db_hash(CHAR16 *dbname, UINT8 *data)
301 {
302 EFI_STATUS efi_status;
303 EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
304 EFI_SIGNATURE_LIST *CertList;
305 EFI_SIGNATURE_DATA *Cert;
306 UINTN dbsize = 0;
307 UINTN CertCount, Index;
308 UINT32 attributes;
309 BOOLEAN IsFound = FALSE;
310 void *db;
311 unsigned int SignatureSize = SHA256_DIGEST_SIZE;
312 EFI_GUID CertType = EfiHashSha256Guid;
313
314 efi_status = get_variable(dbname, secure_var, &attributes, &dbsize, &db);
315
316 if (efi_status != EFI_SUCCESS) {
317 return VAR_NOT_FOUND;
318 }
319
320 CertList = db;
321
322 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
323 CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
324 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
325 if (CompareGuid(&CertList->SignatureType, &CertType) == 0) {
326 for (Index = 0; Index < CertCount; Index++) {
327 if (CompareMem (Cert->SignatureData, data, SignatureSize) == 0) {
328 //
329 // Find the signature in database.
330 //
331 IsFound = TRUE;
332 break;
333 }
334
335 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
336 }
337 if (IsFound) {
338 break;
339 }
340 }
341
342 dbsize -= CertList->SignatureListSize;
343 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
344 }
345
346 FreePool(db);
347
348 if (IsFound)
349 return DATA_FOUND;
350
351 return DATA_NOT_FOUND;
352 }
353
354 static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert, UINT8 *hash)
355 {
356 if (check_db_hash(L"dbx", hash) == DATA_FOUND)
357 return EFI_ACCESS_DENIED;
358 if (check_db_cert(L"dbx", cert, hash) == DATA_FOUND)
359 return EFI_ACCESS_DENIED;
360
361 return EFI_SUCCESS;
362 }
363
364 static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert, UINT8 *hash)
365 {
366 if (check_db_hash(L"db", hash) == DATA_FOUND)
367 return EFI_SUCCESS;
368 if (check_db_cert(L"db", cert, hash) == DATA_FOUND)
369 return EFI_SUCCESS;
370
371 return EFI_ACCESS_DENIED;
372 }
373
374 /*
375 * Check whether we're in Secure Boot and user mode
376 */
377
378 static BOOLEAN secure_mode (void)
379 {
380 EFI_STATUS status;
381 EFI_GUID global_var = EFI_GLOBAL_VARIABLE;
382 UINTN charsize = sizeof(char);
383 UINT8 sb, setupmode;
384 UINT32 attributes;
385
386 status = get_variable(L"SecureBoot", global_var, &attributes, &charsize,
387 (void *)&sb);
388
389 /* FIXME - more paranoia here? */
390 if (status != EFI_SUCCESS || sb != 1) {
391 Print(L"Secure boot not enabled\n");
392 return FALSE;
393 }
394
395 status = get_variable(L"SetupMode", global_var, &attributes, &charsize,
396 (void *)&setupmode);
397
398 if (status == EFI_SUCCESS && setupmode == 1) {
399 Print(L"Platform is in setup mode\n");
400 return FALSE;
401 }
402
403 return TRUE;
404 }
405
406 /*
407 * Check that the signature is valid and matches the binary
408 */
409 static EFI_STATUS verify_buffer (char *data, int datasize,
410 PE_COFF_LOADER_IMAGE_CONTEXT *context, int whitelist)
411 {
412 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
413 unsigned int size = datasize;
414 unsigned int ctxsize;
415 void *ctx = NULL;
416 UINT8 hash[SHA256_DIGEST_SIZE];
417 EFI_STATUS status = EFI_ACCESS_DENIED;
418 char *hashbase;
419 unsigned int hashsize;
420 WIN_CERTIFICATE_EFI_PKCS *cert;
421 unsigned int SumOfBytesHashed, SumOfSectionBytes;
422 unsigned int index, pos;
423 EFI_IMAGE_SECTION_HEADER *Section;
424 EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
425 EFI_IMAGE_SECTION_HEADER *SectionCache;
426 unsigned int i;
427 void *MokListData = NULL;
428 UINTN MokListDataSize = 0;
429 UINT32 MokNum, attributes;
430 MokListNode *list = NULL;
431
432 cert = ImageAddress (data, size, context->SecDir->VirtualAddress);
433
434 if (!cert) {
435 Print(L"Certificate located outside the image\n");
436 return EFI_INVALID_PARAMETER;
437 }
438
439 if (cert->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
440 Print(L"Unsupported certificate type %x\n",
441 cert->Hdr.wCertificateType);
442 return EFI_UNSUPPORTED;
443 }
444
445 /* FIXME: Check which kind of hash */
446
447 ctxsize = Sha256GetContextSize();
448 ctx = AllocatePool(ctxsize);
449
450 if (!ctx) {
451 Print(L"Unable to allocate memory for hash context\n");
452 return EFI_OUT_OF_RESOURCES;
453 }
454
455 if (!Sha256Init(ctx)) {
456 Print(L"Unable to initialise hash\n");
457 status = EFI_OUT_OF_RESOURCES;
458 goto done;
459 }
460
461 /* Hash start to checksum */
462 hashbase = data;
463 hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
464 hashbase;
465
466 if (!(Sha256Update(ctx, hashbase, hashsize))) {
467 Print(L"Unable to generate hash\n");
468 status = EFI_OUT_OF_RESOURCES;
469 goto done;
470 }
471
472 /* Hash post-checksum to start of certificate table */
473 hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
474 sizeof (int);
475 hashsize = (char *)context->SecDir - hashbase;
476
477 if (!(Sha256Update(ctx, hashbase, hashsize))) {
478 Print(L"Unable to generate hash\n");
479 status = EFI_OUT_OF_RESOURCES;
480 goto done;
481 }
482
483 /* Hash end of certificate table to end of image header */
484 hashbase = (char *) &context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
485 hashsize = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders -
486 (int) ((char *) (&context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - data);
487
488 if (!(Sha256Update(ctx, hashbase, hashsize))) {
489 Print(L"Unable to generate hash\n");
490 status = EFI_OUT_OF_RESOURCES;
491 goto done;
492 }
493
494 /* Sort sections */
495 SumOfBytesHashed = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
496
497 Section = (EFI_IMAGE_SECTION_HEADER *) (
498 (char *)context->PEHdr + sizeof (UINT32) +
499 sizeof (EFI_IMAGE_FILE_HEADER) +
500 context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader
501 );
502
503 SectionCache = Section;
504
505 for (index = 0, SumOfSectionBytes = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++, SectionCache++) {
506 SumOfSectionBytes += SectionCache->SizeOfRawData;
507 }
508
509 if (SumOfSectionBytes >= datasize) {
510 Print(L"Malformed binary: %x %x\n", SumOfSectionBytes, size);
511 status = EFI_INVALID_PARAMETER;
512 goto done;
513 }
514
515 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * context->PEHdr->Pe32.FileHeader.NumberOfSections);
516 if (SectionHeader == NULL) {
517 Print(L"Unable to allocate section header\n");
518 status = EFI_OUT_OF_RESOURCES;
519 goto done;
520 }
521
522 /* Sort the section headers */
523 for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
524 pos = index;
525 while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) {
526 CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
527 pos--;
528 }
529 CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
530 Section += 1;
531 }
532
533 /* Hash the sections */
534 for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
535 Section = &SectionHeader[index];
536 if (Section->SizeOfRawData == 0) {
537 continue;
538 }
539 hashbase = ImageAddress(data, size, Section->PointerToRawData);
540 hashsize = (unsigned int) Section->SizeOfRawData;
541
542 if (!hashbase) {
543 Print(L"Malformed section header\n");
544 return EFI_INVALID_PARAMETER;
545 }
546
547 if (!(Sha256Update(ctx, hashbase, hashsize))) {
548 Print(L"Unable to generate hash\n");
549 status = EFI_OUT_OF_RESOURCES;
550 goto done;
551 }
552 SumOfBytesHashed += Section->SizeOfRawData;
553 }
554
555 /* Hash all remaining data */
556 if (size > SumOfBytesHashed) {
557 hashbase = data + SumOfBytesHashed;
558 hashsize = (unsigned int)(
559 size -
560 context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
561 SumOfBytesHashed);
562
563 if (!(Sha256Update(ctx, hashbase, hashsize))) {
564 Print(L"Unable to generate hash\n");
565 status = EFI_OUT_OF_RESOURCES;
566 goto done;
567 }
568 }
569
570 if (!(Sha256Final(ctx, hash))) {
571 Print(L"Unable to finalise hash\n");
572 status = EFI_OUT_OF_RESOURCES;
573 goto done;
574 }
575
576 status = check_blacklist(cert, hash);
577
578 if (status != EFI_SUCCESS) {
579 Print(L"Binary is blacklisted\n");
580 goto done;
581 }
582
583 if (whitelist) {
584 status = check_whitelist(cert, hash);
585
586 if (status == EFI_SUCCESS) {
587 Print(L"Binary is whitelisted\n");
588 goto done;
589 }
590 }
591
592 if (AuthenticodeVerify(cert->CertData,
593 context->SecDir->Size - sizeof(cert->Hdr),
594 vendor_cert, vendor_cert_size, hash,
595 SHA256_DIGEST_SIZE)) {
596 status = EFI_SUCCESS;
597 Print(L"Binary is verified by the vendor certificate\n");
598 goto done;
599 }
600
601 status = get_variable(L"MokList", shim_lock_guid, &attributes,
602 &MokListDataSize, &MokListData);
603
604 if (status != EFI_SUCCESS) {
605 status = EFI_ACCESS_DENIED;
606 Print(L"Invalid signature\n");
607 goto done;
608 }
609
610 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
611 Print(L"MokList is compromised!\nErase all keys in MokList!\n");
612 if (delete_variable(L"MokList", shim_lock_guid) != EFI_SUCCESS) {
613 Print(L"Failed to erase MokList\n");
614 }
615 status = EFI_ACCESS_DENIED;
616 goto done;
617 }
618
619 CopyMem(&MokNum, MokListData, sizeof(UINT32));
620 if (MokNum == 0) {
621 status = EFI_ACCESS_DENIED;
622 goto done;
623 }
624
625 list = build_mok_list(MokNum,
626 (void *)MokListData + sizeof(UINT32),
627 MokListDataSize - sizeof(UINT32));
628
629 if (!list) {
630 Print(L"Failed to construct MOK list\n");
631 status = EFI_OUT_OF_RESOURCES;
632 goto done;
633 }
634
635 for (i = 0; i < MokNum; i++) {
636 if (AuthenticodeVerify(cert->CertData,
637 context->SecDir->Size - sizeof(cert->Hdr),
638 list[i].Mok, list[i].MokSize, hash,
639 SHA256_DIGEST_SIZE)) {
640 status = EFI_SUCCESS;
641 Print(L"Binary is verified by the machine owner key\n");
642 goto done;
643 }
644 }
645 Print(L"Invalid signature\n");
646 status = EFI_ACCESS_DENIED;
647
648 done:
649 if (SectionHeader)
650 FreePool(SectionHeader);
651 if (ctx)
652 FreePool(ctx);
653
654 return status;
655 }
656
657 /*
658 * Read the binary header and grab appropriate information from it
659 */
660 static EFI_STATUS read_header(void *data, unsigned int datasize,
661 PE_COFF_LOADER_IMAGE_CONTEXT *context)
662 {
663 EFI_IMAGE_DOS_HEADER *DosHdr = data;
664 EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
665
666 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
667 PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
668
669 if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
670 Print(L"Unsupported image type\n");
671 return EFI_UNSUPPORTED;
672 }
673
674 if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
675 Print(L"Unsupported image - Relocations have been stripped\n");
676 return EFI_UNSUPPORTED;
677 }
678
679 if (PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
680 Print(L"Only 64-bit images supported\n");
681 return EFI_UNSUPPORTED;
682 }
683
684 context->PEHdr = PEHdr;
685 context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
686 context->ImageSize = (UINT64)PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
687 context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
688 context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
689 context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
690 context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
691 context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
692 context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
693 context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
694
695 if (context->SecDir->VirtualAddress >= datasize) {
696 Print(L"Malformed security header\n");
697 return EFI_INVALID_PARAMETER;
698 }
699
700 if (context->SecDir->Size == 0) {
701 Print(L"Empty security header\n");
702 return EFI_INVALID_PARAMETER;
703 }
704
705 return EFI_SUCCESS;
706 }
707
708 /*
709 * Once the image has been loaded it needs to be validated and relocated
710 */
711 static EFI_STATUS handle_image (void *data, unsigned int datasize,
712 EFI_LOADED_IMAGE *li)
713 {
714 EFI_STATUS efi_status;
715 char *buffer;
716 int i, size;
717 EFI_IMAGE_SECTION_HEADER *Section;
718 char *base, *end;
719 PE_COFF_LOADER_IMAGE_CONTEXT context;
720
721 efi_status = read_header(data, datasize, &context);
722 if (efi_status != EFI_SUCCESS) {
723 Print(L"Failed to read header\n");
724 return efi_status;
725 }
726
727 if (secure_mode ()) {
728 efi_status = verify_buffer(data, datasize, &context, 0);
729
730 if (efi_status != EFI_SUCCESS) {
731 Print(L"Verification failed\n");
732 return efi_status;
733 }
734 }
735
736 buffer = AllocatePool(context.ImageSize);
737
738 if (!buffer) {
739 Print(L"Failed to allocate image buffer\n");
740 return EFI_OUT_OF_RESOURCES;
741 }
742
743 CopyMem(buffer, data, context.SizeOfHeaders);
744
745 Section = context.FirstSection;
746 for (i = 0; i < context.NumberOfSections; i++) {
747 size = Section->Misc.VirtualSize;
748
749 if (size > Section->SizeOfRawData)
750 size = Section->SizeOfRawData;
751
752 base = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress);
753 end = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress + size - 1);
754
755 if (!base || !end) {
756 Print(L"Invalid section size\n");
757 return EFI_UNSUPPORTED;
758 }
759
760 if (Section->SizeOfRawData > 0)
761 CopyMem(base, data + Section->PointerToRawData, size);
762
763 if (size < Section->Misc.VirtualSize)
764 ZeroMem (base + size, Section->Misc.VirtualSize - size);
765
766 Section += 1;
767 }
768
769 efi_status = relocate_coff(&context, buffer);
770
771 if (efi_status != EFI_SUCCESS) {
772 Print(L"Relocation failed\n");
773 FreePool(buffer);
774 return efi_status;
775 }
776
777 entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
778 li->ImageBase = buffer;
779 li->ImageSize = context.ImageSize;
780
781 if (!entry_point) {
782 Print(L"Invalid entry point\n");
783 FreePool(buffer);
784 return EFI_UNSUPPORTED;
785 }
786
787 return EFI_SUCCESS;
788 }
789
790 static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
791 EFI_DEVICE_PATH **grubpath, CHAR16 **PathName)
792 {
793 EFI_DEVICE_PATH *devpath;
794 EFI_HANDLE device;
795 int i;
796 unsigned int pathlen = 0;
797 EFI_STATUS efi_status = EFI_SUCCESS;
798 CHAR16 *bootpath;
799
800 device = li->DeviceHandle;
801 devpath = li->FilePath;
802
803 bootpath = DevicePathToStr(devpath);
804
805 pathlen = StrLen(bootpath);
806
807 for (i=pathlen; i>0; i--) {
808 if (bootpath[i] == '\\')
809 break;
810 }
811
812 bootpath[i+1] = '\0';
813
814 if (bootpath[i-i] == '\\')
815 bootpath[i] = '\0';
816
817 *PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
818
819 if (!*PathName) {
820 Print(L"Failed to allocate path buffer\n");
821 efi_status = EFI_OUT_OF_RESOURCES;
822 goto error;
823 }
824
825 *PathName[0] = '\0';
826 StrCat(*PathName, bootpath);
827 StrCat(*PathName, ImagePath);
828
829 *grubpath = FileDevicePath(device, *PathName);
830
831 error:
832 return efi_status;
833 }
834
835 /*
836 * Locate the second stage bootloader and read it into a buffer
837 */
838 static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
839 int *datasize, CHAR16 *PathName)
840 {
841 EFI_GUID simple_file_system_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
842 EFI_GUID file_info_id = EFI_FILE_INFO_ID;
843 EFI_STATUS efi_status;
844 EFI_HANDLE device;
845 EFI_FILE_INFO *fileinfo = NULL;
846 EFI_FILE_IO_INTERFACE *drive;
847 EFI_FILE *root, *grub;
848 UINTN buffersize = sizeof(EFI_FILE_INFO);
849
850 device = li->DeviceHandle;
851
852 efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
853 &simple_file_system_protocol, &drive);
854
855 if (efi_status != EFI_SUCCESS) {
856 Print(L"Failed to find fs\n");
857 goto error;
858 }
859
860 efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
861
862 if (efi_status != EFI_SUCCESS) {
863 Print(L"Failed to open fs\n");
864 goto error;
865 }
866
867 efi_status = uefi_call_wrapper(root->Open, 5, root, &grub, PathName,
868 EFI_FILE_MODE_READ, 0);
869
870 if (efi_status != EFI_SUCCESS) {
871 Print(L"Failed to open %s - %lx\n", PathName, efi_status);
872 goto error;
873 }
874
875 fileinfo = AllocatePool(buffersize);
876
877 if (!fileinfo) {
878 Print(L"Unable to allocate file info buffer\n");
879 efi_status = EFI_OUT_OF_RESOURCES;
880 goto error;
881 }
882
883 efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
884 &buffersize, fileinfo);
885
886 if (efi_status == EFI_BUFFER_TOO_SMALL) {
887 fileinfo = AllocatePool(buffersize);
888 if (!fileinfo) {
889 Print(L"Unable to allocate file info buffer\n");
890 efi_status = EFI_OUT_OF_RESOURCES;
891 goto error;
892 }
893 efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
894 &file_info_id, &buffersize,
895 fileinfo);
896 }
897
898 if (efi_status != EFI_SUCCESS) {
899 Print(L"Unable to get file info\n");
900 goto error;
901 }
902
903 buffersize = fileinfo->FileSize;
904
905 *data = AllocatePool(buffersize);
906
907 if (!*data) {
908 Print(L"Unable to allocate file buffer\n");
909 efi_status = EFI_OUT_OF_RESOURCES;
910 goto error;
911 }
912 efi_status = uefi_call_wrapper(grub->Read, 3, grub, &buffersize,
913 *data);
914
915 if (efi_status == EFI_BUFFER_TOO_SMALL) {
916 FreePool(*data);
917 *data = AllocatePool(buffersize);
918 efi_status = uefi_call_wrapper(grub->Read, 3, grub,
919 &buffersize, *data);
920 }
921
922 if (efi_status != EFI_SUCCESS) {
923 Print(L"Unexpected return from initial read: %x, buffersize %x\n", efi_status, buffersize);
924 goto error;
925 }
926
927 *datasize = buffersize;
928
929 return EFI_SUCCESS;
930 error:
931 if (*data) {
932 FreePool(*data);
933 *data = NULL;
934 }
935 if (PathName)
936 FreePool(PathName);
937 if (fileinfo)
938 FreePool(fileinfo);
939 return efi_status;
940 }
941
942 EFI_STATUS shim_verify (void *buffer, UINT32 size)
943 {
944 EFI_STATUS status;
945 PE_COFF_LOADER_IMAGE_CONTEXT context;
946
947 if (!secure_mode())
948 return EFI_SUCCESS;
949
950 status = read_header(buffer, size, &context);
951
952 if (status != EFI_SUCCESS)
953 return status;
954
955 status = verify_buffer(buffer, size, &context, 1);
956
957 return status;
958 }
959
960 EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
961 {
962 EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
963 EFI_STATUS efi_status;
964 EFI_LOADED_IMAGE *li, li_bak;
965 EFI_HANDLE handle = NULL;
966 EFI_DEVICE_PATH *path;
967 CHAR16 *PathName;
968 void *data = NULL;
969 int datasize;
970
971 efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
972 &loaded_image_protocol, &li);
973
974 if (efi_status != EFI_SUCCESS) {
975 Print(L"Unable to init protocol\n");
976 return efi_status;
977 }
978
979 efi_status = generate_path(li, ImagePath, &path, &PathName);
980
981 if (efi_status != EFI_SUCCESS) {
982 Print(L"Unable to generate path: %s\n", ImagePath);
983 goto done;
984 }
985
986 efi_status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image_handle,
987 path, NULL, 0, &handle);
988
989 if (efi_status == EFI_SUCCESS) {
990 /* Image validates - start it */
991 Print(L"Starting file via StartImage\n");
992 efi_status = uefi_call_wrapper(BS->StartImage, 3, handle, NULL,
993 NULL);
994 uefi_call_wrapper(BS->UnloadImage, 1, handle);
995 goto done;
996 }
997
998 efi_status = load_image(li, &data, &datasize, PathName);
999
1000 if (efi_status != EFI_SUCCESS) {
1001 Print(L"Failed to load image\n");
1002 goto done;
1003 }
1004
1005 CopyMem(&li_bak, li, sizeof(li_bak));
1006
1007 efi_status = handle_image(data, datasize, li);
1008
1009 if (efi_status != EFI_SUCCESS) {
1010 Print(L"Failed to load image\n");
1011 CopyMem(li, &li_bak, sizeof(li_bak));
1012 goto done;
1013 }
1014
1015 efi_status = uefi_call_wrapper(entry_point, 3, image_handle, systab);
1016
1017 CopyMem(li, &li_bak, sizeof(li_bak));
1018 done:
1019 return efi_status;
1020 }
1021
1022 EFI_STATUS init_grub(EFI_HANDLE image_handle)
1023 {
1024 EFI_STATUS efi_status;
1025
1026 efi_status = start_image(image_handle, SECOND_STAGE);
1027
1028 if (efi_status != EFI_SUCCESS) {
1029 Print(L"Failed to start grub\n");
1030 goto done;
1031 }
1032 done:
1033
1034 return efi_status;
1035 }
1036
1037 EFI_STATUS mirror_mok_list()
1038 {
1039 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1040 EFI_STATUS efi_status;
1041 UINT32 attributes;
1042 void *Data = NULL;
1043 UINTN DataSize = 0;
1044
1045 efi_status = get_variable(L"MokList", shim_lock_guid, &attributes,
1046 &DataSize, &Data);
1047
1048 if (efi_status != EFI_SUCCESS) {
1049 goto done;
1050 }
1051
1052 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListRT",
1053 &shim_lock_guid,
1054 EFI_VARIABLE_BOOTSERVICE_ACCESS
1055 | EFI_VARIABLE_RUNTIME_ACCESS,
1056 DataSize, Data);
1057 if (efi_status != EFI_SUCCESS) {
1058 Print(L"Failed to set MokListRT %d\n", efi_status);
1059 }
1060
1061 done:
1062 return efi_status;
1063 }
1064
1065 EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1066 {
1067 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1068 EFI_STATUS efi_status;
1069 UINTN size = sizeof(UINT32);
1070 UINT32 MokNew;
1071 UINT32 attributes;
1072
1073 if (!secure_mode())
1074 return EFI_SUCCESS;
1075
1076 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokNew",
1077 &shim_lock_guid, &attributes,
1078 &size, (void *)&MokNew);
1079
1080 if (efi_status != EFI_SUCCESS && efi_status != EFI_BUFFER_TOO_SMALL)
1081 goto done;
1082
1083 efi_status = start_image(image_handle, MOK_MANAGER);
1084
1085 if (efi_status != EFI_SUCCESS) {
1086 Print(L"Failed to start MokManager\n");
1087 goto done;
1088 }
1089
1090 done:
1091 return efi_status;
1092 }
1093
1094 EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
1095 {
1096 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1097 static SHIM_LOCK shim_lock_interface;
1098 EFI_HANDLE handle = NULL;
1099 EFI_STATUS efi_status;
1100
1101 shim_lock_interface.Verify = shim_verify;
1102
1103 systab = passed_systab;
1104
1105 InitializeLib(image_handle, systab);
1106
1107 efi_status = check_mok_request(image_handle);
1108
1109 efi_status = mirror_mok_list();
1110
1111 uefi_call_wrapper(BS->InstallProtocolInterface, 4, &handle,
1112 &shim_lock_guid, EFI_NATIVE_INTERFACE,
1113 &shim_lock_interface);
1114
1115 efi_status = init_grub(image_handle);
1116
1117 uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
1118 &shim_lock_guid, &shim_lock_interface);
1119
1120 return efi_status;
1121 }