2 * shim - trivial UEFI first-stage bootloader
4 * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
31 * Significant portions of this code are derived from Tianocore
32 * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
38 #include <Library/BaseCryptLib.h>
41 #include "signature.h"
43 #define SECOND_STAGE L"\\grub.efi"
44 #define MOK_MANAGER L"\\MokManager.efi"
46 static EFI_SYSTEM_TABLE
*systab
;
47 static EFI_STATUS (EFIAPI
*entry_point
) (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*system_table
);
50 * The vendor certificate used for validating the second stage loader
52 extern UINT8 vendor_cert
[];
53 extern UINT32 vendor_cert_size
;
55 #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
68 static EFI_STATUS
get_variable (CHAR16
*name
, EFI_GUID guid
, UINT32
*attributes
,
69 UINTN
*size
, void **buffer
)
71 EFI_STATUS efi_status
;
72 char allocate
= !(*size
);
74 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, name
, &guid
,
75 attributes
, size
, buffer
);
77 if (efi_status
!= EFI_BUFFER_TOO_SMALL
|| !allocate
) {
82 *buffer
= AllocatePool(*size
);
85 Print(L
"Unable to allocate variable buffer\n");
86 return EFI_OUT_OF_RESOURCES
;
89 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, name
, &guid
,
90 attributes
, size
, *buffer
);
95 static EFI_STATUS
delete_variable (CHAR16
*name
, EFI_GUID guid
)
97 EFI_STATUS efi_status
;
99 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, name
, &guid
,
100 0, 0, (UINT8
*)NULL
);
105 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
107 int i
, remain
= DataSize
;
110 list
= AllocatePool(sizeof(MokListNode
) * num
);
113 Print(L
"Unable to allocate MOK list\n");
118 for (i
= 0; i
< num
; i
++) {
119 CopyMem(&list
[i
].MokSize
, ptr
, sizeof(UINT32
));
120 remain
-= sizeof(UINT32
) + list
[i
].MokSize
;
123 Print(L
"MOK list was corrupted\n");
128 ptr
+= sizeof(UINT32
);
130 ptr
+= list
[i
].MokSize
;
137 * Perform basic bounds checking of the intra-image pointers
139 static void *ImageAddress (void *image
, int size
, unsigned int address
)
144 return image
+ address
;
148 * Perform the actual relocation
150 static EFI_STATUS
relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT
*context
,
153 EFI_IMAGE_BASE_RELOCATION
*RelocBase
, *RelocBaseEnd
;
155 UINT16
*Reloc
, *RelocEnd
;
156 char *Fixup
, *FixupBase
, *FixupData
= NULL
;
160 int size
= context
->ImageSize
;
161 void *ImageEnd
= (char *)data
+ size
;
163 context
->PEHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= (UINT64
)data
;
165 if (context
->NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
166 Print(L
"Image has no relocation entry\n");
167 return EFI_UNSUPPORTED
;
170 RelocBase
= ImageAddress(data
, size
, context
->RelocDir
->VirtualAddress
);
171 RelocBaseEnd
= ImageAddress(data
, size
, context
->RelocDir
->VirtualAddress
+ context
->RelocDir
->Size
- 1);
173 if (!RelocBase
|| !RelocBaseEnd
) {
174 Print(L
"Reloc table overflows binary\n");
175 return EFI_UNSUPPORTED
;
178 Adjust
= (UINT64
)data
- context
->ImageAddress
;
180 while (RelocBase
< RelocBaseEnd
) {
181 Reloc
= (UINT16
*) ((char *) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
182 RelocEnd
= (UINT16
*) ((char *) RelocBase
+ RelocBase
->SizeOfBlock
);
184 if ((void *)RelocEnd
< data
|| (void *)RelocEnd
> ImageEnd
) {
185 Print(L
"Reloc entry overflows binary\n");
186 return EFI_UNSUPPORTED
;
189 FixupBase
= ImageAddress(data
, size
, RelocBase
->VirtualAddress
);
191 Print(L
"Invalid fixupbase\n");
192 return EFI_UNSUPPORTED
;
195 while (Reloc
< RelocEnd
) {
196 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
197 switch ((*Reloc
) >> 12) {
198 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
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
);
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
);
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
);
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
);
240 Print(L
"Unknown relocation\n");
241 return EFI_UNSUPPORTED
;
245 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
251 static CHECK_STATUS
check_db_cert(CHAR16
*dbname
, WIN_CERTIFICATE_EFI_PKCS
*data
, UINT8
*hash
)
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
;
258 UINTN CertCount
, Index
;
260 BOOLEAN IsFound
= FALSE
;
262 EFI_GUID CertType
= EfiCertX509Guid
;
264 efi_status
= get_variable(dbname
, secure_var
, &attributes
, &dbsize
, &db
);
266 if (efi_status
!= EFI_SUCCESS
)
267 return VAR_NOT_FOUND
;
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
),
279 CertList
->SignatureSize
,
280 hash
, SHA256_DIGEST_SIZE
);
285 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
288 dbsize
-= CertList
->SignatureListSize
;
289 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
297 return DATA_NOT_FOUND
;
300 static CHECK_STATUS
check_db_hash(CHAR16
*dbname
, UINT8
*data
)
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
;
307 UINTN CertCount
, Index
;
309 BOOLEAN IsFound
= FALSE
;
311 unsigned int SignatureSize
= SHA256_DIGEST_SIZE
;
312 EFI_GUID CertType
= EfiHashSha256Guid
;
314 efi_status
= get_variable(dbname
, secure_var
, &attributes
, &dbsize
, &db
);
316 if (efi_status
!= EFI_SUCCESS
) {
317 return VAR_NOT_FOUND
;
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) {
329 // Find the signature in database.
335 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
342 dbsize
-= CertList
->SignatureListSize
;
343 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
351 return DATA_NOT_FOUND
;
354 static EFI_STATUS
check_blacklist (WIN_CERTIFICATE_EFI_PKCS
*cert
, UINT8
*hash
)
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
;
364 static EFI_STATUS
check_whitelist (WIN_CERTIFICATE_EFI_PKCS
*cert
, UINT8
*hash
)
366 if (check_db_hash(L
"db", hash
) == DATA_FOUND
)
368 if (check_db_cert(L
"db", cert
, hash
) == DATA_FOUND
)
371 return EFI_ACCESS_DENIED
;
375 * Check whether we're in Secure Boot and user mode
378 static BOOLEAN
secure_mode (void)
381 EFI_GUID global_var
= EFI_GLOBAL_VARIABLE
;
382 UINTN charsize
= sizeof(char);
386 status
= get_variable(L
"SecureBoot", global_var
, &attributes
, &charsize
,
389 /* FIXME - more paranoia here? */
390 if (status
!= EFI_SUCCESS
|| sb
!= 1) {
391 Print(L
"Secure boot not enabled\n");
395 status
= get_variable(L
"SetupMode", global_var
, &attributes
, &charsize
,
398 if (status
== EFI_SUCCESS
&& setupmode
== 1) {
399 Print(L
"Platform is in setup mode\n");
407 * Check that the signature is valid and matches the binary
409 static EFI_STATUS
verify_buffer (char *data
, int datasize
,
410 PE_COFF_LOADER_IMAGE_CONTEXT
*context
, int whitelist
)
412 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
413 unsigned int size
= datasize
;
414 unsigned int ctxsize
;
416 UINT8 hash
[SHA256_DIGEST_SIZE
];
417 EFI_STATUS status
= EFI_ACCESS_DENIED
;
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
;
427 void *MokListData
= NULL
;
428 UINTN MokListDataSize
= 0;
429 UINT32 MokNum
, attributes
;
430 MokListNode
*list
= NULL
;
432 cert
= ImageAddress (data
, size
, context
->SecDir
->VirtualAddress
);
435 Print(L
"Certificate located outside the image\n");
436 return EFI_INVALID_PARAMETER
;
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
;
445 /* FIXME: Check which kind of hash */
447 ctxsize
= Sha256GetContextSize();
448 ctx
= AllocatePool(ctxsize
);
451 Print(L
"Unable to allocate memory for hash context\n");
452 return EFI_OUT_OF_RESOURCES
;
455 if (!Sha256Init(ctx
)) {
456 Print(L
"Unable to initialise hash\n");
457 status
= EFI_OUT_OF_RESOURCES
;
461 /* Hash start to checksum */
463 hashsize
= (char *)&context
->PEHdr
->Pe32
.OptionalHeader
.CheckSum
-
466 if (!(Sha256Update(ctx
, hashbase
, hashsize
))) {
467 Print(L
"Unable to generate hash\n");
468 status
= EFI_OUT_OF_RESOURCES
;
472 /* Hash post-checksum to start of certificate table */
473 hashbase
= (char *)&context
->PEHdr
->Pe32
.OptionalHeader
.CheckSum
+
475 hashsize
= (char *)context
->SecDir
- hashbase
;
477 if (!(Sha256Update(ctx
, hashbase
, hashsize
))) {
478 Print(L
"Unable to generate hash\n");
479 status
= EFI_OUT_OF_RESOURCES
;
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
);
488 if (!(Sha256Update(ctx
, hashbase
, hashsize
))) {
489 Print(L
"Unable to generate hash\n");
490 status
= EFI_OUT_OF_RESOURCES
;
495 SumOfBytesHashed
= context
->PEHdr
->Pe32Plus
.OptionalHeader
.SizeOfHeaders
;
497 Section
= (EFI_IMAGE_SECTION_HEADER
*) (
498 (char *)context
->PEHdr
+ sizeof (UINT32
) +
499 sizeof (EFI_IMAGE_FILE_HEADER
) +
500 context
->PEHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
503 SectionCache
= Section
;
505 for (index
= 0, SumOfSectionBytes
= 0; index
< context
->PEHdr
->Pe32
.FileHeader
.NumberOfSections
; index
++, SectionCache
++) {
506 SumOfSectionBytes
+= SectionCache
->SizeOfRawData
;
509 if (SumOfSectionBytes
>= datasize
) {
510 Print(L
"Malformed binary: %x %x\n", SumOfSectionBytes
, size
);
511 status
= EFI_INVALID_PARAMETER
;
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
;
522 /* Sort the section headers */
523 for (index
= 0; index
< context
->PEHdr
->Pe32
.FileHeader
.NumberOfSections
; index
++) {
525 while ((pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[pos
- 1].PointerToRawData
)) {
526 CopyMem (&SectionHeader
[pos
], &SectionHeader
[pos
- 1], sizeof (EFI_IMAGE_SECTION_HEADER
));
529 CopyMem (&SectionHeader
[pos
], Section
, sizeof (EFI_IMAGE_SECTION_HEADER
));
533 /* Hash the sections */
534 for (index
= 0; index
< context
->PEHdr
->Pe32
.FileHeader
.NumberOfSections
; index
++) {
535 Section
= &SectionHeader
[index
];
536 if (Section
->SizeOfRawData
== 0) {
539 hashbase
= ImageAddress(data
, size
, Section
->PointerToRawData
);
540 hashsize
= (unsigned int) Section
->SizeOfRawData
;
543 Print(L
"Malformed section header\n");
544 return EFI_INVALID_PARAMETER
;
547 if (!(Sha256Update(ctx
, hashbase
, hashsize
))) {
548 Print(L
"Unable to generate hash\n");
549 status
= EFI_OUT_OF_RESOURCES
;
552 SumOfBytesHashed
+= Section
->SizeOfRawData
;
555 /* Hash all remaining data */
556 if (size
> SumOfBytesHashed
) {
557 hashbase
= data
+ SumOfBytesHashed
;
558 hashsize
= (unsigned int)(
560 context
->PEHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
-
563 if (!(Sha256Update(ctx
, hashbase
, hashsize
))) {
564 Print(L
"Unable to generate hash\n");
565 status
= EFI_OUT_OF_RESOURCES
;
570 if (!(Sha256Final(ctx
, hash
))) {
571 Print(L
"Unable to finalise hash\n");
572 status
= EFI_OUT_OF_RESOURCES
;
576 status
= check_blacklist(cert
, hash
);
578 if (status
!= EFI_SUCCESS
) {
579 Print(L
"Binary is blacklisted\n");
584 status
= check_whitelist(cert
, hash
);
586 if (status
== EFI_SUCCESS
) {
587 Print(L
"Binary is whitelisted\n");
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");
601 status
= get_variable(L
"MokList", shim_lock_guid
, &attributes
,
602 &MokListDataSize
, &MokListData
);
604 if (status
!= EFI_SUCCESS
) {
605 status
= EFI_ACCESS_DENIED
;
606 Print(L
"Invalid signature\n");
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");
615 status
= EFI_ACCESS_DENIED
;
619 CopyMem(&MokNum
, MokListData
, sizeof(UINT32
));
621 status
= EFI_ACCESS_DENIED
;
625 list
= build_mok_list(MokNum
,
626 (void *)MokListData
+ sizeof(UINT32
),
627 MokListDataSize
- sizeof(UINT32
));
630 Print(L
"Failed to construct MOK list\n");
631 status
= EFI_OUT_OF_RESOURCES
;
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");
645 Print(L
"Invalid signature\n");
646 status
= EFI_ACCESS_DENIED
;
650 FreePool(SectionHeader
);
658 * Read the binary header and grab appropriate information from it
660 static EFI_STATUS
read_header(void *data
, unsigned int datasize
,
661 PE_COFF_LOADER_IMAGE_CONTEXT
*context
)
663 EFI_IMAGE_DOS_HEADER
*DosHdr
= data
;
664 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PEHdr
= data
;
666 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
)
667 PEHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((char *)data
+ DosHdr
->e_lfanew
);
669 if (PEHdr
->Te
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
670 Print(L
"Unsupported image type\n");
671 return EFI_UNSUPPORTED
;
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
;
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
;
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
];
695 if (context
->SecDir
->VirtualAddress
>= datasize
) {
696 Print(L
"Malformed security header\n");
697 return EFI_INVALID_PARAMETER
;
700 if (context
->SecDir
->Size
== 0) {
701 Print(L
"Empty security header\n");
702 return EFI_INVALID_PARAMETER
;
709 * Once the image has been loaded it needs to be validated and relocated
711 static EFI_STATUS
handle_image (void *data
, unsigned int datasize
,
712 EFI_LOADED_IMAGE
*li
)
714 EFI_STATUS efi_status
;
717 EFI_IMAGE_SECTION_HEADER
*Section
;
719 PE_COFF_LOADER_IMAGE_CONTEXT context
;
721 efi_status
= read_header(data
, datasize
, &context
);
722 if (efi_status
!= EFI_SUCCESS
) {
723 Print(L
"Failed to read header\n");
727 if (secure_mode ()) {
728 efi_status
= verify_buffer(data
, datasize
, &context
, 0);
730 if (efi_status
!= EFI_SUCCESS
) {
731 Print(L
"Verification failed\n");
736 buffer
= AllocatePool(context
.ImageSize
);
739 Print(L
"Failed to allocate image buffer\n");
740 return EFI_OUT_OF_RESOURCES
;
743 CopyMem(buffer
, data
, context
.SizeOfHeaders
);
745 Section
= context
.FirstSection
;
746 for (i
= 0; i
< context
.NumberOfSections
; i
++) {
747 size
= Section
->Misc
.VirtualSize
;
749 if (size
> Section
->SizeOfRawData
)
750 size
= Section
->SizeOfRawData
;
752 base
= ImageAddress (buffer
, context
.ImageSize
, Section
->VirtualAddress
);
753 end
= ImageAddress (buffer
, context
.ImageSize
, Section
->VirtualAddress
+ size
- 1);
756 Print(L
"Invalid section size\n");
757 return EFI_UNSUPPORTED
;
760 if (Section
->SizeOfRawData
> 0)
761 CopyMem(base
, data
+ Section
->PointerToRawData
, size
);
763 if (size
< Section
->Misc
.VirtualSize
)
764 ZeroMem (base
+ size
, Section
->Misc
.VirtualSize
- size
);
769 efi_status
= relocate_coff(&context
, buffer
);
771 if (efi_status
!= EFI_SUCCESS
) {
772 Print(L
"Relocation failed\n");
777 entry_point
= ImageAddress(buffer
, context
.ImageSize
, context
.EntryPoint
);
778 li
->ImageBase
= buffer
;
779 li
->ImageSize
= context
.ImageSize
;
782 Print(L
"Invalid entry point\n");
784 return EFI_UNSUPPORTED
;
790 static EFI_STATUS
generate_path(EFI_LOADED_IMAGE
*li
, CHAR16
*ImagePath
,
791 EFI_DEVICE_PATH
**grubpath
, CHAR16
**PathName
)
793 EFI_DEVICE_PATH
*devpath
;
796 unsigned int pathlen
= 0;
797 EFI_STATUS efi_status
= EFI_SUCCESS
;
800 device
= li
->DeviceHandle
;
801 devpath
= li
->FilePath
;
803 bootpath
= DevicePathToStr(devpath
);
805 pathlen
= StrLen(bootpath
);
807 for (i
=pathlen
; i
>0; i
--) {
808 if (bootpath
[i
] == '\\')
812 bootpath
[i
+1] = '\0';
814 if (bootpath
[i
-i
] == '\\')
817 *PathName
= AllocatePool(StrSize(bootpath
) + StrSize(ImagePath
));
820 Print(L
"Failed to allocate path buffer\n");
821 efi_status
= EFI_OUT_OF_RESOURCES
;
826 StrCat(*PathName
, bootpath
);
827 StrCat(*PathName
, ImagePath
);
829 *grubpath
= FileDevicePath(device
, *PathName
);
836 * Locate the second stage bootloader and read it into a buffer
838 static EFI_STATUS
load_image (EFI_LOADED_IMAGE
*li
, void **data
,
839 int *datasize
, CHAR16
*PathName
)
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
;
845 EFI_FILE_INFO
*fileinfo
= NULL
;
846 EFI_FILE_IO_INTERFACE
*drive
;
847 EFI_FILE
*root
, *grub
;
848 UINTN buffersize
= sizeof(EFI_FILE_INFO
);
850 device
= li
->DeviceHandle
;
852 efi_status
= uefi_call_wrapper(BS
->HandleProtocol
, 3, device
,
853 &simple_file_system_protocol
, &drive
);
855 if (efi_status
!= EFI_SUCCESS
) {
856 Print(L
"Failed to find fs\n");
860 efi_status
= uefi_call_wrapper(drive
->OpenVolume
, 2, drive
, &root
);
862 if (efi_status
!= EFI_SUCCESS
) {
863 Print(L
"Failed to open fs\n");
867 efi_status
= uefi_call_wrapper(root
->Open
, 5, root
, &grub
, PathName
,
868 EFI_FILE_MODE_READ
, 0);
870 if (efi_status
!= EFI_SUCCESS
) {
871 Print(L
"Failed to open %s - %lx\n", PathName
, efi_status
);
875 fileinfo
= AllocatePool(buffersize
);
878 Print(L
"Unable to allocate file info buffer\n");
879 efi_status
= EFI_OUT_OF_RESOURCES
;
883 efi_status
= uefi_call_wrapper(grub
->GetInfo
, 4, grub
, &file_info_id
,
884 &buffersize
, fileinfo
);
886 if (efi_status
== EFI_BUFFER_TOO_SMALL
) {
887 fileinfo
= AllocatePool(buffersize
);
889 Print(L
"Unable to allocate file info buffer\n");
890 efi_status
= EFI_OUT_OF_RESOURCES
;
893 efi_status
= uefi_call_wrapper(grub
->GetInfo
, 4, grub
,
894 &file_info_id
, &buffersize
,
898 if (efi_status
!= EFI_SUCCESS
) {
899 Print(L
"Unable to get file info\n");
903 buffersize
= fileinfo
->FileSize
;
905 *data
= AllocatePool(buffersize
);
908 Print(L
"Unable to allocate file buffer\n");
909 efi_status
= EFI_OUT_OF_RESOURCES
;
912 efi_status
= uefi_call_wrapper(grub
->Read
, 3, grub
, &buffersize
,
915 if (efi_status
== EFI_BUFFER_TOO_SMALL
) {
917 *data
= AllocatePool(buffersize
);
918 efi_status
= uefi_call_wrapper(grub
->Read
, 3, grub
,
922 if (efi_status
!= EFI_SUCCESS
) {
923 Print(L
"Unexpected return from initial read: %x, buffersize %x\n", efi_status
, buffersize
);
927 *datasize
= buffersize
;
942 EFI_STATUS
shim_verify (void *buffer
, UINT32 size
)
945 PE_COFF_LOADER_IMAGE_CONTEXT context
;
950 status
= read_header(buffer
, size
, &context
);
952 if (status
!= EFI_SUCCESS
)
955 status
= verify_buffer(buffer
, size
, &context
, 1);
960 EFI_STATUS
start_image(EFI_HANDLE image_handle
, CHAR16
*ImagePath
)
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
;
971 efi_status
= uefi_call_wrapper(BS
->HandleProtocol
, 3, image_handle
,
972 &loaded_image_protocol
, &li
);
974 if (efi_status
!= EFI_SUCCESS
) {
975 Print(L
"Unable to init protocol\n");
979 efi_status
= generate_path(li
, ImagePath
, &path
, &PathName
);
981 if (efi_status
!= EFI_SUCCESS
) {
982 Print(L
"Unable to generate path: %s\n", ImagePath
);
986 efi_status
= uefi_call_wrapper(BS
->LoadImage
, 6, FALSE
, image_handle
,
987 path
, NULL
, 0, &handle
);
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
,
994 uefi_call_wrapper(BS
->UnloadImage
, 1, handle
);
998 efi_status
= load_image(li
, &data
, &datasize
, PathName
);
1000 if (efi_status
!= EFI_SUCCESS
) {
1001 Print(L
"Failed to load image\n");
1005 CopyMem(&li_bak
, li
, sizeof(li_bak
));
1007 efi_status
= handle_image(data
, datasize
, li
);
1009 if (efi_status
!= EFI_SUCCESS
) {
1010 Print(L
"Failed to load image\n");
1011 CopyMem(li
, &li_bak
, sizeof(li_bak
));
1015 efi_status
= uefi_call_wrapper(entry_point
, 3, image_handle
, systab
);
1017 CopyMem(li
, &li_bak
, sizeof(li_bak
));
1022 EFI_STATUS
init_grub(EFI_HANDLE image_handle
)
1024 EFI_STATUS efi_status
;
1026 efi_status
= start_image(image_handle
, SECOND_STAGE
);
1028 if (efi_status
!= EFI_SUCCESS
) {
1029 Print(L
"Failed to start grub\n");
1037 EFI_STATUS
mirror_mok_list()
1039 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1040 EFI_STATUS efi_status
;
1045 efi_status
= get_variable(L
"MokList", shim_lock_guid
, &attributes
,
1048 if (efi_status
!= EFI_SUCCESS
) {
1052 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokListRT",
1054 EFI_VARIABLE_BOOTSERVICE_ACCESS
1055 | EFI_VARIABLE_RUNTIME_ACCESS
,
1057 if (efi_status
!= EFI_SUCCESS
) {
1058 Print(L
"Failed to set MokListRT %d\n", efi_status
);
1065 EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
1067 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1068 EFI_STATUS efi_status
;
1069 UINTN size
= sizeof(UINT32
);
1076 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokNew",
1077 &shim_lock_guid
, &attributes
,
1078 &size
, (void *)&MokNew
);
1080 if (efi_status
!= EFI_SUCCESS
&& efi_status
!= EFI_BUFFER_TOO_SMALL
)
1083 efi_status
= start_image(image_handle
, MOK_MANAGER
);
1085 if (efi_status
!= EFI_SUCCESS
) {
1086 Print(L
"Failed to start MokManager\n");
1094 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*passed_systab
)
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
;
1101 shim_lock_interface
.Verify
= shim_verify
;
1103 systab
= passed_systab
;
1105 InitializeLib(image_handle
, systab
);
1107 efi_status
= check_mok_request(image_handle
);
1109 efi_status
= mirror_mok_list();
1111 uefi_call_wrapper(BS
->InstallProtocolInterface
, 4, &handle
,
1112 &shim_lock_guid
, EFI_NATIVE_INTERFACE
,
1113 &shim_lock_interface
);
1115 efi_status
= init_grub(image_handle
);
1117 uefi_call_wrapper(BS
->UninstallProtocolInterface
, 3, handle
,
1118 &shim_lock_guid
, &shim_lock_interface
);