]> git.proxmox.com Git - efi-boot-shim.git/blame - shim.c
Make sure we don't try to load a binary from a different arch.
[efi-boot-shim.git] / shim.c
CommitLineData
f898777d
MG
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
b2fe1780
MG
36#include <efi.h>
37#include <efilib.h>
7f055335 38#include <Library/BaseCryptLib.h>
b2fe1780 39#include "PeImage.h"
f4b24734 40#include "shim.h"
1c595706 41#include "netboot.h"
ef8c9962 42#include "shim_cert.h"
cbef697a 43#include "replacements.h"
6e1bd3dc 44#include "ucs2.h"
b2fe1780 45
53862dda 46#include "guid.h"
7f0208a0 47#include "variables.h"
53862dda 48#include "efiauthenticated.h"
59dcd9d1 49#include "security_policy.h"
bc71a15e 50#include "console.h"
0fb089ee 51#include "version.h"
53862dda 52
6d6b0221 53#define FALLBACK L"\\fallback.efi"
4b34567d 54#define MOK_MANAGER L"\\MokManager.efi"
f898777d 55
7f055335
MG
56static EFI_SYSTEM_TABLE *systab;
57static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
58
09e2c939
GCPL
59static CHAR16 *second_stage;
60static void *load_options;
61static UINT32 load_options_size;
e50cfe37
GCPL
62static UINT8 in_protocol;
63
64#define perror(fmt, ...) ({ \
65 UINTN __perror_ret = 0; \
66 if (in_protocol) \
67 __perror_ret = Print((fmt), ##__VA_ARGS__); \
68 __perror_ret; \
69 })
09e2c939 70
cb59de38
PJ
71EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
72
f898777d
MG
73/*
74 * The vendor certificate used for validating the second stage loader
75 */
a1f28635
PJ
76extern struct {
77 UINT32 vendor_cert_size;
78 UINT32 vendor_dbx_size;
79 UINT32 vendor_cert_offset;
80 UINT32 vendor_dbx_offset;
81} cert_table;
82
83UINT32 vendor_cert_size;
84UINT32 vendor_dbx_size;
85UINT8 *vendor_cert;
86UINT8 *vendor_dbx;
b2fe1780 87
cbef697a
PJ
88/*
89 * indicator of how an image has been verified
90 */
91verification_method_t verification_method;
92int loader_is_participating;
93
c13fc2f7
MG
94#define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
95
e60f1181 96UINT8 user_insecure_mode;
47ebeb62 97UINT8 ignore_db;
9eaadb0d 98
c16548d0
MG
99typedef enum {
100 DATA_FOUND,
101 DATA_NOT_FOUND,
102 VAR_NOT_FOUND
103} CHECK_STATUS;
104
13422973
GCPL
105typedef struct {
106 UINT32 MokSize;
107 UINT8 *Mok;
108} MokListNode;
109
f898777d
MG
110/*
111 * Perform basic bounds checking of the intra-image pointers
112 */
47a9d2c9 113static void *ImageAddress (void *image, unsigned int size, unsigned int address)
b2fe1780 114{
f898777d
MG
115 if (address > size)
116 return NULL;
9d56c38f 117
f898777d
MG
118 return image + address;
119}
9d56c38f 120
f898777d
MG
121/*
122 * Perform the actual relocation
123 */
7db60bd8
MG
124static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
125 void *data)
f898777d
MG
126{
127 EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
128 UINT64 Adjust;
129 UINT16 *Reloc, *RelocEnd;
130 char *Fixup, *FixupBase, *FixupData = NULL;
131 UINT16 *Fixup16;
132 UINT32 *Fixup32;
133 UINT64 *Fixup64;
134 int size = context->ImageSize;
7db60bd8 135 void *ImageEnd = (char *)data + size;
9d56c38f 136
b6a12d99 137#if __LP64__
7db60bd8 138 context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)data;
b6a12d99
M
139#else
140 context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)data;
141#endif
7f055335 142
f898777d 143 if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
e50cfe37 144 perror(L"Image has no relocation entry\n");
f898777d 145 return EFI_UNSUPPORTED;
7f055335
MG
146 }
147
4ca60879
AB
148 if (!context->RelocDir->Size)
149 return EFI_SUCCESS;
150
7db60bd8
MG
151 RelocBase = ImageAddress(data, size, context->RelocDir->VirtualAddress);
152 RelocBaseEnd = ImageAddress(data, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
9d56c38f 153
f898777d 154 if (!RelocBase || !RelocBaseEnd) {
e50cfe37 155 perror(L"Reloc table overflows binary\n");
f898777d 156 return EFI_UNSUPPORTED;
9d56c38f
MG
157 }
158
b6a12d99 159 Adjust = (UINTN)data - context->ImageAddress;
9d56c38f 160
a3beb2a6
PJ
161 if (Adjust == 0)
162 return EFI_SUCCESS;
163
f898777d
MG
164 while (RelocBase < RelocBaseEnd) {
165 Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
9d56c38f 166
a3beb2a6 167 if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > context->RelocDir->Size)) {
e50cfe37 168 perror(L"Reloc block size is invalid\n");
a3beb2a6
PJ
169 return EFI_UNSUPPORTED;
170 }
171
172 RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
7db60bd8 173 if ((void *)RelocEnd < data || (void *)RelocEnd > ImageEnd) {
e50cfe37 174 perror(L"Reloc entry overflows binary\n");
f898777d 175 return EFI_UNSUPPORTED;
9d56c38f
MG
176 }
177
7db60bd8 178 FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
f898777d 179 if (!FixupBase) {
e50cfe37 180 perror(L"Invalid fixupbase\n");
f898777d 181 return EFI_UNSUPPORTED;
9d56c38f 182 }
9d56c38f 183
f898777d
MG
184 while (Reloc < RelocEnd) {
185 Fixup = FixupBase + (*Reloc & 0xFFF);
186 switch ((*Reloc) >> 12) {
187 case EFI_IMAGE_REL_BASED_ABSOLUTE:
188 break;
9d56c38f 189
f898777d
MG
190 case EFI_IMAGE_REL_BASED_HIGH:
191 Fixup16 = (UINT16 *) Fixup;
192 *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
193 if (FixupData != NULL) {
194 *(UINT16 *) FixupData = *Fixup16;
195 FixupData = FixupData + sizeof (UINT16);
196 }
197 break;
9d56c38f 198
f898777d
MG
199 case EFI_IMAGE_REL_BASED_LOW:
200 Fixup16 = (UINT16 *) Fixup;
201 *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
202 if (FixupData != NULL) {
203 *(UINT16 *) FixupData = *Fixup16;
204 FixupData = FixupData + sizeof (UINT16);
205 }
206 break;
b2fe1780 207
f898777d
MG
208 case EFI_IMAGE_REL_BASED_HIGHLOW:
209 Fixup32 = (UINT32 *) Fixup;
210 *Fixup32 = *Fixup32 + (UINT32) Adjust;
211 if (FixupData != NULL) {
212 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
213 *(UINT32 *)FixupData = *Fixup32;
214 FixupData = FixupData + sizeof (UINT32);
215 }
216 break;
b2fe1780 217
f898777d
MG
218 case EFI_IMAGE_REL_BASED_DIR64:
219 Fixup64 = (UINT64 *) Fixup;
220 *Fixup64 = *Fixup64 + (UINT64) Adjust;
221 if (FixupData != NULL) {
222 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
223 *(UINT64 *)(FixupData) = *Fixup64;
224 FixupData = FixupData + sizeof(UINT64);
225 }
226 break;
b2fe1780 227
f898777d 228 default:
e50cfe37 229 perror(L"Unknown relocation\n");
f898777d
MG
230 return EFI_UNSUPPORTED;
231 }
232 Reloc += 1;
0e6b0195 233 }
f898777d 234 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
7f055335 235 }
b2fe1780
MG
236
237 return EFI_SUCCESS;
238}
239
b8070380
GCPL
240static BOOLEAN verify_x509(UINT8 *Cert, UINTN CertSize)
241{
242 UINTN length;
243
244 if (!Cert || CertSize < 4)
245 return FALSE;
246
247 /*
248 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
249 * the number of length bytes, and the number of value bytes.
250 * The size of a x509 certificate is usually between 127 bytes
251 * and 64KB. For convenience, assume the number of value bytes
252 * is 2, i.e. the second byte is 0x82.
253 */
254 if (Cert[0] != 0x30 || Cert[1] != 0x82)
255 return FALSE;
256
257 length = Cert[2]<<8 | Cert[3];
258 if (length != (CertSize - 4))
259 return FALSE;
260
261 return TRUE;
262}
263
5f0a358b
PJ
264static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
265 UINTN dbsize,
266 WIN_CERTIFICATE_EFI_PKCS *data,
267 UINT8 *hash)
3df68c18 268{
3df68c18 269 EFI_SIGNATURE_DATA *Cert;
b8070380 270 UINTN CertSize;
c13fc2f7 271 BOOLEAN IsFound = FALSE;
53862dda 272 EFI_GUID CertType = X509_GUID;
c16548d0 273
c16548d0 274 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
c13fc2f7 275 if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
c16548d0 276 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
b8070380
GCPL
277 CertSize = CertList->SignatureSize - sizeof(EFI_GUID);
278 if (verify_x509(Cert->SignatureData, CertSize)) {
c16548d0
MG
279 IsFound = AuthenticodeVerify (data->CertData,
280 data->Hdr.dwLength - sizeof(data->Hdr),
281 Cert->SignatureData,
b8070380 282 CertSize,
c16548d0 283 hash, SHA256_DIGEST_SIZE);
7430b901 284 if (IsFound)
b8070380
GCPL
285 return DATA_FOUND;
286 } else if (verbose) {
287 console_notify(L"Not a DER encoding x.509 Certificate");
c16548d0 288 }
c16548d0
MG
289 }
290
291 dbsize -= CertList->SignatureListSize;
292 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
293 }
294
c16548d0
MG
295 return DATA_NOT_FOUND;
296}
297
5f0a358b
PJ
298static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
299 WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash)
c16548d0 300{
5f0a358b 301 CHECK_STATUS rc;
c16548d0 302 EFI_STATUS efi_status;
c16548d0 303 EFI_SIGNATURE_LIST *CertList;
c16548d0 304 UINTN dbsize = 0;
7f0208a0 305 UINT8 *db;
3df68c18 306
7f0208a0 307 efi_status = get_variable(dbname, &db, &dbsize, guid);
3df68c18 308
5f0a358b 309 if (efi_status != EFI_SUCCESS)
c16548d0 310 return VAR_NOT_FOUND;
3df68c18 311
7f0208a0 312 CertList = (EFI_SIGNATURE_LIST *)db;
3df68c18 313
5f0a358b
PJ
314 rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
315
316 FreePool(db);
317
318 return rc;
319}
320
20f6cde6
MG
321/*
322 * Check a hash against an EFI_SIGNATURE_LIST in a buffer
323 */
5f0a358b
PJ
324static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
325 UINTN dbsize, UINT8 *data,
326 int SignatureSize, EFI_GUID CertType)
327{
328 EFI_SIGNATURE_DATA *Cert;
329 UINTN CertCount, Index;
330 BOOLEAN IsFound = FALSE;
331
c16548d0 332 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
d71240bf 333 CertCount = (CertList->SignatureListSize -sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
3df68c18 334 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
c13fc2f7 335 if (CompareGuid(&CertList->SignatureType, &CertType) == 0) {
3df68c18 336 for (Index = 0; Index < CertCount; Index++) {
c16548d0 337 if (CompareMem (Cert->SignatureData, data, SignatureSize) == 0) {
3df68c18
MG
338 //
339 // Find the signature in database.
340 //
341 IsFound = TRUE;
342 break;
343 }
344
345 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
346 }
347 if (IsFound) {
348 break;
349 }
350 }
351
c16548d0 352 dbsize -= CertList->SignatureListSize;
3df68c18
MG
353 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
354 }
355
3df68c18 356 if (IsFound)
c16548d0
MG
357 return DATA_FOUND;
358
359 return DATA_NOT_FOUND;
360}
361
20f6cde6
MG
362/*
363 * Check a hash against an EFI_SIGNATURE_LIST in a UEFI variable
364 */
5f0a358b
PJ
365static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
366 int SignatureSize, EFI_GUID CertType)
367{
368 EFI_STATUS efi_status;
369 EFI_SIGNATURE_LIST *CertList;
5f0a358b 370 UINTN dbsize = 0;
7f0208a0 371 UINT8 *db;
5f0a358b 372
7f0208a0 373 efi_status = get_variable(dbname, &db, &dbsize, guid);
5f0a358b
PJ
374
375 if (efi_status != EFI_SUCCESS) {
376 return VAR_NOT_FOUND;
377 }
378
7f0208a0 379 CertList = (EFI_SIGNATURE_LIST *)db;
5f0a358b
PJ
380
381 CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
382 SignatureSize, CertType);
383 FreePool(db);
384 return rc;
385
386}
387
20f6cde6
MG
388/*
389 * Check whether the binary signature or hash are present in dbx or the
390 * built-in blacklist
391 */
ce6a5748
MG
392static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
393 UINT8 *sha256hash, UINT8 *sha1hash)
c16548d0 394{
0a6565c5 395 EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
92888645 396 EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
0a6565c5 397
92888645 398 if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
53862dda 399 SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
8b7685b2 400 DATA_FOUND)
5f0a358b 401 return EFI_ACCESS_DENIED;
92888645 402 if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
53862dda 403 SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
8b7685b2 404 DATA_FOUND)
5f0a358b 405 return EFI_ACCESS_DENIED;
8044a321
PJ
406 if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
407 sha256hash) == DATA_FOUND)
5f0a358b
PJ
408 return EFI_ACCESS_DENIED;
409
0a6565c5 410 if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
53862dda 411 EFI_CERT_SHA256_GUID) == DATA_FOUND)
c16548d0 412 return EFI_ACCESS_DENIED;
0a6565c5 413 if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
53862dda 414 EFI_CERT_SHA1_GUID) == DATA_FOUND)
ce6a5748 415 return EFI_ACCESS_DENIED;
8044a321
PJ
416 if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
417 DATA_FOUND)
3df68c18
MG
418 return EFI_ACCESS_DENIED;
419
420 return EFI_SUCCESS;
421}
422
cbef697a
PJ
423static void update_verification_method(verification_method_t method)
424{
425 if (verification_method == VERIFIED_BY_NOTHING)
426 verification_method = method;
427}
428
20f6cde6
MG
429/*
430 * Check whether the binary signature or hash are present in db or MokList
431 */
ce6a5748
MG
432static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
433 UINT8 *sha256hash, UINT8 *sha1hash)
b2058cf8 434{
0a6565c5
MG
435 EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
436 EFI_GUID shim_var = SHIM_LOCK_GUID;
437
47ebeb62
JB
438 if (!ignore_db) {
439 if (check_db_hash(L"db", secure_var, sha256hash, SHA256_DIGEST_SIZE,
440 EFI_CERT_SHA256_GUID) == DATA_FOUND) {
441 update_verification_method(VERIFIED_BY_HASH);
442 return EFI_SUCCESS;
443 }
444 if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
445 EFI_CERT_SHA1_GUID) == DATA_FOUND) {
446 verification_method = VERIFIED_BY_HASH;
447 update_verification_method(VERIFIED_BY_HASH);
448 return EFI_SUCCESS;
449 }
8044a321
PJ
450 if (cert && check_db_cert(L"db", secure_var, cert, sha256hash)
451 == DATA_FOUND) {
47ebeb62
JB
452 verification_method = VERIFIED_BY_CERT;
453 update_verification_method(VERIFIED_BY_CERT);
454 return EFI_SUCCESS;
455 }
cbef697a 456 }
47ebeb62 457
0a6565c5 458 if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
cbef697a
PJ
459 EFI_CERT_SHA256_GUID) == DATA_FOUND) {
460 verification_method = VERIFIED_BY_HASH;
461 update_verification_method(VERIFIED_BY_HASH);
0a6565c5 462 return EFI_SUCCESS;
cbef697a 463 }
8044a321
PJ
464 if (cert && check_db_cert(L"MokList", shim_var, cert, sha256hash) ==
465 DATA_FOUND) {
cbef697a
PJ
466 verification_method = VERIFIED_BY_CERT;
467 update_verification_method(VERIFIED_BY_CERT);
b2058cf8 468 return EFI_SUCCESS;
cbef697a 469 }
b2058cf8 470
cbef697a 471 update_verification_method(VERIFIED_BY_NOTHING);
b2058cf8
MG
472 return EFI_ACCESS_DENIED;
473}
474
6279b58e
MG
475/*
476 * Check whether we're in Secure Boot and user mode
477 */
478
479static BOOLEAN secure_mode (void)
480{
e60f1181 481 if (user_insecure_mode)
9eaadb0d
MG
482 return FALSE;
483
7a72592b 484 if (variable_is_secureboot() != 1) {
e50cfe37 485 if (verbose && !in_protocol)
95c6743e 486 console_notify(L"Secure boot not enabled");
6b1f8796
PJ
487 return FALSE;
488 }
6279b58e 489
9ea3d9b4
PJ
490 /* If we /do/ have "SecureBoot", but /don't/ have "SetupMode",
491 * then the implementation is bad, but we assume that secure boot is
492 * enabled according to the status of "SecureBoot". If we have both
493 * of them, then "SetupMode" may tell us additional data, and we need
494 * to consider it.
495 */
496 if (variable_is_setupmode(0) == 1) {
e50cfe37 497 if (verbose && !in_protocol)
95c6743e 498 console_notify(L"Platform is in setup mode");
6279b58e
MG
499 return FALSE;
500 }
501
502 return TRUE;
503}
504
f898777d 505/*
f394b22e 506 * Calculate the SHA1 and SHA256 hashes of a binary
f898777d 507 */
f394b22e 508
47a9d2c9 509static EFI_STATUS generate_hash (char *data, int datasize_in,
f394b22e
MG
510 PE_COFF_LOADER_IMAGE_CONTEXT *context,
511 UINT8 *sha256hash, UINT8 *sha1hash)
512
7f055335 513{
ce6a5748 514 unsigned int sha256ctxsize, sha1ctxsize;
47a9d2c9 515 unsigned int size = datasize_in;
ce6a5748 516 void *sha256ctx = NULL, *sha1ctx = NULL;
7f055335
MG
517 char *hashbase;
518 unsigned int hashsize;
7f055335 519 unsigned int SumOfBytesHashed, SumOfSectionBytes;
3df68c18 520 unsigned int index, pos;
47a9d2c9 521 unsigned int datasize;
7f055335 522 EFI_IMAGE_SECTION_HEADER *Section;
0db1af8a 523 EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
f394b22e 524 EFI_STATUS status = EFI_SUCCESS;
16a83563
PJ
525 EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
526 unsigned int PEHdr_offset = 0;
7f055335 527
47a9d2c9 528 if (datasize_in < 0) {
e50cfe37 529 perror(L"Invalid data size\n");
47a9d2c9
KC
530 return EFI_INVALID_PARAMETER;
531 }
532 size = datasize = (unsigned int)datasize_in;
533
16a83563
PJ
534 if (datasize <= sizeof (*DosHdr) ||
535 DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
e50cfe37 536 perror(L"Invalid signature\n");
16a83563
PJ
537 return EFI_INVALID_PARAMETER;
538 }
539 PEHdr_offset = DosHdr->e_lfanew;
540
541 sha256ctxsize = Sha256GetContextSize();
542 sha256ctx = AllocatePool(sha256ctxsize);
543
544 sha1ctxsize = Sha1GetContextSize();
545 sha1ctx = AllocatePool(sha1ctxsize);
546
ce6a5748 547 if (!sha256ctx || !sha1ctx) {
e50cfe37 548 perror(L"Unable to allocate memory for hash context\n");
7f055335
MG
549 return EFI_OUT_OF_RESOURCES;
550 }
551
ce6a5748 552 if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) {
e50cfe37 553 perror(L"Unable to initialise hash\n");
7f055335
MG
554 status = EFI_OUT_OF_RESOURCES;
555 goto done;
556 }
557
558 /* Hash start to checksum */
7db60bd8 559 hashbase = data;
7f055335
MG
560 hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
561 hashbase;
562
ce6a5748
MG
563 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
564 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e50cfe37 565 perror(L"Unable to generate hash\n");
7f055335
MG
566 status = EFI_OUT_OF_RESOURCES;
567 goto done;
568 }
569
570 /* Hash post-checksum to start of certificate table */
571 hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
572 sizeof (int);
573 hashsize = (char *)context->SecDir - hashbase;
574
ce6a5748
MG
575 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
576 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e50cfe37 577 perror(L"Unable to generate hash\n");
7f055335
MG
578 status = EFI_OUT_OF_RESOURCES;
579 goto done;
580 }
581
582 /* Hash end of certificate table to end of image header */
b6a12d99 583#if __LP64__
7f055335
MG
584 hashbase = (char *) &context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
585 hashsize = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders -
7db60bd8 586 (int) ((char *) (&context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - data);
b6a12d99
M
587#else
588 hashbase = (char *) &context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
589 hashsize = context->PEHdr->Pe32.OptionalHeader.SizeOfHeaders -
590 (int) ((char *) (&context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - data);
591#endif
0db1af8a 592
ce6a5748
MG
593 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
594 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e50cfe37 595 perror(L"Unable to generate hash\n");
7f055335
MG
596 status = EFI_OUT_OF_RESOURCES;
597 goto done;
598 }
599
f898777d 600 /* Sort sections */
b6a12d99 601#if __LP64__
7f055335 602 SumOfBytesHashed = context->PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
b6a12d99
M
603#else
604 SumOfBytesHashed = context->PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
605#endif
7f055335 606
47a9d2c9 607 /* Validate section locations and sizes */
a63d665f 608 for (index = 0, SumOfSectionBytes = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
47a9d2c9
KC
609 EFI_IMAGE_SECTION_HEADER *SectionPtr;
610
611 /* Validate SectionPtr is within image */
612 SectionPtr = ImageAddress(data, datasize,
16a83563 613 PEHdr_offset +
47a9d2c9
KC
614 sizeof (UINT32) +
615 sizeof (EFI_IMAGE_FILE_HEADER) +
616 context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader +
617 (index * sizeof(*SectionPtr)));
618 if (!SectionPtr) {
e50cfe37 619 perror(L"Malformed section %d\n", index);
47a9d2c9
KC
620 status = EFI_INVALID_PARAMETER;
621 goto done;
622 }
623 /* Validate section size is within image. */
624 if (SectionPtr->SizeOfRawData >
625 datasize - SumOfBytesHashed - SumOfSectionBytes) {
e50cfe37 626 perror(L"Malformed section %d size\n", index);
47a9d2c9
KC
627 status = EFI_INVALID_PARAMETER;
628 goto done;
629 }
630 SumOfSectionBytes += SectionPtr->SizeOfRawData;
7f055335
MG
631 }
632
633 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * context->PEHdr->Pe32.FileHeader.NumberOfSections);
634 if (SectionHeader == NULL) {
e50cfe37 635 perror(L"Unable to allocate section header\n");
7f055335
MG
636 status = EFI_OUT_OF_RESOURCES;
637 goto done;
638 }
639
47a9d2c9 640 /* Already validated above */
16a83563
PJ
641 Section = ImageAddress(data, datasize,
642 PEHdr_offset +
643 sizeof (UINT32) +
47a9d2c9
KC
644 sizeof (EFI_IMAGE_FILE_HEADER) +
645 context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader);
646
7f055335
MG
647 /* Sort the section headers */
648 for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
649 pos = index;
650 while ((pos > 0) && (Section->PointerToRawData < SectionHeader[pos - 1].PointerToRawData)) {
651 CopyMem (&SectionHeader[pos], &SectionHeader[pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
652 pos--;
653 }
654 CopyMem (&SectionHeader[pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
655 Section += 1;
656 }
657
658 /* Hash the sections */
659 for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
660 Section = &SectionHeader[index];
661 if (Section->SizeOfRawData == 0) {
662 continue;
663 }
cf718e19 664 hashbase = ImageAddress(data, size, Section->PointerToRawData);
7f055335 665
f898777d 666 if (!hashbase) {
e50cfe37 667 perror(L"Malformed section header\n");
cbe21407
MG
668 status = EFI_INVALID_PARAMETER;
669 goto done;
f898777d
MG
670 }
671
47a9d2c9
KC
672 /* Verify hashsize within image. */
673 if (Section->SizeOfRawData >
674 datasize - Section->PointerToRawData) {
e50cfe37 675 perror(L"Malformed section raw size %d\n", index);
47a9d2c9
KC
676 status = EFI_INVALID_PARAMETER;
677 goto done;
678 }
679 hashsize = (unsigned int) Section->SizeOfRawData;
680
ce6a5748
MG
681 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
682 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e50cfe37 683 perror(L"Unable to generate hash\n");
7f055335
MG
684 status = EFI_OUT_OF_RESOURCES;
685 goto done;
686 }
687 SumOfBytesHashed += Section->SizeOfRawData;
688 }
689
690 /* Hash all remaining data */
47a9d2c9 691 if (datasize > SumOfBytesHashed) {
7db60bd8 692 hashbase = data + SumOfBytesHashed;
7f055335 693 hashsize = (unsigned int)(
47a9d2c9 694 datasize -
b6a12d99 695#if __LP64__
7f055335 696 context->PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
b6a12d99
M
697#else
698 context->PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
699#endif
7f055335
MG
700 SumOfBytesHashed);
701
ce6a5748
MG
702 if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
703 !(Sha1Update(sha1ctx, hashbase, hashsize))) {
e50cfe37 704 perror(L"Unable to generate hash\n");
7f055335
MG
705 status = EFI_OUT_OF_RESOURCES;
706 goto done;
707 }
708 }
709
ce6a5748
MG
710 if (!(Sha256Final(sha256ctx, sha256hash)) ||
711 !(Sha1Final(sha1ctx, sha1hash))) {
e50cfe37 712 perror(L"Unable to finalise hash\n");
7f055335
MG
713 status = EFI_OUT_OF_RESOURCES;
714 goto done;
715 }
716
f394b22e
MG
717done:
718 if (SectionHeader)
719 FreePool(SectionHeader);
720 if (sha1ctx)
721 FreePool(sha1ctx);
722 if (sha256ctx)
723 FreePool(sha256ctx);
724
725 return status;
726}
727
20f6cde6
MG
728/*
729 * Ensure that the MOK database hasn't been set or modified from an OS
730 */
0a6565c5
MG
731static EFI_STATUS verify_mok (void) {
732 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
733 EFI_STATUS status = EFI_SUCCESS;
7f0208a0 734 UINT8 *MokListData = NULL;
0a6565c5
MG
735 UINTN MokListDataSize = 0;
736 UINT32 attributes;
737
7f0208a0
GCPL
738 status = get_variable_attr(L"MokList", &MokListData, &MokListDataSize,
739 shim_lock_guid, &attributes);
0a6565c5 740
42426e6e 741 if (!EFI_ERROR(status) && attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
e50cfe37 742 perror(L"MokList is compromised!\nErase all keys in MokList!\n");
0a6565c5 743 if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
e50cfe37 744 perror(L"Failed to erase MokList\n");
42426e6e 745 return EFI_ACCESS_DENIED;
0a6565c5 746 }
0a6565c5
MG
747 }
748
ca2e00d0
GCPL
749 if (MokListData)
750 FreePool(MokListData);
751
0a6565c5
MG
752 return EFI_SUCCESS;
753}
754
f394b22e
MG
755/*
756 * Check that the signature is valid and matches the binary
757 */
758static EFI_STATUS verify_buffer (char *data, int datasize,
0a6565c5 759 PE_COFF_LOADER_IMAGE_CONTEXT *context)
f394b22e 760{
f394b22e
MG
761 UINT8 sha256hash[SHA256_DIGEST_SIZE];
762 UINT8 sha1hash[SHA1_DIGEST_SIZE];
763 EFI_STATUS status = EFI_ACCESS_DENIED;
8044a321 764 WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
f394b22e
MG
765 unsigned int size = datasize;
766
8044a321
PJ
767 if (context->SecDir->Size != 0) {
768 cert = ImageAddress (data, size,
769 context->SecDir->VirtualAddress);
832e5161 770
8044a321 771 if (!cert) {
e50cfe37 772 perror(L"Certificate located outside the image\n");
8044a321
PJ
773 return EFI_INVALID_PARAMETER;
774 }
f394b22e 775
8044a321
PJ
776 if (cert->Hdr.wCertificateType !=
777 WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
e50cfe37 778 perror(L"Unsupported certificate type %x\n",
8044a321
PJ
779 cert->Hdr.wCertificateType);
780 return EFI_UNSUPPORTED;
781 }
f394b22e
MG
782 }
783
784 status = generate_hash(data, datasize, context, sha256hash, sha1hash);
785
786 if (status != EFI_SUCCESS)
787 return status;
788
20f6cde6
MG
789 /*
790 * Check that the MOK database hasn't been modified
791 */
42426e6e
AB
792 status = verify_mok();
793 if (status != EFI_SUCCESS)
794 return status;
0a6565c5 795
20f6cde6
MG
796 /*
797 * Ensure that the binary isn't blacklisted
798 */
ce6a5748 799 status = check_blacklist(cert, sha256hash, sha1hash);
3df68c18
MG
800
801 if (status != EFI_SUCCESS) {
e50cfe37 802 perror(L"Binary is blacklisted\n");
f394b22e 803 return status;
3df68c18
MG
804 }
805
20f6cde6
MG
806 /*
807 * Check whether the binary is whitelisted in any of the firmware
808 * databases
809 */
0a6565c5 810 status = check_whitelist(cert, sha256hash, sha1hash);
4ab978a3 811 if (status == EFI_SUCCESS)
0a6565c5 812 return status;
b2058cf8 813
8044a321
PJ
814 if (cert) {
815 /*
816 * Check against the shim build key
817 */
818 if (AuthenticodeVerify(cert->CertData,
ef8c9962
MG
819 context->SecDir->Size - sizeof(cert->Hdr),
820 shim_cert, sizeof(shim_cert), sha256hash,
821 SHA256_DIGEST_SIZE)) {
8044a321
PJ
822 status = EFI_SUCCESS;
823 return status;
824 }
ef8c9962
MG
825
826
8044a321
PJ
827 /*
828 * And finally, check against shim's built-in key
829 */
830 if (AuthenticodeVerify(cert->CertData,
13422973 831 context->SecDir->Size - sizeof(cert->Hdr),
ce6a5748 832 vendor_cert, vendor_cert_size, sha256hash,
13422973 833 SHA256_DIGEST_SIZE)) {
8044a321
PJ
834 status = EFI_SUCCESS;
835 return status;
836 }
13422973
GCPL
837 }
838
13422973 839 status = EFI_ACCESS_DENIED;
7f055335 840
f898777d
MG
841 return status;
842}
b2fe1780 843
f898777d
MG
844/*
845 * Read the binary header and grab appropriate information from it
846 */
ce78d2d2 847static EFI_STATUS read_header(void *data, unsigned int datasize,
f898777d
MG
848 PE_COFF_LOADER_IMAGE_CONTEXT *context)
849{
7db60bd8
MG
850 EFI_IMAGE_DOS_HEADER *DosHdr = data;
851 EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
b6a12d99 852 unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
b2fe1780 853
cbe21407 854 if (datasize < sizeof(EFI_IMAGE_DOS_HEADER)) {
e50cfe37 855 perror(L"Invalid image\n");
cbe21407
MG
856 return EFI_UNSUPPORTED;
857 }
858
f898777d 859 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
7db60bd8 860 PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
b6a12d99
M
861#if __LP64__
862 context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
863 context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
864 context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
865 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
866#else
867 context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
868 context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
869 context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
870 OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
871#endif
872 context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
b2fe1780 873
b6a12d99 874 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
e50cfe37 875 perror(L"Image header too small\n");
7de74e67
PJ
876 return EFI_UNSUPPORTED;
877 }
878
b6a12d99 879 HeaderWithoutDataDir = OptHeaderSize
7de74e67 880 - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
b6a12d99
M
881 if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
882 context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
e50cfe37 883 perror(L"Image header overflows data directory\n");
7de74e67
PJ
884 return EFI_UNSUPPORTED;
885 }
886
887 SectionHeaderOffset = DosHdr->e_lfanew
888 + sizeof (UINT32)
889 + sizeof (EFI_IMAGE_FILE_HEADER)
b6a12d99
M
890 + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
891 if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
892 <= context->NumberOfSections) {
e50cfe37 893 perror(L"Image sections overflow image size\n");
7de74e67
PJ
894 return EFI_UNSUPPORTED;
895 }
896
b6a12d99
M
897 if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
898 < (UINT32)context->NumberOfSections) {
e50cfe37 899 perror(L"Image sections overflow section headers\n");
7de74e67
PJ
900 return EFI_UNSUPPORTED;
901 }
902
cbe21407 903 if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) {
e50cfe37 904 perror(L"Invalid image\n");
cbe21407
MG
905 return EFI_UNSUPPORTED;
906 }
907
f898777d 908 if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
e50cfe37 909 perror(L"Unsupported image type\n");
f898777d
MG
910 return EFI_UNSUPPORTED;
911 }
b2fe1780 912
f898777d 913 if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
e50cfe37 914 perror(L"Unsupported image - Relocations have been stripped\n");
f898777d
MG
915 return EFI_UNSUPPORTED;
916 }
b2fe1780 917
f898777d 918 context->PEHdr = PEHdr;
b6a12d99 919#if __LP64__
f898777d 920 context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
f898777d
MG
921 context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
922 context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
f898777d 923 context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
b6a12d99
M
924#else
925 context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
926 context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
927 context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
928 context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
929#endif
930 context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
b2fe1780 931
cbe21407 932 if (context->ImageSize < context->SizeOfHeaders) {
e50cfe37 933 perror(L"Invalid image\n");
cbe21407 934 return EFI_UNSUPPORTED;
b2fe1780
MG
935 }
936
47a9d2c9
KC
937 if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) >
938 (datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) {
e50cfe37 939 perror(L"Invalid image\n");
cbe21407
MG
940 return EFI_UNSUPPORTED;
941 }
942
ce78d2d2 943 if (context->SecDir->VirtualAddress >= datasize) {
e50cfe37 944 perror(L"Malformed security header\n");
f898777d
MG
945 return EFI_INVALID_PARAMETER;
946 }
f898777d 947 return EFI_SUCCESS;
b2fe1780
MG
948}
949
00c84188
PJ
950static const UINT16 machine_type =
951#if defined(__x86_64__)
952 IMAGE_FILE_MACHINE_X64;
953#elif defined(__aarch64__)
954 IMAGE_FILE_MACHINE_ARM64;
955#elif defined(__arm__)
956 IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
957#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
958 IMAGE_FILE_MACHINE_I386;
959#elif defined(__ia64__)
960 IMAGE_FILE_MACHINE_IA64;
961#else
962#error this architecture is not supported by shim
963#endif
e50cfe37 964
f898777d
MG
965/*
966 * Once the image has been loaded it needs to be validated and relocated
967 */
000c565c
GCPL
968static EFI_STATUS handle_image (void *data, unsigned int datasize,
969 EFI_LOADED_IMAGE *li)
b2fe1780
MG
970{
971 EFI_STATUS efi_status;
972 char *buffer;
47a9d2c9
KC
973 int i;
974 unsigned int size;
b2fe1780 975 EFI_IMAGE_SECTION_HEADER *Section;
0e6b0195 976 char *base, *end;
b2fe1780 977 PE_COFF_LOADER_IMAGE_CONTEXT context;
7f055335 978
20f6cde6
MG
979 /*
980 * The binary header contains relevant context and section pointers
981 */
ce78d2d2 982 efi_status = read_header(data, datasize, &context);
b2fe1780 983 if (efi_status != EFI_SUCCESS) {
e50cfe37 984 perror(L"Failed to read header: %r\n", efi_status);
b2fe1780
MG
985 return efi_status;
986 }
987
00c84188
PJ
988 if (context.PEHdr->Pe32.FileHeader.Machine != machine_type) {
989 perror(L"Image is for a different architecture\n");
990 return EFI_UNSUPPORTED;
991 }
992
20f6cde6
MG
993 /*
994 * We only need to verify the binary if we're in secure mode
995 */
6279b58e 996 if (secure_mode ()) {
0a6565c5 997 efi_status = verify_buffer(data, datasize, &context);
7f055335 998
4ab978a3
PJ
999 if (EFI_ERROR(efi_status)) {
1000 console_error(L"Verification failed", efi_status);
6279b58e 1001 return efi_status;
4ab978a3
PJ
1002 } else {
1003 if (verbose)
1004 console_notify(L"Verification succeeded");
6279b58e 1005 }
7f055335
MG
1006 }
1007
b2fe1780
MG
1008 buffer = AllocatePool(context.ImageSize);
1009
0e6b0195 1010 if (!buffer) {
e50cfe37 1011 perror(L"Failed to allocate image buffer\n");
0e6b0195
MG
1012 return EFI_OUT_OF_RESOURCES;
1013 }
1014
7db60bd8 1015 CopyMem(buffer, data, context.SizeOfHeaders);
b2fe1780 1016
20f6cde6
MG
1017 /*
1018 * Copy the executable's sections to their desired offsets
1019 */
b2fe1780 1020 Section = context.FirstSection;
4ca60879
AB
1021 for (i = 0; i < context.NumberOfSections; i++, Section++) {
1022 if (Section->Characteristics & 0x02000000)
1023 /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
1024 continue;
1025
b2fe1780
MG
1026 size = Section->Misc.VirtualSize;
1027
1028 if (size > Section->SizeOfRawData)
1029 size = Section->SizeOfRawData;
1030
1031 base = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress);
1032 end = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress + size - 1);
1033
1034 if (!base || !end) {
e50cfe37 1035 perror(L"Invalid section size\n");
b2fe1780 1036 return EFI_UNSUPPORTED;
7de74e67
PJ
1037 }
1038
1039 if (Section->VirtualAddress < context.SizeOfHeaders ||
1040 Section->PointerToRawData < context.SizeOfHeaders) {
e50cfe37 1041 perror(L"Section is inside image headers\n");
7de74e67 1042 return EFI_UNSUPPORTED;
b2fe1780
MG
1043 }
1044
b2fe1780 1045 if (Section->SizeOfRawData > 0)
7db60bd8 1046 CopyMem(base, data + Section->PointerToRawData, size);
b2fe1780
MG
1047
1048 if (size < Section->Misc.VirtualSize)
1049 ZeroMem (base + size, Section->Misc.VirtualSize - size);
b2fe1780
MG
1050 }
1051
20f6cde6
MG
1052 /*
1053 * Run the relocation fixups
1054 */
7db60bd8 1055 efi_status = relocate_coff(&context, buffer);
b2fe1780
MG
1056
1057 if (efi_status != EFI_SUCCESS) {
e50cfe37 1058 perror(L"Relocation failed: %r\n", efi_status);
0db1af8a 1059 FreePool(buffer);
b2fe1780
MG
1060 return efi_status;
1061 }
1062
0e6b0195 1063 entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
20f6cde6
MG
1064 /*
1065 * grub needs to know its location and size in memory, so fix up
1066 * the loaded image protocol values
1067 */
5fe882ba
MG
1068 li->ImageBase = buffer;
1069 li->ImageSize = context.ImageSize;
1070
09e2c939
GCPL
1071 /* Pass the load options to the second stage loader */
1072 li->LoadOptions = load_options;
1073 li->LoadOptionsSize = load_options_size;
1074
0e6b0195 1075 if (!entry_point) {
e50cfe37 1076 perror(L"Invalid entry point\n");
0db1af8a 1077 FreePool(buffer);
0e6b0195
MG
1078 return EFI_UNSUPPORTED;
1079 }
b2fe1780
MG
1080
1081 return EFI_SUCCESS;
1082}
1083
6d6b0221
PJ
1084static int
1085should_use_fallback(EFI_HANDLE image_handle)
1086{
1087 EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
1088 EFI_LOADED_IMAGE *li;
6d6b0221 1089 unsigned int pathlen = 0;
fe8527aa 1090 CHAR16 *bootpath = NULL;
6d6b0221 1091 EFI_FILE_IO_INTERFACE *fio = NULL;
35b0b55b
PJ
1092 EFI_FILE *vh;
1093 EFI_FILE *fh;
6d6b0221 1094 EFI_STATUS rc;
fe8527aa 1095 int ret = 0;
6d6b0221
PJ
1096
1097 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
1098 &loaded_image_protocol, (void **)&li);
c9d11306 1099 if (EFI_ERROR(rc)) {
e50cfe37 1100 perror(L"Could not get image for bootx64.efi: %r\n", rc);
6d6b0221 1101 return 0;
c9d11306 1102 }
6d6b0221 1103
2e7fc28d 1104 bootpath = DevicePathToStr(li->FilePath);
6d6b0221
PJ
1105
1106 /* Check the beginning of the string and the end, to avoid
1107 * caring about which arch this is. */
1108 /* I really don't know why, but sometimes bootpath gives us
1109 * L"\\EFI\\BOOT\\/BOOTX64.EFI". So just handle that here...
1110 */
1111 if (StrnCaseCmp(bootpath, L"\\EFI\\BOOT\\BOOT", 14) &&
1112 StrnCaseCmp(bootpath, L"\\EFI\\BOOT\\/BOOT", 15))
fe8527aa 1113 goto error;
2e7fc28d 1114
6d6b0221
PJ
1115 pathlen = StrLen(bootpath);
1116 if (pathlen < 5 || StrCaseCmp(bootpath + pathlen - 4, L".EFI"))
fe8527aa 1117 goto error;
6d6b0221 1118
6d6b0221 1119 rc = uefi_call_wrapper(BS->HandleProtocol, 3, li->DeviceHandle,
35b0b55b 1120 &FileSystemProtocol, (void **)&fio);
c9d11306 1121 if (EFI_ERROR(rc)) {
e50cfe37 1122 perror(L"Could not get fio for li->DeviceHandle: %r\n", rc);
fe8527aa 1123 goto error;
c9d11306 1124 }
e50cfe37 1125
6d6b0221 1126 rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &vh);
c9d11306 1127 if (EFI_ERROR(rc)) {
e50cfe37 1128 perror(L"Could not open fio volume: %r\n", rc);
fe8527aa 1129 goto error;
c9d11306 1130 }
6d6b0221
PJ
1131
1132 rc = uefi_call_wrapper(vh->Open, 5, vh, &fh, L"\\EFI\\BOOT" FALLBACK,
5bb3e64e 1133 EFI_FILE_MODE_READ, 0);
6d6b0221 1134 if (EFI_ERROR(rc)) {
b32a3ce1
PJ
1135 /* Do not print the error here - this is an acceptable case
1136 * for removable media, where we genuinely don't want
1137 * fallback.efi to exist.
1138 * Print(L"Could not open \"\\EFI\\BOOT%s\": %d\n", FALLBACK,
1139 * rc);
1140 */
6d6b0221 1141 uefi_call_wrapper(vh->Close, 1, vh);
fe8527aa 1142 goto error;
6d6b0221
PJ
1143 }
1144 uefi_call_wrapper(fh->Close, 1, fh);
1145 uefi_call_wrapper(vh->Close, 1, vh);
1146
fe8527aa
GCPL
1147 ret = 1;
1148error:
1149 if (bootpath)
1150 FreePool(bootpath);
1151
1152 return ret;
6d6b0221
PJ
1153}
1154
20f6cde6
MG
1155/*
1156 * Generate the path of an executable given shim's path and the name
1157 * of the executable
1158 */
822d089e 1159static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
c9022560 1160 CHAR16 **PathName)
f898777d 1161{
0db1af8a 1162 EFI_DEVICE_PATH *devpath;
47a9d2c9
KC
1163 unsigned int i;
1164 int j, last = -1;
db54b0a4
MG
1165 unsigned int pathlen = 0;
1166 EFI_STATUS efi_status = EFI_SUCCESS;
bc6aaefa 1167 CHAR16 *bootpath;
f898777d 1168
0db1af8a 1169 devpath = li->FilePath;
f898777d 1170
bc6aaefa 1171 bootpath = DevicePathToStr(devpath);
f898777d 1172
bc6aaefa 1173 pathlen = StrLen(bootpath);
f898777d 1174
f9f81a22
GCPL
1175 /*
1176 * DevicePathToStr() concatenates two nodes with '/'.
1177 * Convert '/' to '\\'.
1178 */
1179 for (i = 0; i < pathlen; i++) {
1180 if (bootpath[i] == '/')
1181 bootpath[i] = '\\';
1182 }
436afcc2 1183
bc6aaefa 1184 for (i=pathlen; i>0; i--) {
436afcc2
GCPL
1185 if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
1186 bootpath[i] = '/';
1187 else if (last == -1 && bootpath[i] == '\\')
1188 last = i;
1189 }
1190
1191 if (last == -1 && bootpath[0] == '\\')
1192 last = 0;
1193 bootpath[last+1] = '\0';
1194
1195 if (last > 0) {
1196 for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
1197 if (bootpath[i] != '/') {
1198 bootpath[j] = bootpath[i];
1199 j++;
1200 }
1201 }
1202 bootpath[j] = '\0';
f898777d
MG
1203 }
1204
f9f81a22
GCPL
1205 while (*ImagePath == '\\')
1206 ImagePath++;
00ced0c1 1207
822d089e 1208 *PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
f898777d 1209
db54b0a4 1210 if (!*PathName) {
e50cfe37 1211 perror(L"Failed to allocate path buffer\n");
0db1af8a
MG
1212 efi_status = EFI_OUT_OF_RESOURCES;
1213 goto error;
f898777d
MG
1214 }
1215
bc6aaefa 1216 *PathName[0] = '\0';
155a76bb
PJ
1217 if (StrnCaseCmp(bootpath, ImagePath, StrLen(bootpath)))
1218 StrCat(*PathName, bootpath);
822d089e 1219 StrCat(*PathName, ImagePath);
db54b0a4 1220
db54b0a4 1221error:
f9f81a22
GCPL
1222 FreePool(bootpath);
1223
db54b0a4
MG
1224 return efi_status;
1225}
1226
1227/*
20f6cde6 1228 * Open the second stage bootloader and read it into a buffer
db54b0a4 1229 */
822d089e
GCPL
1230static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
1231 int *datasize, CHAR16 *PathName)
db54b0a4
MG
1232{
1233 EFI_GUID simple_file_system_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
1234 EFI_GUID file_info_id = EFI_FILE_INFO_ID;
1235 EFI_STATUS efi_status;
1236 EFI_HANDLE device;
1237 EFI_FILE_INFO *fileinfo = NULL;
1238 EFI_FILE_IO_INTERFACE *drive;
1239 EFI_FILE *root, *grub;
6eb1eca4 1240 UINTN buffersize = sizeof(EFI_FILE_INFO);
db54b0a4
MG
1241
1242 device = li->DeviceHandle;
f898777d 1243
20f6cde6
MG
1244 /*
1245 * Open the device
1246 */
0db1af8a 1247 efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
ed711b02
MG
1248 &simple_file_system_protocol,
1249 (void **)&drive);
f898777d 1250
0db1af8a 1251 if (efi_status != EFI_SUCCESS) {
e50cfe37 1252 perror(L"Failed to find fs: %r\n", efi_status);
0db1af8a
MG
1253 goto error;
1254 }
f898777d 1255
0db1af8a
MG
1256 efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
1257
1258 if (efi_status != EFI_SUCCESS) {
e50cfe37 1259 perror(L"Failed to open fs: %r\n", efi_status);
0db1af8a
MG
1260 goto error;
1261 }
f898777d 1262
20f6cde6
MG
1263 /*
1264 * And then open the file
1265 */
f898777d
MG
1266 efi_status = uefi_call_wrapper(root->Open, 5, root, &grub, PathName,
1267 EFI_FILE_MODE_READ, 0);
1268
1269 if (efi_status != EFI_SUCCESS) {
e50cfe37 1270 perror(L"Failed to open %s - %r\n", PathName, efi_status);
0db1af8a
MG
1271 goto error;
1272 }
1273
1274 fileinfo = AllocatePool(buffersize);
1275
1276 if (!fileinfo) {
e50cfe37 1277 perror(L"Unable to allocate file info buffer\n");
0db1af8a
MG
1278 efi_status = EFI_OUT_OF_RESOURCES;
1279 goto error;
f898777d
MG
1280 }
1281
20f6cde6
MG
1282 /*
1283 * Find out how big the file is in order to allocate the storage
1284 * buffer
1285 */
f898777d
MG
1286 efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
1287 &buffersize, fileinfo);
1288
1289 if (efi_status == EFI_BUFFER_TOO_SMALL) {
cbe21407 1290 FreePool(fileinfo);
f898777d
MG
1291 fileinfo = AllocatePool(buffersize);
1292 if (!fileinfo) {
e50cfe37 1293 perror(L"Unable to allocate file info buffer\n");
0db1af8a
MG
1294 efi_status = EFI_OUT_OF_RESOURCES;
1295 goto error;
f898777d
MG
1296 }
1297 efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
1298 &file_info_id, &buffersize,
1299 fileinfo);
1300 }
1301
1302 if (efi_status != EFI_SUCCESS) {
e50cfe37 1303 perror(L"Unable to get file info: %r\n", efi_status);
0db1af8a 1304 goto error;
f898777d
MG
1305 }
1306
1307 buffersize = fileinfo->FileSize;
0db1af8a 1308
7db60bd8 1309 *data = AllocatePool(buffersize);
f898777d 1310
7db60bd8 1311 if (!*data) {
e50cfe37 1312 perror(L"Unable to allocate file buffer\n");
0db1af8a
MG
1313 efi_status = EFI_OUT_OF_RESOURCES;
1314 goto error;
f898777d 1315 }
20f6cde6
MG
1316
1317 /*
1318 * Perform the actual read
1319 */
f898777d 1320 efi_status = uefi_call_wrapper(grub->Read, 3, grub, &buffersize,
7db60bd8 1321 *data);
f898777d 1322
0db1af8a
MG
1323 if (efi_status == EFI_BUFFER_TOO_SMALL) {
1324 FreePool(*data);
1325 *data = AllocatePool(buffersize);
1326 efi_status = uefi_call_wrapper(grub->Read, 3, grub,
1327 &buffersize, *data);
f898777d
MG
1328 }
1329
1330 if (efi_status != EFI_SUCCESS) {
e50cfe37 1331 perror(L"Unexpected return from initial read: %r, buffersize %x\n", efi_status, buffersize);
0db1af8a 1332 goto error;
f898777d
MG
1333 }
1334
7db60bd8 1335 *datasize = buffersize;
f898777d 1336
cbe21407
MG
1337 FreePool(fileinfo);
1338
f898777d 1339 return EFI_SUCCESS;
0db1af8a
MG
1340error:
1341 if (*data) {
1342 FreePool(*data);
1343 *data = NULL;
1344 }
6f161626 1345
0db1af8a
MG
1346 if (fileinfo)
1347 FreePool(fileinfo);
1348 return efi_status;
f898777d
MG
1349}
1350
20f6cde6
MG
1351/*
1352 * Protocol entry point. If secure boot is enabled, verify that the provided
1353 * buffer is signed with a trusted key.
1354 */
db54b0a4 1355EFI_STATUS shim_verify (void *buffer, UINT32 size)
f4b24734
MG
1356{
1357 EFI_STATUS status;
1358 PE_COFF_LOADER_IMAGE_CONTEXT context;
1359
cbef697a 1360 loader_is_participating = 1;
e50cfe37 1361 in_protocol = 1;
cbef697a 1362
6279b58e
MG
1363 if (!secure_mode())
1364 return EFI_SUCCESS;
1365
ce78d2d2 1366 status = read_header(buffer, size, &context);
f4b24734
MG
1367
1368 if (status != EFI_SUCCESS)
e50cfe37 1369 goto done;
f4b24734 1370
0a6565c5 1371 status = verify_buffer(buffer, size, &context);
e50cfe37
GCPL
1372done:
1373 in_protocol = 0;
1374 return status;
1375}
1376
1377static EFI_STATUS shim_hash (char *data, int datasize,
1378 PE_COFF_LOADER_IMAGE_CONTEXT *context,
1379 UINT8 *sha256hash, UINT8 *sha1hash)
1380{
1381 EFI_STATUS status;
1382
1383 in_protocol = 1;
1384 status = generate_hash(data, datasize, context, sha256hash, sha1hash);
1385 in_protocol = 0;
1386
1387 return status;
1388}
1389
1390static EFI_STATUS shim_read_header(void *data, unsigned int datasize,
1391 PE_COFF_LOADER_IMAGE_CONTEXT *context)
1392{
1393 EFI_STATUS status;
1394
1395 in_protocol = 1;
1396 status = read_header(data, datasize, context);
1397 in_protocol = 0;
f4b24734
MG
1398
1399 return status;
1400}
1401
20f6cde6
MG
1402/*
1403 * Load and run an EFI executable
1404 */
cec6a0a9 1405EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
822d089e 1406{
cec6a0a9 1407 EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
822d089e 1408 EFI_STATUS efi_status;
cec6a0a9 1409 EFI_LOADED_IMAGE *li, li_bak;
1c595706
MG
1410 CHAR16 *PathName = NULL;
1411 void *sourcebuffer = NULL;
fbc486b5 1412 UINT64 sourcesize = 0;
822d089e
GCPL
1413 void *data = NULL;
1414 int datasize;
1415
20f6cde6
MG
1416 /*
1417 * We need to refer to the loaded image protocol on the running
1418 * binary in order to find our path
1419 */
cec6a0a9 1420 efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
ed711b02 1421 &loaded_image_protocol, (void **)&li);
cec6a0a9
GCPL
1422
1423 if (efi_status != EFI_SUCCESS) {
e50cfe37 1424 perror(L"Unable to init protocol\n");
cec6a0a9
GCPL
1425 return efi_status;
1426 }
1427
20f6cde6
MG
1428 /*
1429 * Build a new path from the existing one plus the executable name
1430 */
c9022560 1431 efi_status = generate_path(li, ImagePath, &PathName);
cec6a0a9
GCPL
1432
1433 if (efi_status != EFI_SUCCESS) {
e50cfe37 1434 perror(L"Unable to generate path %s: %r\n", ImagePath, efi_status);
cec6a0a9
GCPL
1435 goto done;
1436 }
1437
da49ac6d 1438 if (findNetboot(li->DeviceHandle)) {
1c595706
MG
1439 efi_status = parseNetbootinfo(image_handle);
1440 if (efi_status != EFI_SUCCESS) {
e50cfe37 1441 perror(L"Netboot parsing failed: %r\n", efi_status);
1c595706
MG
1442 return EFI_PROTOCOL_ERROR;
1443 }
1444 efi_status = FetchNetbootimage(image_handle, &sourcebuffer,
1445 &sourcesize);
1446 if (efi_status != EFI_SUCCESS) {
e50cfe37 1447 perror(L"Unable to fetch TFTP image: %r\n", efi_status);
1c595706
MG
1448 return efi_status;
1449 }
1450 data = sourcebuffer;
1451 datasize = sourcesize;
1452 } else {
4ad234f1
MG
1453 /*
1454 * Read the new executable off disk
1455 */
1c595706 1456 efi_status = load_image(li, &data, &datasize, PathName);
822d089e 1457
1c595706 1458 if (efi_status != EFI_SUCCESS) {
e50cfe37 1459 perror(L"Failed to load image %s: %r\n", PathName, efi_status);
1c595706
MG
1460 goto done;
1461 }
822d089e
GCPL
1462 }
1463
20f6cde6
MG
1464 /*
1465 * We need to modify the loaded image protocol entry before running
1466 * the new binary, so back it up
1467 */
822d089e
GCPL
1468 CopyMem(&li_bak, li, sizeof(li_bak));
1469
20f6cde6
MG
1470 /*
1471 * Verify and, if appropriate, relocate and execute the executable
1472 */
822d089e
GCPL
1473 efi_status = handle_image(data, datasize, li);
1474
1475 if (efi_status != EFI_SUCCESS) {
e50cfe37 1476 perror(L"Failed to load image: %r\n", efi_status);
822d089e
GCPL
1477 CopyMem(li, &li_bak, sizeof(li_bak));
1478 goto done;
1479 }
1480
cbef697a
PJ
1481 loader_is_participating = 0;
1482
20f6cde6
MG
1483 /*
1484 * The binary is trusted and relocated. Run it
1485 */
cbe21407 1486 efi_status = uefi_call_wrapper(entry_point, 2, image_handle, systab);
822d089e 1487
20f6cde6
MG
1488 /*
1489 * Restore our original loaded image values
1490 */
822d089e
GCPL
1491 CopyMem(li, &li_bak, sizeof(li_bak));
1492done:
cbe21407
MG
1493 if (PathName)
1494 FreePool(PathName);
1495
1496 if (data)
1497 FreePool(data);
1498
822d089e
GCPL
1499 return efi_status;
1500}
1501
20f6cde6
MG
1502/*
1503 * Load and run grub. If that fails because grub isn't trusted, load and
1504 * run MokManager.
1505 */
db54b0a4 1506EFI_STATUS init_grub(EFI_HANDLE image_handle)
b2fe1780
MG
1507{
1508 EFI_STATUS efi_status;
f4b24734 1509
6d6b0221
PJ
1510 if (should_use_fallback(image_handle))
1511 efi_status = start_image(image_handle, FALLBACK);
1512 else
1513 efi_status = start_image(image_handle, second_stage);
b2fe1780 1514
ef8c9962
MG
1515 if (efi_status != EFI_SUCCESS)
1516 efi_status = start_image(image_handle, MOK_MANAGER);
db54b0a4
MG
1517
1518 return efi_status;
1519}
1520
20f6cde6
MG
1521/*
1522 * Copy the boot-services only MokList variable to the runtime-accessible
1523 * MokListRT variable. It's not marked NV, so the OS can't modify it.
1524 */
a903fb10
GCPL
1525EFI_STATUS mirror_mok_list()
1526{
1527 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1528 EFI_STATUS efi_status;
7f0208a0 1529 UINT8 *Data = NULL;
a903fb10 1530 UINTN DataSize = 0;
4185c7d6
PJ
1531 void *FullData = NULL;
1532 UINTN FullDataSize = 0;
1533 EFI_SIGNATURE_LIST *CertList = NULL;
1534 EFI_SIGNATURE_DATA *CertData = NULL;
1535 uint8_t *p = NULL;
a903fb10 1536
7f0208a0 1537 efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
4185c7d6
PJ
1538 if (efi_status != EFI_SUCCESS)
1539 DataSize = 0;
1540
1541 FullDataSize = DataSize
1542 + sizeof (*CertList)
1543 + sizeof (EFI_GUID)
1544 + vendor_cert_size
1545 ;
1546 FullData = AllocatePool(FullDataSize);
1547 if (!FullData) {
e50cfe37 1548 perror(L"Failed to allocate space for MokListRT\n");
4185c7d6
PJ
1549 return EFI_OUT_OF_RESOURCES;
1550 }
1551 p = FullData;
a903fb10 1552
4185c7d6
PJ
1553 if (efi_status == EFI_SUCCESS && DataSize > 0) {
1554 CopyMem(p, Data, DataSize);
1555 p += DataSize;
a903fb10 1556 }
4185c7d6
PJ
1557 CertList = (EFI_SIGNATURE_LIST *)p;
1558 p += sizeof (*CertList);
1559 CertData = (EFI_SIGNATURE_DATA *)p;
1560 p += sizeof (EFI_GUID);
1561
1562 CertList->SignatureType = EFI_CERT_X509_GUID;
1563 CertList->SignatureListSize = vendor_cert_size
1564 + sizeof (*CertList)
1565 + sizeof (*CertData)
1566 -1;
1567 CertList->SignatureHeaderSize = 0;
1568 CertList->SignatureSize = vendor_cert_size + sizeof (EFI_GUID);
1569
1570 CertData->SignatureOwner = SHIM_LOCK_GUID;
1571 CopyMem(p, vendor_cert, vendor_cert_size);
a903fb10
GCPL
1572
1573 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListRT",
1574 &shim_lock_guid,
1575 EFI_VARIABLE_BOOTSERVICE_ACCESS
1576 | EFI_VARIABLE_RUNTIME_ACCESS,
4185c7d6 1577 FullDataSize, FullData);
a903fb10 1578 if (efi_status != EFI_SUCCESS) {
e50cfe37 1579 perror(L"Failed to set MokListRT: %r\n", efi_status);
a903fb10
GCPL
1580 }
1581
a903fb10
GCPL
1582 return efi_status;
1583}
1584
20f6cde6
MG
1585/*
1586 * Check if a variable exists
1587 */
d5a2d9ea 1588static BOOLEAN check_var(CHAR16 *varname)
4b34567d
GCPL
1589{
1590 EFI_STATUS efi_status;
e470969e 1591 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1041805a 1592 UINTN size = sizeof(UINT32);
801d1b93 1593 UINT32 MokVar;
e470969e
GCPL
1594 UINT32 attributes;
1595
d5a2d9ea 1596 efi_status = uefi_call_wrapper(RT->GetVariable, 5, varname,
1041805a 1597 &shim_lock_guid, &attributes,
d5a2d9ea 1598 &size, (void *)&MokVar);
e470969e 1599
d5a2d9ea
MG
1600 if (efi_status == EFI_SUCCESS || efi_status == EFI_BUFFER_TOO_SMALL)
1601 return TRUE;
4b34567d 1602
d5a2d9ea
MG
1603 return FALSE;
1604}
4b34567d 1605
20f6cde6
MG
1606/*
1607 * If the OS has set any of these variables we need to drop into MOK and
1608 * handle them appropriately
1609 */
d5a2d9ea
MG
1610EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1611{
1612 EFI_STATUS efi_status;
4b34567d 1613
d5a2d9ea 1614 if (check_var(L"MokNew") || check_var(L"MokSB") ||
92a136d8 1615 check_var(L"MokPW") || check_var(L"MokAuth") ||
47ebeb62 1616 check_var(L"MokDel") || check_var(L"MokDB")) {
9272bc5b 1617 efi_status = start_image(image_handle, MOK_MANAGER);
4b34567d 1618
9272bc5b 1619 if (efi_status != EFI_SUCCESS) {
e50cfe37 1620 perror(L"Failed to start MokManager: %r\n", efi_status);
9272bc5b
MG
1621 return efi_status;
1622 }
4b34567d 1623 }
4b34567d 1624
9272bc5b 1625 return EFI_SUCCESS;
4b34567d
GCPL
1626}
1627
20f6cde6
MG
1628/*
1629 * Verify that MokSBState is valid, and if appropriate set insecure mode
1630 */
1631
9eaadb0d
MG
1632static EFI_STATUS check_mok_sb (void)
1633{
1634 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1635 EFI_STATUS status = EFI_SUCCESS;
875eb1b9
GCPL
1636 UINT8 MokSBState;
1637 UINTN MokSBStateSize = sizeof(MokSBState);
9eaadb0d
MG
1638 UINT32 attributes;
1639
e60f1181 1640 user_insecure_mode = 0;
0948ac09
PJ
1641 ignore_db = 0;
1642
875eb1b9
GCPL
1643 status = uefi_call_wrapper(RT->GetVariable, 5, L"MokSBState", &shim_lock_guid,
1644 &attributes, &MokSBStateSize, &MokSBState);
9eaadb0d
MG
1645 if (status != EFI_SUCCESS)
1646 return EFI_ACCESS_DENIED;
1647
20f6cde6
MG
1648 /*
1649 * Delete and ignore the variable if it's been set from or could be
1650 * modified by the OS
1651 */
9eaadb0d 1652 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
e50cfe37 1653 perror(L"MokSBState is compromised! Clearing it\n");
9eaadb0d 1654 if (LibDeleteVariable(L"MokSBState", &shim_lock_guid) != EFI_SUCCESS) {
e50cfe37 1655 perror(L"Failed to erase MokSBState\n");
9eaadb0d
MG
1656 }
1657 status = EFI_ACCESS_DENIED;
1658 } else {
875eb1b9 1659 if (MokSBState == 1) {
e60f1181 1660 user_insecure_mode = 1;
9eaadb0d
MG
1661 }
1662 }
1663
1664 return status;
4b34567d
GCPL
1665}
1666
47ebeb62
JB
1667/*
1668 * Verify that MokDBState is valid, and if appropriate set ignore db mode
1669 */
1670
1671static EFI_STATUS check_mok_db (void)
1672{
1673 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1674 EFI_STATUS status = EFI_SUCCESS;
875eb1b9
GCPL
1675 UINT8 MokDBState;
1676 UINTN MokDBStateSize = sizeof(MokDBStateSize);
47ebeb62
JB
1677 UINT32 attributes;
1678
875eb1b9
GCPL
1679 status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDBState", &shim_lock_guid,
1680 &attributes, &MokDBStateSize, &MokDBState);
47ebeb62
JB
1681 if (status != EFI_SUCCESS)
1682 return EFI_ACCESS_DENIED;
1683
1684 ignore_db = 0;
1685
1686 /*
1687 * Delete and ignore the variable if it's been set from or could be
1688 * modified by the OS
1689 */
1690 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
e50cfe37 1691 perror(L"MokDBState is compromised! Clearing it\n");
47ebeb62 1692 if (LibDeleteVariable(L"MokDBState", &shim_lock_guid) != EFI_SUCCESS) {
e50cfe37 1693 perror(L"Failed to erase MokDBState\n");
47ebeb62
JB
1694 }
1695 status = EFI_ACCESS_DENIED;
1696 } else {
875eb1b9 1697 if (MokDBState == 1) {
47ebeb62
JB
1698 ignore_db = 1;
1699 }
1700 }
1701
47ebeb62
JB
1702 return status;
1703}
1704
1705static EFI_STATUS mok_ignore_db()
1706{
1707 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1708 EFI_STATUS efi_status = EFI_SUCCESS;
1709 UINT8 Data = 1;
1710 UINTN DataSize = sizeof(UINT8);
1711
1712 check_mok_db();
1713
1714 if (ignore_db) {
1715 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokIgnoreDB",
1716 &shim_lock_guid,
1717 EFI_VARIABLE_BOOTSERVICE_ACCESS
1718 | EFI_VARIABLE_RUNTIME_ACCESS,
1719 DataSize, (void *)&Data);
1720 if (efi_status != EFI_SUCCESS) {
e50cfe37 1721 perror(L"Failed to set MokIgnoreDB: %r\n", efi_status);
47ebeb62
JB
1722 }
1723 }
1724
1725 return efi_status;
1726
1727}
1728
09e2c939
GCPL
1729/*
1730 * Check the load options to specify the second stage loader
1731 */
1732EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
1733{
1734 EFI_STATUS status;
1735 EFI_LOADED_IMAGE *li;
1736 CHAR16 *start = NULL, *c;
47a9d2c9
KC
1737 unsigned int i;
1738 int remaining_size = 0;
0283024e 1739 CHAR16 *loader_str = NULL;
47a9d2c9 1740 unsigned int loader_len = 0;
09e2c939
GCPL
1741
1742 second_stage = DEFAULT_LOADER;
1743 load_options = NULL;
1744 load_options_size = 0;
1745
1746 status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
1747 &LoadedImageProtocol, (void **) &li);
1748 if (status != EFI_SUCCESS) {
e50cfe37 1749 perror (L"Failed to get load options: %r\n", status);
09e2c939
GCPL
1750 return status;
1751 }
1752
1753 /* Expect a CHAR16 string with at least one CHAR16 */
1754 if (li->LoadOptionsSize < 4 || li->LoadOptionsSize % 2 != 0) {
1755 return EFI_BAD_BUFFER_SIZE;
1756 }
1757 c = (CHAR16 *)(li->LoadOptions + (li->LoadOptionsSize - 2));
1758 if (*c != L'\0') {
1759 return EFI_BAD_BUFFER_SIZE;
1760 }
1761
0283024e
GCPL
1762 /*
1763 * UEFI shell copies the whole line of the command into LoadOptions.
1764 * We ignore the string before the first L' ', i.e. the name of this
1765 * program.
1766 */
09e2c939
GCPL
1767 for (i = 0; i < li->LoadOptionsSize; i += 2) {
1768 c = (CHAR16 *)(li->LoadOptions + i);
1769 if (*c == L' ') {
1770 *c = L'\0';
1771 start = c + 1;
1772 remaining_size = li->LoadOptionsSize - i - 2;
1773 break;
1774 }
1775 }
1776
0283024e
GCPL
1777 if (!start || remaining_size <= 0)
1778 return EFI_SUCCESS;
6e1bd3dc 1779
0283024e
GCPL
1780 for (i = 0; start[i] != '\0'; i++) {
1781 if (start[i] == L' ' || start[i] == L'\0')
1782 break;
1783 loader_len++;
1784 }
1785
1786 /*
1787 * Setup the name of the alternative loader and the LoadOptions for
1788 * the loader
1789 */
1790 if (loader_len > 0) {
1791 loader_str = AllocatePool((loader_len + 1) * sizeof(CHAR16));
1792 if (!loader_str) {
e50cfe37 1793 perror(L"Failed to allocate loader string\n");
0283024e
GCPL
1794 return EFI_OUT_OF_RESOURCES;
1795 }
1796 for (i = 0; i < loader_len; i++)
1797 loader_str[i] = start[i];
1798 loader_str[loader_len] = L'\0';
1799
1800 second_stage = loader_str;
09e2c939
GCPL
1801 load_options = start;
1802 load_options_size = remaining_size;
1803 }
1804
1805 return EFI_SUCCESS;
1806}
1807
cf90edff
PJ
1808static SHIM_LOCK shim_lock_interface;
1809static EFI_HANDLE shim_lock_handle;
1810
1811EFI_STATUS
1812install_shim_protocols(void)
1813{
1814 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1815 EFI_STATUS efi_status;
1816 /*
1817 * Install the protocol
1818 */
1819 efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
1820 &shim_lock_handle, &shim_lock_guid,
1821 EFI_NATIVE_INTERFACE, &shim_lock_interface);
1822 if (EFI_ERROR(efi_status)) {
1823 console_error(L"Could not install security protocol",
1824 efi_status);
1825 return efi_status;
1826 }
1827
1828#if defined(OVERRIDE_SECURITY_POLICY)
1829 /*
1830 * Install the security protocol hook
1831 */
1832 security_policy_install(shim_verify);
1833#endif
1834
1835 return EFI_SUCCESS;
1836}
1837
1838void
1839uninstall_shim_protocols(void)
db54b0a4
MG
1840{
1841 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
cf90edff
PJ
1842#if defined(OVERRIDE_SECURITY_POLICY)
1843 /*
1844 * Clean up the security protocol hook
1845 */
1846 security_policy_uninstall();
1847#endif
1848
1849 /*
1850 * If we're back here then clean everything up before exiting
1851 */
1852 uefi_call_wrapper(BS->UninstallProtocolInterface, 3, shim_lock_handle,
1853 &shim_lock_guid, &shim_lock_interface);
1854}
1855
1856EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
1857{
0a232ca9 1858 EFI_STATUS efi_status;
db54b0a4 1859
cbef697a
PJ
1860 verification_method = VERIFIED_BY_NOTHING;
1861
a1f28635
PJ
1862 vendor_cert_size = cert_table.vendor_cert_size;
1863 vendor_dbx_size = cert_table.vendor_dbx_size;
1864 vendor_cert = (UINT8 *)&cert_table + cert_table.vendor_cert_offset;
1865 vendor_dbx = (UINT8 *)&cert_table + cert_table.vendor_dbx_offset;
1866
20f6cde6
MG
1867 /*
1868 * Set up the shim lock protocol so that grub and MokManager can
1869 * call back in and use shim functions
1870 */
db54b0a4 1871 shim_lock_interface.Verify = shim_verify;
e50cfe37
GCPL
1872 shim_lock_interface.Hash = shim_hash;
1873 shim_lock_interface.Context = shim_read_header;
db54b0a4
MG
1874
1875 systab = passed_systab;
1876
20f6cde6
MG
1877 /*
1878 * Ensure that gnu-efi functions are available
1879 */
db54b0a4
MG
1880 InitializeLib(image_handle, systab);
1881
bc71a15e 1882 setup_console(1);
4ab978a3 1883 setup_verbosity();
bc71a15e 1884
4ab978a3 1885 dprinta(shim_version);
0fb089ee 1886
09e2c939
GCPL
1887 /* Set the second stage loader */
1888 set_second_stage (image_handle);
1889
20f6cde6
MG
1890 /*
1891 * Check whether the user has configured the system to run in
1892 * insecure mode
1893 */
9eaadb0d
MG
1894 check_mok_sb();
1895
20f6cde6
MG
1896 /*
1897 * Tell the user that we're in insecure mode if necessary
1898 */
e60f1181 1899 if (user_insecure_mode) {
9eaadb0d
MG
1900 Print(L"Booting in insecure mode\n");
1901 uefi_call_wrapper(BS->Stall, 1, 2000000);
e60f1181 1902 } else if (secure_mode()) {
7c1f49da
MG
1903 if (vendor_cert_size || vendor_dbx_size) {
1904 /*
1905 * If shim includes its own certificates then ensure
1906 * that anything it boots has performed some
1907 * validation of the next image.
1908 */
1909 hook_system_services(systab);
1910 loader_is_participating = 0;
1911 }
9eaadb0d
MG
1912 }
1913
cf90edff
PJ
1914 efi_status = install_shim_protocols();
1915 if (EFI_ERROR(efi_status))
1d563059 1916 return efi_status;
59dcd9d1 1917
20f6cde6
MG
1918 /*
1919 * Enter MokManager if necessary
1920 */
4b34567d
GCPL
1921 efi_status = check_mok_request(image_handle);
1922
20f6cde6
MG
1923 /*
1924 * Copy the MOK list to a runtime variable so the kernel can make
1925 * use of it
1926 */
a903fb10
GCPL
1927 efi_status = mirror_mok_list();
1928
47ebeb62
JB
1929 /*
1930 * Create the runtime MokIgnoreDB variable so the kernel can make
1931 * use of it
1932 */
1933 efi_status = mok_ignore_db();
1934
20f6cde6
MG
1935 /*
1936 * Hand over control to the second stage bootloader
1937 */
db54b0a4 1938
0a232ca9
MG
1939 efi_status = init_grub(image_handle);
1940
cf90edff 1941 uninstall_shim_protocols();
59dcd9d1 1942 /*
98a99578 1943 * Remove our hooks from system services.
59dcd9d1 1944 */
98a99578 1945 unhook_system_services();
59dcd9d1 1946
0283024e
GCPL
1947 /*
1948 * Free the space allocated for the alternative 2nd stage loader
1949 */
1950 if (load_options_size > 0)
1951 FreePool(second_stage);
1952
bc71a15e
PJ
1953 setup_console(0);
1954
0a232ca9 1955 return efi_status;
b2fe1780 1956}