summaryrefslogtreecommitdiff
path: root/shim.c
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@canonical.com>2019-02-09 21:28:06 -0800
committerSteve Langasek <steve.langasek@canonical.com>2019-02-09 21:32:44 -0800
commitab4c731c1dd379acd3e95971af57401fb0a650a1 (patch)
tree6a26fb8d0746cbbaa6c2d4b242c73442bcc1df06 /shim.c
parent0d63079c7da8e86104ce4bbdae2f6cb8d2ea40c6 (diff)
parent9c12130f9cd2ae11a9336813dd1f1669c0b64ad0 (diff)
downloadefi-boot-shim-debian/15+1533136590.3beb971-1.tar.gz
efi-boot-shim-debian/15+1533136590.3beb971-1.zip
* New upstream release.debian/15+1533136590.3beb971-1
- debian/patches/second-stage-path: dropped; the default loader path now includes an arch suffix. - debian/patches/sbsigntool-no-pesign: dropped; no longer needed. * Drop remaining patches that were not being applied. * Sync packaging from Ubuntu: - debian/copyright: Update upstream source location. - debian/control: add a Build-Depends on libelf-dev. - Enable arm64 build. - debian/patches/fixup_git.patch: don't run git in clean; we're not really in a git tree. - debian/rules, debian/shim.install: use the upstream install target as intended, and move files to the target directory using dh_install. - define RELEASE and COMMIT_ID for the snapshot. - Set ENABLE_HTTPBOOT to enable the HTTP Boot feature. - Update dh_auto_build/dh_auto_clean/dh_auto_install for new upstream options: set MAKELEVEL. - Define an EFI_ARCH variable, and use that for paths to shim. This makes it possible to build a shim for other architectures than amd64. - Set EFIDIR=$distro for dh_auto_install; that will let files be installed in the "right" final directories, and makes boot.csv for us. - Set ENABLE_SHIM_CERT, to keep using ephemeral self-signed certs built at compile-time for MokManager and fallback. - Set ENABLE_SBSIGN, to use sbsign instead of pesign for signing fallback and MokManager.
Diffstat (limited to 'shim.c')
-rw-r--r--shim.c1309
1 files changed, 606 insertions, 703 deletions
diff --git a/shim.c b/shim.c
index c69961b9..f29f3921 100644
--- a/shim.c
+++ b/shim.c
@@ -33,51 +33,35 @@
* Corporation.
*/
-#include <efi.h>
-#include <efilib.h>
-#include <Library/BaseCryptLib.h>
-#include "PeImage.h"
#include "shim.h"
-#include "netboot.h"
-#include "httpboot.h"
-#include "shim_cert.h"
-#include "replacements.h"
-#include "tpm.h"
-#include "ucs2.h"
-
-#include "guid.h"
-#include "variables.h"
-#include "efiauthenticated.h"
-#include "security_policy.h"
-#include "console.h"
-#include "version.h"
#include <stdarg.h>
+
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <openssl/rsa.h>
+#include <internal/dso.h>
+
+#include <Library/BaseCryptLib.h>
-#define FALLBACK L"\\fb" EFI_ARCH L".efi"
-#define MOK_MANAGER L"\\mm" EFI_ARCH L".efi"
+#include <stdint.h>
#define OID_EKU_MODSIGN "1.3.6.1.4.1.2312.16.1.2"
static EFI_SYSTEM_TABLE *systab;
-static EFI_HANDLE image_handle;
-static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
+static EFI_HANDLE global_image_handle;
static CHAR16 *second_stage;
static void *load_options;
static UINT32 load_options_size;
-static UINT8 in_protocol;
-
-#define perror(fmt, ...) ({ \
- UINTN __perror_ret = 0; \
- if (!in_protocol) \
- __perror_ret = Print((fmt), ##__VA_ARGS__); \
- __perror_ret; \
- })
-
-EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
/*
* The vendor certificate used for validating the second stage loader
@@ -119,11 +103,17 @@ typedef struct {
/*
* Perform basic bounds checking of the intra-image pointers
*/
-static void *ImageAddress (void *image, unsigned int size, unsigned int address)
+static void *ImageAddress (void *image, uint64_t size, uint64_t address)
{
+ /* ensure our local pointer isn't bigger than our size */
if (address > size)
return NULL;
+ /* Insure our math won't overflow */
+ if (UINT64_MAX - address < (uint64_t)(intptr_t)image)
+ return NULL;
+
+ /* return the absolute pointer */
return image + address;
}
@@ -237,7 +227,7 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
UINT64 Adjust;
UINT16 *Reloc, *RelocEnd;
- char *Fixup, *FixupBase, *FixupData = NULL;
+ char *Fixup, *FixupBase;
UINT16 *Fixup16;
UINT32 *Fixup32;
UINT64 *Fixup64;
@@ -245,11 +235,6 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
void *ImageEnd = (char *)orig + size;
int n = 0;
- if (image_is_64_bit(context->PEHdr))
- context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)(unsigned long)data;
- else
- context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)(unsigned long)data;
-
/* Alright, so here's how this works:
*
* context->RelocDir gives us two things:
@@ -297,8 +282,14 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
while (RelocBase < RelocBaseEnd) {
Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
- if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > context->RelocDir->Size)) {
- perror(L"Reloc %d block size %d is invalid\n", n, RelocBase->SizeOfBlock);
+ if (RelocBase->SizeOfBlock == 0) {
+ perror(L"Reloc %d block size 0 is invalid\n", n);
+ return EFI_UNSUPPORTED;
+ } else if (RelocBase->SizeOfBlock > context->RelocDir->Size) {
+ perror(L"Reloc %d block size %d greater than reloc dir"
+ "size %d, which is invalid\n", n,
+ RelocBase->SizeOfBlock,
+ context->RelocDir->Size);
return EFI_UNSUPPORTED;
}
@@ -323,39 +314,21 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
case EFI_IMAGE_REL_BASED_HIGH:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *Fixup16;
- FixupData = FixupData + sizeof (UINT16);
- }
break;
case EFI_IMAGE_REL_BASED_LOW:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *Fixup16;
- FixupData = FixupData + sizeof (UINT16);
- }
break;
case EFI_IMAGE_REL_BASED_HIGHLOW:
Fixup32 = (UINT32 *) Fixup;
*Fixup32 = *Fixup32 + (UINT32) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
- *(UINT32 *)FixupData = *Fixup32;
- FixupData = FixupData + sizeof (UINT32);
- }
break;
case EFI_IMAGE_REL_BASED_DIR64:
Fixup64 = (UINT64 *) Fixup;
*Fixup64 = *Fixup64 + (UINT64) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
- *(UINT64 *)(FixupData) = *Fixup64;
- FixupData = FixupData + sizeof(UINT64);
- }
break;
default:
@@ -371,6 +344,14 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
return EFI_SUCCESS;
}
+static void
+drain_openssl_errors(void)
+{
+ unsigned long err = -1;
+ while (err != 0)
+ err = ERR_get_error();
+}
+
static BOOLEAN verify_x509(UINT8 *Cert, UINTN CertSize)
{
UINTN length;
@@ -422,34 +403,59 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
X509_free(x509);
}
- OBJ_cleanup();
-
return TRUE;
}
+static void show_ca_warning()
+{
+ CHAR16 *text[9];
+
+ text[0] = L"WARNING!";
+ text[1] = L"";
+ text[2] = L"The CA certificate used to verify this image doesn't ";
+ text[3] = L"contain the CA flag in Basic Constraints or KeyCertSign";
+ text[4] = L"in KeyUsage. Such CA certificates will not be supported";
+ text[5] = L"in the future. ";
+ text[6] = L"";
+ text[7] = L"Please contact the issuer to update the certificate. ";
+ text[8] = NULL;
+
+ console_reset();
+ console_print_box(text, -1);
+}
+
static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
UINTN dbsize,
WIN_CERTIFICATE_EFI_PKCS *data,
- UINT8 *hash)
+ UINT8 *hash, CHAR16 *dbname,
+ EFI_GUID guid)
{
EFI_SIGNATURE_DATA *Cert;
UINTN CertSize;
BOOLEAN IsFound = FALSE;
- EFI_GUID CertType = X509_GUID;
while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
- if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
+ if (CompareGuid (&CertList->SignatureType, &EFI_CERT_TYPE_X509_GUID) == 0) {
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
CertSize = CertList->SignatureSize - sizeof(EFI_GUID);
if (verify_x509(Cert->SignatureData, CertSize)) {
if (verify_eku(Cert->SignatureData, CertSize)) {
+ clear_ca_warning();
IsFound = AuthenticodeVerify (data->CertData,
data->Hdr.dwLength - sizeof(data->Hdr),
Cert->SignatureData,
CertSize,
hash, SHA256_DIGEST_SIZE);
- if (IsFound)
+ if (IsFound) {
+ if (get_ca_warning()) {
+ show_ca_warning();
+ }
+ tpm_measure_variable(dbname, guid, CertSize, Cert->SignatureData);
+ drain_openssl_errors();
return DATA_FOUND;
+ } else {
+ LogError(L"AuthenticodeVerify(): %d\n", IsFound);
+ }
}
} else if (verbose) {
console_notify(L"Not a DER encoding x.509 Certificate");
@@ -473,13 +479,12 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
UINT8 *db;
efi_status = get_variable(dbname, &db, &dbsize, guid);
-
- if (efi_status != EFI_SUCCESS)
+ if (EFI_ERROR(efi_status))
return VAR_NOT_FOUND;
CertList = (EFI_SIGNATURE_LIST *)db;
- rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
+ rc = check_db_cert_in_ram(CertList, dbsize, data, hash, dbname, guid);
FreePool(db);
@@ -491,7 +496,8 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
*/
static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
UINTN dbsize, UINT8 *data,
- int SignatureSize, EFI_GUID CertType)
+ int SignatureSize, EFI_GUID CertType,
+ CHAR16 *dbname, EFI_GUID guid)
{
EFI_SIGNATURE_DATA *Cert;
UINTN CertCount, Index;
@@ -507,6 +513,7 @@ static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
// Find the signature in database.
//
IsFound = TRUE;
+ tpm_measure_variable(dbname, guid, SignatureSize, data);
break;
}
@@ -539,15 +546,15 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
UINT8 *db;
efi_status = get_variable(dbname, &db, &dbsize, guid);
-
- if (efi_status != EFI_SUCCESS) {
+ if (EFI_ERROR(efi_status)) {
return VAR_NOT_FOUND;
}
CertList = (EFI_SIGNATURE_LIST *)db;
CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
- SignatureSize, CertType);
+ SignatureSize, CertType,
+ dbname, guid);
FreePool(db);
return rc;
@@ -560,40 +567,55 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
UINT8 *sha256hash, UINT8 *sha1hash)
{
- EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
- EFI_GUID shim_var = SHIM_LOCK_GUID;
EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
- SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
- DATA_FOUND)
- return EFI_ACCESS_DENIED;
- if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
- SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
- DATA_FOUND)
- return EFI_ACCESS_DENIED;
- if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
- sha256hash) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
-
- if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
- EFI_CERT_SHA256_GUID) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
- if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
- EFI_CERT_SHA1_GUID) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
- if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
- DATA_FOUND)
- return EFI_ACCESS_DENIED;
- if (check_db_hash(L"MokListX", shim_var, sha256hash, SHA256_DIGEST_SIZE,
- EFI_CERT_SHA256_GUID) == DATA_FOUND) {
- return EFI_ACCESS_DENIED;
- }
- if (cert && check_db_cert(L"MokListX", shim_var, cert, sha256hash) ==
- DATA_FOUND) {
- return EFI_ACCESS_DENIED;
+ SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID, L"dbx",
+ EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) {
+ LogError(L"binary sha256hash found in vendor dbx\n");
+ return EFI_SECURITY_VIOLATION;
}
-
+ if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
+ SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID, L"dbx",
+ EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) {
+ LogError(L"binary sha1hash found in vendor dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (cert &&
+ check_db_cert_in_ram(dbx, vendor_dbx_size, cert, sha256hash, L"dbx",
+ EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) {
+ LogError(L"cert sha256hash found in vendor dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (check_db_hash(L"dbx", EFI_SECURE_BOOT_DB_GUID, sha256hash,
+ SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) == DATA_FOUND) {
+ LogError(L"binary sha256hash found in system dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (check_db_hash(L"dbx", EFI_SECURE_BOOT_DB_GUID, sha1hash,
+ SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) == DATA_FOUND) {
+ LogError(L"binary sha1hash found in system dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (cert &&
+ check_db_cert(L"dbx", EFI_SECURE_BOOT_DB_GUID,
+ cert, sha256hash) == DATA_FOUND) {
+ LogError(L"cert sha256hash found in system dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (check_db_hash(L"MokListX", SHIM_LOCK_GUID, sha256hash,
+ SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) == DATA_FOUND) {
+ LogError(L"binary sha256hash found in Mok dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (cert &&
+ check_db_cert(L"MokListX", SHIM_LOCK_GUID,
+ cert, sha256hash) == DATA_FOUND) {
+ LogError(L"cert sha256hash found in Mok dbx\n");
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ drain_openssl_errors();
return EFI_SUCCESS;
}
@@ -609,44 +631,52 @@ static void update_verification_method(verification_method_t method)
static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
UINT8 *sha256hash, UINT8 *sha1hash)
{
- EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
- EFI_GUID shim_var = SHIM_LOCK_GUID;
-
if (!ignore_db) {
- if (check_db_hash(L"db", secure_var, sha256hash, SHA256_DIGEST_SIZE,
+ if (check_db_hash(L"db", EFI_SECURE_BOOT_DB_GUID, sha256hash, SHA256_DIGEST_SIZE,
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
+ } else {
+ LogError(L"check_db_hash(db, sha256hash) != DATA_FOUND\n");
}
- if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
+ if (check_db_hash(L"db", EFI_SECURE_BOOT_DB_GUID, sha1hash, SHA1_DIGEST_SIZE,
EFI_CERT_SHA1_GUID) == DATA_FOUND) {
verification_method = VERIFIED_BY_HASH;
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
+ } else {
+ LogError(L"check_db_hash(db, sha1hash) != DATA_FOUND\n");
}
- if (cert && check_db_cert(L"db", secure_var, cert, sha256hash)
+ if (cert && check_db_cert(L"db", EFI_SECURE_BOOT_DB_GUID, cert, sha256hash)
== DATA_FOUND) {
verification_method = VERIFIED_BY_CERT;
update_verification_method(VERIFIED_BY_CERT);
return EFI_SUCCESS;
+ } else {
+ LogError(L"check_db_cert(db, sha256hash) != DATA_FOUND\n");
}
}
- if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
- EFI_CERT_SHA256_GUID) == DATA_FOUND) {
+ if (check_db_hash(L"MokList", SHIM_LOCK_GUID, sha256hash,
+ SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID)
+ == DATA_FOUND) {
verification_method = VERIFIED_BY_HASH;
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
+ } else {
+ LogError(L"check_db_hash(MokList, sha256hash) != DATA_FOUND\n");
}
- if (cert && check_db_cert(L"MokList", shim_var, cert, sha256hash) ==
- DATA_FOUND) {
+ if (cert && check_db_cert(L"MokList", SHIM_LOCK_GUID, cert, sha256hash)
+ == DATA_FOUND) {
verification_method = VERIFIED_BY_CERT;
update_verification_method(VERIFIED_BY_CERT);
return EFI_SUCCESS;
+ } else {
+ LogError(L"check_db_cert(MokList, sha256hash) != DATA_FOUND\n");
}
update_verification_method(VERIFIED_BY_NOTHING);
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
}
/*
@@ -686,12 +716,14 @@ static BOOLEAN secure_mode (void)
#define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \
if ((unsigned long)hashbase > \
(unsigned long)data + datasize_in) { \
+ efi_status = EFI_INVALID_PARAMETER; \
perror(L"shim.c:%d Invalid hash base 0x%016x\n", l, \
hashbase); \
goto done; \
} \
if ((unsigned long)hashbase + hashsize > \
(unsigned long)data + datasize_in) { \
+ efi_status = EFI_INVALID_PARAMETER; \
perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \
hashsize); \
goto done; \
@@ -718,15 +750,11 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
unsigned int datasize;
EFI_IMAGE_SECTION_HEADER *Section;
EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
- EFI_STATUS status = EFI_SUCCESS;
+ EFI_STATUS efi_status = EFI_SUCCESS;
EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
unsigned int PEHdr_offset = 0;
- if (datasize_in < 0) {
- perror(L"Invalid data size\n");
- return EFI_INVALID_PARAMETER;
- }
- size = datasize = (unsigned int)datasize_in;
+ size = datasize = datasize_in;
if (datasize <= sizeof (*DosHdr) ||
DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
@@ -748,7 +776,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!Sha256Init(sha256ctx) || !Sha1Init(sha1ctx)) {
perror(L"Unable to initialise hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -761,7 +789,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) {
perror(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -774,7 +802,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) {
perror(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -784,7 +812,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
if (hashsize > datasize_in) {
perror(L"Data Directory size %d is invalid\n", hashsize);
- status = EFI_INVALID_PARAMETER;
+ efi_status = EFI_INVALID_PARAMETER;
goto done;
}
check_size(data, datasize_in, hashbase, hashsize);
@@ -792,7 +820,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) {
perror(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -812,14 +840,14 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
(index * sizeof(*SectionPtr)));
if (!SectionPtr) {
perror(L"Malformed section %d\n", index);
- status = EFI_INVALID_PARAMETER;
+ efi_status = EFI_INVALID_PARAMETER;
goto done;
}
/* Validate section size is within image. */
if (SectionPtr->SizeOfRawData >
datasize - SumOfBytesHashed - SumOfSectionBytes) {
perror(L"Malformed section %d size\n", index);
- status = EFI_INVALID_PARAMETER;
+ efi_status = EFI_INVALID_PARAMETER;
goto done;
}
SumOfSectionBytes += SectionPtr->SizeOfRawData;
@@ -828,7 +856,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * context->PEHdr->Pe32.FileHeader.NumberOfSections);
if (SectionHeader == NULL) {
perror(L"Unable to allocate section header\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -838,6 +866,19 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader);
+ /* But check it again just for better error messaging, and so
+ * clang-analyzer doesn't get confused. */
+ if (Section == NULL) {
+ uint64_t addr;
+
+ addr = PEHdr_offset + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)
+ + context->PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ perror(L"Malformed file header.\n");
+ perror(L"Image address for Section 0 is 0x%016llx\n", addr);
+ perror(L"File size is 0x%016llx\n", datasize);
+ efi_status = EFI_INVALID_PARAMETER;
+ goto done;
+ }
/* Sort the section headers */
for (index = 0; index < context->PEHdr->Pe32.FileHeader.NumberOfSections; index++) {
@@ -860,7 +901,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!hashbase) {
perror(L"Malformed section header\n");
- status = EFI_INVALID_PARAMETER;
+ efi_status = EFI_INVALID_PARAMETER;
goto done;
}
@@ -868,7 +909,7 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (Section->SizeOfRawData >
datasize - Section->PointerToRawData) {
perror(L"Malformed section raw size %d\n", index);
- status = EFI_INVALID_PARAMETER;
+ efi_status = EFI_INVALID_PARAMETER;
goto done;
}
hashsize = (unsigned int) Section->SizeOfRawData;
@@ -877,30 +918,64 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) {
perror(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
SumOfBytesHashed += Section->SizeOfRawData;
}
+ /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */
+ if (datasize > SumOfBytesHashed && context->SecDir->Size) {
+ hashbase = data + SumOfBytesHashed;
+ hashsize = datasize - context->SecDir->Size - SumOfBytesHashed;
+
+ if ((datasize - SumOfBytesHashed < context->SecDir->Size) ||
+ (SumOfBytesHashed + hashsize != context->SecDir->VirtualAddress)) {
+ perror(L"Malformed binary after Attribute Certificate Table\n");
+ console_print(L"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n",
+ datasize, SumOfBytesHashed, context->SecDir->Size);
+ console_print(L"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n",
+ hashsize, context->SecDir->VirtualAddress);
+ efi_status = EFI_INVALID_PARAMETER;
+ goto done;
+ }
+ check_size(data, datasize_in, hashbase, hashsize);
+
+ if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
+ !(Sha1Update(sha1ctx, hashbase, hashsize))) {
+ perror(L"Unable to generate hash\n");
+ efi_status = EFI_OUT_OF_RESOURCES;
+ goto done;
+ }
+
+#if 1
+ }
+#else // we have to migrate to doing this later :/
+ SumOfBytesHashed += hashsize;
+ }
+
/* Hash all remaining data */
if (datasize > SumOfBytesHashed) {
hashbase = data + SumOfBytesHashed;
- hashsize = datasize - context->SecDir->Size - SumOfBytesHashed;
+ hashsize = datasize - SumOfBytesHashed;
+
check_size(data, datasize_in, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) {
perror(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
+
+ SumOfBytesHashed += hashsize;
}
+#endif
if (!(Sha256Final(sha256ctx, sha256hash)) ||
!(Sha1Final(sha1ctx, sha1hash))) {
perror(L"Unable to finalise hash\n");
- status = EFI_OUT_OF_RESOURCES;
+ efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
@@ -912,48 +987,23 @@ done:
if (sha256ctx)
FreePool(sha256ctx);
- return status;
-}
-
-/*
- * Ensure that the MOK database hasn't been set or modified from an OS
- */
-static EFI_STATUS verify_mok (void) {
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS status = EFI_SUCCESS;
- UINT8 *MokListData = NULL;
- UINTN MokListDataSize = 0;
- UINT32 attributes;
-
- status = get_variable_attr(L"MokList", &MokListData, &MokListDataSize,
- shim_lock_guid, &attributes);
-
- if (!EFI_ERROR(status) && attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
- perror(L"MokList is compromised!\nErase all keys in MokList!\n");
- if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
- perror(L"Failed to erase MokList\n");
- return EFI_ACCESS_DENIED;
- }
- }
-
- if (MokListData)
- FreePool(MokListData);
-
- return EFI_SUCCESS;
+ return efi_status;
}
/*
* Check that the signature is valid and matches the binary
*/
static EFI_STATUS verify_buffer (char *data, int datasize,
- PE_COFF_LOADER_IMAGE_CONTEXT *context)
+ PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ UINT8 *sha256hash, UINT8 *sha1hash)
{
- UINT8 sha256hash[SHA256_DIGEST_SIZE];
- UINT8 sha1hash[SHA1_DIGEST_SIZE];
- EFI_STATUS status = EFI_ACCESS_DENIED;
+ EFI_STATUS efi_status = EFI_SECURITY_VIOLATION;
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
unsigned int size = datasize;
+ if (datasize < 0)
+ return EFI_INVALID_PARAMETER;
+
if (context->SecDir->Size != 0) {
if (context->SecDir->Size >= size) {
perror(L"Certificate Database size is too large\n");
@@ -981,64 +1031,94 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
}
}
- status = generate_hash(data, datasize, context, sha256hash, sha1hash);
- if (status != EFI_SUCCESS)
- return status;
-
/*
- * Check that the MOK database hasn't been modified
+ * Clear OpenSSL's error log, because we get some DSO unimplemented
+ * errors during its intialization, and we don't want those to look
+ * like they're the reason for validation failures.
*/
- status = verify_mok();
- if (status != EFI_SUCCESS)
- return status;
+ drain_openssl_errors();
+
+ efi_status = generate_hash(data, datasize, context, sha256hash, sha1hash);
+ if (EFI_ERROR(efi_status)) {
+ LogError(L"generate_hash: %r\n", efi_status);
+ return efi_status;
+ }
/*
* Ensure that the binary isn't blacklisted
*/
- status = check_blacklist(cert, sha256hash, sha1hash);
-
- if (status != EFI_SUCCESS) {
+ efi_status = check_blacklist(cert, sha256hash, sha1hash);
+ if (EFI_ERROR(efi_status)) {
perror(L"Binary is blacklisted\n");
- return status;
+ LogError(L"Binary is blacklisted: %r\n", efi_status);
+ return efi_status;
}
/*
* Check whether the binary is whitelisted in any of the firmware
* databases
*/
- status = check_whitelist(cert, sha256hash, sha1hash);
- if (status == EFI_SUCCESS)
- return status;
+ efi_status = check_whitelist(cert, sha256hash, sha1hash);
+ if (EFI_ERROR(efi_status)) {
+ LogError(L"check_whitelist(): %r\n", efi_status);
+ } else {
+ drain_openssl_errors();
+ return efi_status;
+ }
if (cert) {
+#if defined(ENABLE_SHIM_CERT)
/*
* Check against the shim build key
*/
+ clear_ca_warning();
if (sizeof(shim_cert) &&
AuthenticodeVerify(cert->CertData,
cert->Hdr.dwLength - sizeof(cert->Hdr),
shim_cert, sizeof(shim_cert), sha256hash,
SHA256_DIGEST_SIZE)) {
- status = EFI_SUCCESS;
- return status;
+ if (get_ca_warning()) {
+ show_ca_warning();
+ }
+ update_verification_method(VERIFIED_BY_CERT);
+ tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
+ sizeof(shim_cert), shim_cert);
+ efi_status = EFI_SUCCESS;
+ drain_openssl_errors();
+ return efi_status;
+ } else {
+ LogError(L"AuthenticodeVerify(shim_cert) failed\n");
}
+#endif /* defined(ENABLE_SHIM_CERT) */
/*
* And finally, check against shim's built-in key
*/
+ clear_ca_warning();
if (vendor_cert_size &&
AuthenticodeVerify(cert->CertData,
cert->Hdr.dwLength - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size,
sha256hash, SHA256_DIGEST_SIZE)) {
- status = EFI_SUCCESS;
- return status;
+ if (get_ca_warning()) {
+ show_ca_warning();
+ }
+ update_verification_method(VERIFIED_BY_CERT);
+ tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
+ vendor_cert_size, vendor_cert);
+ efi_status = EFI_SUCCESS;
+ drain_openssl_errors();
+ return efi_status;
+ } else {
+ LogError(L"AuthenticodeVerify(vendor_cert) failed\n");
}
}
- status = EFI_ACCESS_DENIED;
-
- return status;
+ LogError(L"Binary is not whitelisted\n");
+ crypterr(EFI_SECURITY_VIOLATION);
+ PrintErrors();
+ efi_status = EFI_SECURITY_VIOLATION;
+ return efi_status;
}
/*
@@ -1165,7 +1245,9 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
return EFI_UNSUPPORTED;
}
- if (context->SecDir->VirtualAddress >= datasize) {
+ if (context->SecDir->VirtualAddress > datasize ||
+ (context->SecDir->VirtualAddress == datasize &&
+ context->SecDir->Size > 0)) {
perror(L"Malformed security header\n");
return EFI_INVALID_PARAMETER;
}
@@ -1176,7 +1258,10 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
* Once the image has been loaded it needs to be validated and relocated
*/
static EFI_STATUS handle_image (void *data, unsigned int datasize,
- EFI_LOADED_IMAGE *li)
+ EFI_LOADED_IMAGE *li,
+ EFI_IMAGE_ENTRY_POINT *entry_point,
+ EFI_PHYSICAL_ADDRESS *alloc_address,
+ UINTN *alloc_pages)
{
EFI_STATUS efi_status;
char *buffer;
@@ -1184,14 +1269,16 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
EFI_IMAGE_SECTION_HEADER *Section;
char *base, *end;
PE_COFF_LOADER_IMAGE_CONTEXT context;
- unsigned int alignment;
+ unsigned int alignment, alloc_size;
int found_entry_point = 0;
+ UINT8 sha1hash[SHA1_DIGEST_SIZE];
+ UINT8 sha256hash[SHA256_DIGEST_SIZE];
/*
* The binary header contains relevant context and section pointers
*/
efi_status = read_header(data, datasize, &context);
- if (efi_status != EFI_SUCCESS) {
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to read header: %r\n", efi_status);
return efi_status;
}
@@ -1199,15 +1286,32 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
/*
* We only need to verify the binary if we're in secure mode
*/
+ efi_status = generate_hash(data, datasize, &context, sha256hash,
+ sha1hash);
+ if (EFI_ERROR(efi_status))
+ return efi_status;
+
+ /* Measure the binary into the TPM */
+#ifdef REQUIRE_TPM
+ efi_status =
+#endif
+ tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, sha1hash, 4);
+#ifdef REQUIRE_TPM
+ if (efi_status != EFI_SUCCESS) {
+ return efi_status;
+ }
+#endif
+
if (secure_mode ()) {
- efi_status = verify_buffer(data, datasize, &context);
+ efi_status = verify_buffer(data, datasize, &context,
+ sha256hash, sha1hash);
if (EFI_ERROR(efi_status)) {
console_error(L"Verification failed", efi_status);
return efi_status;
} else {
if (verbose)
- console_notify(L"Verification succeeded");
+ console_print(L"Verification succeeded\n");
}
}
@@ -1229,20 +1333,25 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
if (!alignment)
alignment = 4096;
- buffer = AllocatePool(context.ImageSize + context.SectionAlignment);
- buffer = ALIGN_POINTER(buffer, alignment);
+ alloc_size = ALIGN_VALUE(context.ImageSize + context.SectionAlignment,
+ PAGE_SIZE);
+ *alloc_pages = alloc_size / PAGE_SIZE;
- if (!buffer) {
+ efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
+ *alloc_pages, alloc_address);
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to allocate image buffer\n");
return EFI_OUT_OF_RESOURCES;
}
+ buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment);
+
CopyMem(buffer, data, context.SizeOfHeaders);
- entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
- if (!entry_point) {
+ *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
+ if (!*entry_point) {
perror(L"Entry point is invalid\n");
- FreePool(buffer);
+ gBS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED;
}
@@ -1276,7 +1385,7 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
if (end < base) {
perror(L"Section %d has negative size\n", i);
- FreePool(buffer);
+ gBS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED;
}
@@ -1355,7 +1464,7 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
efi_status = relocate_coff(&context, RelocSection, data,
buffer);
- if (efi_status != EFI_SUCCESS) {
+ if (EFI_ERROR(efi_status)) {
perror(L"Relocation failed: %r\n", efi_status);
FreePool(buffer);
return efi_status;
@@ -1370,8 +1479,10 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
li->ImageSize = context.ImageSize;
/* Pass the load options to the second stage loader */
- li->LoadOptions = load_options;
- li->LoadOptionsSize = load_options_size;
+ if ( load_options ) {
+ li->LoadOptions = load_options;
+ li->LoadOptionsSize = load_options_size;
+ }
if (!found_entry_point) {
perror(L"Entry point is not within sections\n");
@@ -1388,20 +1499,20 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
static int
should_use_fallback(EFI_HANDLE image_handle)
{
- EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
EFI_LOADED_IMAGE *li;
unsigned int pathlen = 0;
CHAR16 *bootpath = NULL;
EFI_FILE_IO_INTERFACE *fio = NULL;
EFI_FILE *vh = NULL;
EFI_FILE *fh = NULL;
- EFI_STATUS rc;
+ EFI_STATUS efi_status;
int ret = 0;
- rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
- &loaded_image_protocol, (void **)&li);
- if (EFI_ERROR(rc)) {
- perror(L"Could not get image for bootx64.efi: %r\n", rc);
+ efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
+ (void **)&li);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Could not get image for bootx64.efi: %r\n",
+ efi_status);
return 0;
}
@@ -1422,27 +1533,28 @@ should_use_fallback(EFI_HANDLE image_handle)
if (pathlen < 5 || StrCaseCmp(bootpath + pathlen - 4, L".EFI"))
goto error;
- rc = uefi_call_wrapper(BS->HandleProtocol, 3, li->DeviceHandle,
- &FileSystemProtocol, (void **)&fio);
- if (EFI_ERROR(rc)) {
- perror(L"Could not get fio for li->DeviceHandle: %r\n", rc);
+ efi_status = gBS->HandleProtocol(li->DeviceHandle, &FileSystemProtocol,
+ (void **) &fio);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Could not get fio for li->DeviceHandle: %r\n",
+ efi_status);
goto error;
}
- rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &vh);
- if (EFI_ERROR(rc)) {
- perror(L"Could not open fio volume: %r\n", rc);
+ efi_status = fio->OpenVolume(fio, &vh);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Could not open fio volume: %r\n", efi_status);
goto error;
}
- rc = uefi_call_wrapper(vh->Open, 5, vh, &fh, L"\\EFI\\BOOT" FALLBACK,
- EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR(rc)) {
+ efi_status = vh->Open(vh, &fh, L"\\EFI\\BOOT" FALLBACK,
+ EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR(efi_status)) {
/* Do not print the error here - this is an acceptable case
* for removable media, where we genuinely don't want
* fallback.efi to exist.
- * Print(L"Could not open \"\\EFI\\BOOT%s\": %d\n", FALLBACK,
- * rc);
+ * Print(L"Could not open \"\\EFI\\BOOT%s\": %r\n", FALLBACK,
+ * efi_status);
*/
goto error;
}
@@ -1450,9 +1562,9 @@ should_use_fallback(EFI_HANDLE image_handle)
ret = 1;
error:
if (fh)
- uefi_call_wrapper(fh->Close, 1, fh);
+ fh->Close(fh);
if (vh)
- uefi_call_wrapper(vh->Close, 1, vh);
+ vh->Close(vh);
if (bootpath)
FreePool(bootpath);
@@ -1463,8 +1575,9 @@ error:
* Generate the path of an executable given shim's path and the name
* of the executable
*/
-static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
- CHAR16 **PathName)
+static EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li,
+ CHAR16 *ImagePath,
+ CHAR16 **PathName)
{
EFI_DEVICE_PATH *devpath;
unsigned int i;
@@ -1555,8 +1668,6 @@ error:
static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
int *datasize, CHAR16 *PathName)
{
- EFI_GUID simple_file_system_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
- EFI_GUID file_info_id = EFI_FILE_INFO_ID;
EFI_STATUS efi_status;
EFI_HANDLE device;
EFI_FILE_INFO *fileinfo = NULL;
@@ -1569,18 +1680,15 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
/*
* Open the device
*/
- efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
- &simple_file_system_protocol,
- (void **)&drive);
-
- if (efi_status != EFI_SUCCESS) {
+ efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
+ (void **) &drive);
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to find fs: %r\n", efi_status);
goto error;
}
- efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
-
- if (efi_status != EFI_SUCCESS) {
+ efi_status = drive->OpenVolume(drive, &root);
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to open fs: %r\n", efi_status);
goto error;
}
@@ -1588,10 +1696,8 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
/*
* And then open the file
*/
- efi_status = uefi_call_wrapper(root->Open, 5, root, &grub, PathName,
- EFI_FILE_MODE_READ, 0);
-
- if (efi_status != EFI_SUCCESS) {
+ efi_status = root->Open(root, &grub, PathName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to open %s - %r\n", PathName, efi_status);
goto error;
}
@@ -1608,9 +1714,8 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
* Find out how big the file is in order to allocate the storage
* buffer
*/
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub, &file_info_id,
- &buffersize, fileinfo);
-
+ efi_status = grub->GetInfo(grub, &EFI_FILE_INFO_GUID, &buffersize,
+ fileinfo);
if (efi_status == EFI_BUFFER_TOO_SMALL) {
FreePool(fileinfo);
fileinfo = AllocatePool(buffersize);
@@ -1619,20 +1724,17 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
efi_status = EFI_OUT_OF_RESOURCES;
goto error;
}
- efi_status = uefi_call_wrapper(grub->GetInfo, 4, grub,
- &file_info_id, &buffersize,
- fileinfo);
+ efi_status = grub->GetInfo(grub, &EFI_FILE_INFO_GUID,
+ &buffersize, fileinfo);
}
- if (efi_status != EFI_SUCCESS) {
+ if (EFI_ERROR(efi_status)) {
perror(L"Unable to get file info: %r\n", efi_status);
goto error;
}
buffersize = fileinfo->FileSize;
-
*data = AllocatePool(buffersize);
-
if (!*data) {
perror(L"Unable to allocate file buffer\n");
efi_status = EFI_OUT_OF_RESOURCES;
@@ -1642,18 +1744,15 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
/*
* Perform the actual read
*/
- efi_status = uefi_call_wrapper(grub->Read, 3, grub, &buffersize,
- *data);
-
+ efi_status = grub->Read(grub, &buffersize, *data);
if (efi_status == EFI_BUFFER_TOO_SMALL) {
FreePool(*data);
*data = AllocatePool(buffersize);
- efi_status = uefi_call_wrapper(grub->Read, 3, grub,
- &buffersize, *data);
+ efi_status = grub->Read(grub, &buffersize, *data);
}
-
- if (efi_status != EFI_SUCCESS) {
- perror(L"Unexpected return from initial read: %r, buffersize %x\n", efi_status, buffersize);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Unexpected return from initial read: %r, buffersize %x\n",
+ efi_status, buffersize);
goto error;
}
@@ -1679,48 +1778,75 @@ error:
*/
EFI_STATUS shim_verify (void *buffer, UINT32 size)
{
- EFI_STATUS status = EFI_SUCCESS;
+ EFI_STATUS efi_status = EFI_SUCCESS;
PE_COFF_LOADER_IMAGE_CONTEXT context;
+ UINT8 sha1hash[SHA1_DIGEST_SIZE];
+ UINT8 sha256hash[SHA256_DIGEST_SIZE];
+
+ if ((INT32)size < 0)
+ return EFI_INVALID_PARAMETER;
loader_is_participating = 1;
in_protocol = 1;
- if (!secure_mode())
+ efi_status = read_header(buffer, size, &context);
+ if (EFI_ERROR(efi_status))
goto done;
- status = read_header(buffer, size, &context);
- if (status != EFI_SUCCESS)
+ efi_status = generate_hash(buffer, size, &context,
+ sha256hash, sha1hash);
+ if (EFI_ERROR(efi_status))
goto done;
- status = verify_buffer(buffer, size, &context);
+ /* Measure the binary into the TPM */
+#ifdef REQUIRE_TPM
+ efi_status =
+#endif
+ tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)buffer, size, sha1hash, 4);
+#ifdef REQUIRE_TPM
+ if (EFI_ERROR(efi_status))
+ goto done;
+#endif
+
+ if (!secure_mode()) {
+ efi_status = EFI_SUCCESS;
+ goto done;
+ }
+
+ efi_status = verify_buffer(buffer, size, &context,
+ sha256hash, sha1hash);
done:
in_protocol = 0;
- return status;
+ return efi_status;
}
static EFI_STATUS shim_hash (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
UINT8 *sha256hash, UINT8 *sha1hash)
{
- EFI_STATUS status;
+ EFI_STATUS efi_status;
+
+ if (datasize < 0)
+ return EFI_INVALID_PARAMETER;
in_protocol = 1;
- status = generate_hash(data, datasize, context, sha256hash, sha1hash);
+ efi_status = generate_hash(data, datasize, context,
+ sha256hash, sha1hash);
in_protocol = 0;
- return status;
+ return efi_status;
}
static EFI_STATUS shim_read_header(void *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
- EFI_STATUS status;
+ EFI_STATUS efi_status;
in_protocol = 1;
- status = read_header(data, datasize, context);
+ efi_status = read_header(data, datasize, context);
in_protocol = 0;
- return status;
+ return efi_status;
}
/*
@@ -1728,9 +1854,11 @@ static EFI_STATUS shim_read_header(void *data, unsigned int datasize,
*/
EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
{
- EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
EFI_STATUS efi_status;
EFI_LOADED_IMAGE *li, li_bak;
+ EFI_IMAGE_ENTRY_POINT entry_point;
+ EFI_PHYSICAL_ADDRESS alloc_address;
+ UINTN alloc_pages;
CHAR16 *PathName = NULL;
void *sourcebuffer = NULL;
UINT64 sourcesize = 0;
@@ -1741,10 +1869,9 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
* We need to refer to the loaded image protocol on the running
* binary in order to find our path
*/
- efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
- &loaded_image_protocol, (void **)&li);
-
- if (efi_status != EFI_SUCCESS) {
+ efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
+ (void **)&li);
+ if (EFI_ERROR(efi_status)) {
perror(L"Unable to init protocol\n");
return efi_status;
}
@@ -1752,33 +1879,36 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
/*
* Build a new path from the existing one plus the executable name
*/
- efi_status = generate_path(li, ImagePath, &PathName);
-
- if (efi_status != EFI_SUCCESS) {
- perror(L"Unable to generate path %s: %r\n", ImagePath, efi_status);
+ efi_status = generate_path_from_image_path(li, ImagePath, &PathName);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Unable to generate path %s: %r\n", ImagePath,
+ efi_status);
goto done;
}
if (findNetboot(li->DeviceHandle)) {
efi_status = parseNetbootinfo(image_handle);
- if (efi_status != EFI_SUCCESS) {
+ if (EFI_ERROR(efi_status)) {
perror(L"Netboot parsing failed: %r\n", efi_status);
return EFI_PROTOCOL_ERROR;
}
efi_status = FetchNetbootimage(image_handle, &sourcebuffer,
&sourcesize);
- if (efi_status != EFI_SUCCESS) {
- perror(L"Unable to fetch TFTP image: %r\n", efi_status);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Unable to fetch TFTP image: %r\n",
+ efi_status);
return efi_status;
}
data = sourcebuffer;
datasize = sourcesize;
#if defined(ENABLE_HTTPBOOT)
} else if (find_httpboot(li->DeviceHandle)) {
- efi_status = httpboot_fetch_buffer (image_handle, &sourcebuffer,
+ efi_status = httpboot_fetch_buffer (image_handle,
+ &sourcebuffer,
&sourcesize);
- if (efi_status != EFI_SUCCESS) {
- perror(L"Unable to fetch HTTP image: %r\n", efi_status);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Unable to fetch HTTP image: %r\n",
+ efi_status);
return efi_status;
}
data = sourcebuffer;
@@ -1789,16 +1919,19 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
* Read the new executable off disk
*/
efi_status = load_image(li, &data, &datasize, PathName);
-
- if (efi_status != EFI_SUCCESS) {
- perror(L"Failed to load image %s: %r\n", PathName, efi_status);
+ if (EFI_ERROR(efi_status)) {
+ perror(L"Failed to load image %s: %r\n",
+ PathName, efi_status);
+ PrintErrors();
+ ClearErrors();
goto done;
}
}
- /* Measure the binary into the TPM */
- tpm_log_event((EFI_PHYSICAL_ADDRESS)data, datasize, 9,
- (CHAR8 *)"Second stage bootloader");
+ if (datasize < 0) {
+ efi_status = EFI_INVALID_PARAMETER;
+ goto done;
+ }
/*
* We need to modify the loaded image protocol entry before running
@@ -1809,10 +1942,12 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
/*
* Verify and, if appropriate, relocate and execute the executable
*/
- efi_status = handle_image(data, datasize, li);
-
- if (efi_status != EFI_SUCCESS) {
+ efi_status = handle_image(data, datasize, li, &entry_point,
+ &alloc_address, &alloc_pages);
+ if (EFI_ERROR(efi_status)) {
perror(L"Failed to load image: %r\n", efi_status);
+ PrintErrors();
+ ClearErrors();
CopyMem(li, &li_bak, sizeof(li_bak));
goto done;
}
@@ -1822,7 +1957,7 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
/*
* The binary is trusted and relocated. Run it
*/
- efi_status = uefi_call_wrapper(entry_point, 2, image_handle, systab);
+ efi_status = entry_point(image_handle, systab);
/*
* Restore our original loaded image values
@@ -1848,12 +1983,12 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
int use_fb = should_use_fallback(image_handle);
efi_status = start_image(image_handle, use_fb ? FALLBACK :second_stage);
-
- if (efi_status == EFI_SECURITY_VIOLATION) {
+ if (efi_status == EFI_SECURITY_VIOLATION ||
+ efi_status == EFI_ACCESS_DENIED) {
efi_status = start_image(image_handle, MOK_MANAGER);
- if (efi_status != EFI_SUCCESS) {
- Print(L"start_image() returned %r\n", efi_status);
- uefi_call_wrapper(BS->Stall, 1, 2000000);
+ if (EFI_ERROR(efi_status)) {
+ console_print(L"start_image() returned %r\n", efi_status);
+ msleep(2000000);
return efi_status;
}
@@ -1861,320 +1996,14 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
use_fb ? FALLBACK : second_stage);
}
- if (efi_status != EFI_SUCCESS) {
- Print(L"start_image() returned %r\n", efi_status);
- uefi_call_wrapper(BS->Stall, 1, 2000000);
- }
-
- return efi_status;
-}
-
-/*
- * Measure some of the MOK variables into the TPM
- */
-EFI_STATUS measure_mok()
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS efi_status;
- UINT8 *Data = NULL;
- UINTN DataSize = 0;
-
- efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
- (CHAR8 *)"MokList");
-
- FreePool(Data);
-
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- efi_status = get_variable(L"MokSBState", &Data, &DataSize,
- shim_lock_guid);
-
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
- (CHAR8 *)"MokSBState");
-
- FreePool(Data);
-
- return efi_status;
-}
-
-/*
- * Copy the boot-services only MokList variable to the runtime-accessible
- * MokListRT variable. It's not marked NV, so the OS can't modify it.
- */
-EFI_STATUS mirror_mok_list()
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS efi_status;
- UINT8 *Data = NULL;
- UINTN DataSize = 0;
- void *FullData = NULL;
- UINTN FullDataSize = 0;
- EFI_SIGNATURE_LIST *CertList = NULL;
- EFI_SIGNATURE_DATA *CertData = NULL;
- uint8_t *p = NULL;
-
- efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
- if (efi_status != EFI_SUCCESS)
- DataSize = 0;
-
- if (vendor_cert_size) {
- FullDataSize = DataSize
- + sizeof (*CertList)
- + sizeof (EFI_GUID)
- + vendor_cert_size
- ;
- FullData = AllocatePool(FullDataSize);
- if (!FullData) {
- perror(L"Failed to allocate space for MokListRT\n");
- return EFI_OUT_OF_RESOURCES;
- }
- p = FullData;
-
- if (efi_status == EFI_SUCCESS && DataSize > 0) {
- CopyMem(p, Data, DataSize);
- p += DataSize;
- }
- CertList = (EFI_SIGNATURE_LIST *)p;
- p += sizeof (*CertList);
- CertData = (EFI_SIGNATURE_DATA *)p;
- p += sizeof (EFI_GUID);
-
- CertList->SignatureType = EFI_CERT_X509_GUID;
- CertList->SignatureListSize = vendor_cert_size
- + sizeof (*CertList)
- + sizeof (*CertData)
- -1;
- CertList->SignatureHeaderSize = 0;
- CertList->SignatureSize = vendor_cert_size + sizeof (EFI_GUID);
-
- CertData->SignatureOwner = SHIM_LOCK_GUID;
- CopyMem(p, vendor_cert, vendor_cert_size);
- } else {
- FullDataSize = DataSize;
- FullData = Data;
- }
-
- efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListRT",
- &shim_lock_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- FullDataSize, FullData);
- if (efi_status != EFI_SUCCESS) {
- perror(L"Failed to set MokListRT: %r\n", efi_status);
- }
-
- return efi_status;
-}
-
-/*
- * Copy the boot-services only MokListX variable to the runtime-accessible
- * MokListXRT variable. It's not marked NV, so the OS can't modify it.
- */
-EFI_STATUS mirror_mok_list_x()
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS efi_status;
- UINT8 *Data = NULL;
- UINTN DataSize = 0;
-
- efi_status = get_variable(L"MokListX", &Data, &DataSize, shim_lock_guid);
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListXRT",
- &shim_lock_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- DataSize, Data);
- if (efi_status != EFI_SUCCESS) {
- console_error(L"Failed to set MokListRT", efi_status);
- }
-
- return efi_status;
-}
-
-/*
- * Copy the boot-services only MokSBState variable to the runtime-accessible
- * MokSBStateRT variable. It's not marked NV, so the OS can't modify it.
- */
-EFI_STATUS mirror_mok_sb_state()
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS efi_status;
- UINT8 *Data = NULL;
- UINTN DataSize = 0;
-
- efi_status = get_variable(L"MokSBState", &Data, &DataSize, shim_lock_guid);
- if (efi_status != EFI_SUCCESS)
- return efi_status;
-
- efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokSBStateRT",
- &shim_lock_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- DataSize, Data);
- if (efi_status != EFI_SUCCESS) {
- console_error(L"Failed to set MokSBStateRT", efi_status);
- }
-
- return efi_status;
-}
-
-/*
- * Check if a variable exists
- */
-static BOOLEAN check_var(CHAR16 *varname)
-{
- EFI_STATUS efi_status;
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- UINTN size = sizeof(UINT32);
- UINT32 MokVar;
- UINT32 attributes;
-
- efi_status = uefi_call_wrapper(RT->GetVariable, 5, varname,
- &shim_lock_guid, &attributes,
- &size, (void *)&MokVar);
-
- if (efi_status == EFI_SUCCESS || efi_status == EFI_BUFFER_TOO_SMALL)
- return TRUE;
-
- return FALSE;
-}
-
-/*
- * If the OS has set any of these variables we need to drop into MOK and
- * handle them appropriately
- */
-EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
-{
- EFI_STATUS efi_status;
-
- if (check_var(L"MokNew") || check_var(L"MokSB") ||
- check_var(L"MokPW") || check_var(L"MokAuth") ||
- check_var(L"MokDel") || check_var(L"MokDB") ||
- check_var(L"MokXNew") || check_var(L"MokXDel") ||
- check_var(L"MokXAuth")) {
- efi_status = start_image(image_handle, MOK_MANAGER);
-
- if (efi_status != EFI_SUCCESS) {
- perror(L"Failed to start MokManager: %r\n", efi_status);
- return efi_status;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/*
- * Verify that MokSBState is valid, and if appropriate set insecure mode
- */
-static EFI_STATUS check_mok_sb (void)
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS status = EFI_SUCCESS;
- UINT8 MokSBState;
- UINTN MokSBStateSize = sizeof(MokSBState);
- UINT32 attributes;
-
- user_insecure_mode = 0;
- ignore_db = 0;
-
- status = uefi_call_wrapper(RT->GetVariable, 5, L"MokSBState", &shim_lock_guid,
- &attributes, &MokSBStateSize, &MokSBState);
- if (status != EFI_SUCCESS)
- return EFI_ACCESS_DENIED;
-
- /*
- * Delete and ignore the variable if it's been set from or could be
- * modified by the OS
- */
- if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
- perror(L"MokSBState is compromised! Clearing it\n");
- if (LibDeleteVariable(L"MokSBState", &shim_lock_guid) != EFI_SUCCESS) {
- perror(L"Failed to erase MokSBState\n");
- }
- status = EFI_ACCESS_DENIED;
- } else {
- if (MokSBState == 1) {
- user_insecure_mode = 1;
- }
- }
-
- return status;
-}
-
-/*
- * Verify that MokDBState is valid, and if appropriate set ignore db mode
- */
-
-static EFI_STATUS check_mok_db (void)
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS status = EFI_SUCCESS;
- UINT8 MokDBState;
- UINTN MokDBStateSize = sizeof(MokDBState);
- UINT32 attributes;
-
- status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDBState", &shim_lock_guid,
- &attributes, &MokDBStateSize, &MokDBState);
- if (status != EFI_SUCCESS)
- return EFI_ACCESS_DENIED;
-
- ignore_db = 0;
-
- /*
- * Delete and ignore the variable if it's been set from or could be
- * modified by the OS
- */
- if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
- perror(L"MokDBState is compromised! Clearing it\n");
- if (LibDeleteVariable(L"MokDBState", &shim_lock_guid) != EFI_SUCCESS) {
- perror(L"Failed to erase MokDBState\n");
- }
- status = EFI_ACCESS_DENIED;
- } else {
- if (MokDBState == 1) {
- ignore_db = 1;
- }
- }
-
- return status;
-}
-
-static EFI_STATUS mok_ignore_db()
-{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS efi_status = EFI_SUCCESS;
- UINT8 Data = 1;
- UINTN DataSize = sizeof(UINT8);
-
- check_mok_db();
-
- if (ignore_db) {
- efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokIgnoreDB",
- &shim_lock_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- DataSize, (void *)&Data);
- if (efi_status != EFI_SUCCESS) {
- perror(L"Failed to set MokIgnoreDB: %r\n", efi_status);
- }
+ if (EFI_ERROR(efi_status)) {
+ console_print(L"start_image() returned %r\n", efi_status);
+ msleep(2000000);
}
return efi_status;
-
}
-EFI_GUID bds_guid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
-
static inline EFI_STATUS
get_load_option_optional_data(UINT8 *data, UINTN data_size,
UINT8 **od, UINTN *ods)
@@ -2285,13 +2114,31 @@ get_load_option_optional_data(UINT8 *data, UINTN data_size,
return EFI_SUCCESS;
}
+static int is_our_path(EFI_LOADED_IMAGE *li, CHAR16 *path, UINTN len)
+{
+ CHAR16 *dppath = NULL;
+ int ret = 1;
+
+ dppath = DevicePathToStr(li->FilePath);
+ if (!dppath)
+ return 0;
+
+ dprint(L"dppath: %s\n", dppath);
+ dprint(L"path: %s\n", path);
+ if (StrnCaseCmp(dppath, path, len))
+ ret = 0;
+
+ FreePool(dppath);
+ return ret;
+}
+
/*
* Check the load options to specify the second stage loader
*/
EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
{
- EFI_STATUS status;
- EFI_LOADED_IMAGE *li;
+ EFI_STATUS efi_status;
+ EFI_LOADED_IMAGE *li = NULL;
CHAR16 *start = NULL;
int remaining_size = 0;
CHAR16 *loader_str = NULL;
@@ -2302,11 +2149,11 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
load_options = NULL;
load_options_size = 0;
- status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
- &LoadedImageProtocol, (void **) &li);
- if (status != EFI_SUCCESS) {
- perror (L"Failed to get load options: %r\n", status);
- return status;
+ efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
+ (void **) &li);
+ if (EFI_ERROR(efi_status)) {
+ perror (L"Failed to get load options: %r\n", efi_status);
+ return efi_status;
}
/* So, load options are a giant pain in the ass. If we're invoked
@@ -2376,11 +2223,17 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
if (li->LoadOptionsSize > 16) {
if (CompareGuid((EFI_GUID *)(li->LoadOptions
+ (li->LoadOptionsSize - 16)),
- &bds_guid) == 0)
+ &BDS_GUID) == 0)
li->LoadOptionsSize -= 16;
}
/*
+ * Apparently sometimes we get L"\0\0"? Which isn't useful at all.
+ */
+ if (is_all_nuls(li->LoadOptions, li->LoadOptionsSize))
+ return EFI_SUCCESS;
+
+ /*
* Check and see if this is just a list of strings. If it's an
* EFI_LOAD_OPTION, it'll be 0, since we know EndEntire device path
* won't pass muster as UCS2-LE.
@@ -2398,11 +2251,11 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
* We at least didn't find /enough/ strings. See if it works
* as an EFI_LOAD_OPTION.
*/
- status = get_load_option_optional_data(li->LoadOptions,
- li->LoadOptionsSize,
- (UINT8 **)&start,
- &loader_len);
- if (status != EFI_SUCCESS)
+ efi_status = get_load_option_optional_data(li->LoadOptions,
+ li->LoadOptionsSize,
+ (UINT8 **)&start,
+ &loader_len);
+ if (EFI_ERROR(efi_status))
return EFI_SUCCESS;
remaining_size = 0;
@@ -2454,6 +2307,20 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
return EFI_SUCCESS;
/*
+ * And then I found a version of BDS that gives us our own path in
+ * LoadOptions:
+
+77162C58 5c 00 45 00 46 00 49 00 |\.E.F.I.|
+77162C60 5c 00 42 00 4f 00 4f 00 54 00 5c 00 42 00 4f 00 |\.B.O.O.T.\.B.O.|
+77162C70 4f 00 54 00 58 00 36 00 34 00 2e 00 45 00 46 00 |O.T.X.6.4...E.F.|
+77162C80 49 00 00 00 |I...|
+
+ * which is just cruel... So yeah, just don't use it.
+ */
+ if (strings == 1 && is_our_path(li, start, loader_len))
+ return EFI_SUCCESS;
+
+ /*
* Set up the name of the alternative loader and the LoadOptions for
* the loader
*/
@@ -2469,37 +2336,99 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
loader_str[loader_len/2-1] = L'\0';
second_stage = loader_str;
- load_options = remaining_size ? start + loader_len : NULL;
+ load_options = remaining_size ? start + (loader_len/2) : NULL;
load_options_size = remaining_size;
}
return EFI_SUCCESS;
}
+static void *
+ossl_malloc(size_t num, const char *file, int line)
+{
+ return AllocatePool(num);
+}
+
+static void
+ossl_free(void *addr, const char *file, int line)
+{
+ FreePool(addr);
+}
+
+static void
+init_openssl(void)
+{
+ CRYPTO_set_mem_functions(ossl_malloc, NULL, ossl_free);
+ OPENSSL_init();
+ CRYPTO_set_mem_functions(ossl_malloc, NULL, ossl_free);
+ ERR_load_ERR_strings();
+ ERR_load_BN_strings();
+ ERR_load_RSA_strings();
+ ERR_load_DH_strings();
+ ERR_load_EVP_strings();
+ ERR_load_BUF_strings();
+ ERR_load_OBJ_strings();
+ ERR_load_PEM_strings();
+ ERR_load_X509_strings();
+ ERR_load_ASN1_strings();
+ ERR_load_CONF_strings();
+ ERR_load_CRYPTO_strings();
+ ERR_load_COMP_strings();
+ ERR_load_BIO_strings();
+ ERR_load_PKCS7_strings();
+ ERR_load_X509V3_strings();
+ ERR_load_PKCS12_strings();
+ ERR_load_RAND_strings();
+ ERR_load_DSO_strings();
+ ERR_load_OCSP_strings();
+}
+
static SHIM_LOCK shim_lock_interface;
static EFI_HANDLE shim_lock_handle;
EFI_STATUS
install_shim_protocols(void)
{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ SHIM_LOCK *shim_lock;
EFI_STATUS efi_status;
- if (!secure_mode())
- return EFI_SUCCESS;
+ /*
+ * Did another instance of shim earlier already install the
+ * protocol? If so, get rid of it.
+ *
+ * We have to uninstall shim's protocol here, because if we're
+ * On the fallback.efi path, then our call pathway is:
+ *
+ * shim->fallback->shim->grub
+ * ^ ^ ^
+ * | | \- gets protocol #0
+ * | \- installs its protocol (#1)
+ * \- installs its protocol (#0)
+ * and if we haven't removed this, then grub will get the *first*
+ * shim's protocol, but it'll get the second shim's systab
+ * replacements. So even though it will participate and verify
+ * the kernel, the systab never finds out.
+ */
+ efi_status = LibLocateProtocol(&SHIM_LOCK_GUID, (VOID **)&shim_lock);
+ if (!EFI_ERROR(efi_status))
+ uninstall_shim_protocols();
/*
* Install the protocol
*/
- efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
- &shim_lock_handle, &shim_lock_guid,
- EFI_NATIVE_INTERFACE, &shim_lock_interface);
+ efi_status = gBS->InstallProtocolInterface(&shim_lock_handle,
+ &SHIM_LOCK_GUID,
+ EFI_NATIVE_INTERFACE,
+ &shim_lock_interface);
if (EFI_ERROR(efi_status)) {
console_error(L"Could not install security protocol",
efi_status);
return efi_status;
}
+ if (!secure_mode())
+ return EFI_SUCCESS;
+
#if defined(OVERRIDE_SECURITY_POLICY)
/*
* Install the security protocol hook
@@ -2513,7 +2442,11 @@ install_shim_protocols(void)
void
uninstall_shim_protocols(void)
{
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ /*
+ * If we're back here then clean everything up before exiting
+ */
+ gBS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID,
+ &shim_lock_interface);
if (!secure_mode())
return;
@@ -2524,24 +2457,16 @@ uninstall_shim_protocols(void)
*/
security_policy_uninstall();
#endif
-
- /*
- * If we're back here then clean everything up before exiting
- */
- uefi_call_wrapper(BS->UninstallProtocolInterface, 3, shim_lock_handle,
- &shim_lock_guid, &shim_lock_interface);
}
EFI_STATUS
shim_init(void)
{
- EFI_STATUS status = EFI_SUCCESS;
- setup_console(1);
setup_verbosity();
- dprinta(shim_version);
+ dprint(L"%a", shim_version);
/* Set the second stage loader */
- set_second_stage (image_handle);
+ set_second_stage (global_image_handle);
if (secure_mode()) {
if (vendor_cert_size || vendor_dbx_size) {
@@ -2555,20 +2480,20 @@ shim_init(void)
}
hook_exit(systab);
-
- status = install_shim_protocols();
}
- return status;
+
+ return install_shim_protocols();
}
void
shim_fini(void)
{
+ /*
+ * Remove our protocols
+ */
+ uninstall_shim_protocols();
+
if (secure_mode()) {
- /*
- * Remove our protocols
- */
- uninstall_shim_protocols();
/*
* Remove our hooks from system services.
@@ -2583,7 +2508,7 @@ shim_fini(void)
if (load_options_size > 0 && second_stage)
FreePool(second_stage);
- setup_console(0);
+ console_fini();
}
extern EFI_STATUS
@@ -2593,7 +2518,6 @@ static void
__attribute__((__optimize__("0")))
debug_hook(void)
{
- EFI_GUID guid = SHIM_LOCK_GUID;
UINT8 *data = NULL;
UINTN dataSize = 0;
EFI_STATUS efi_status;
@@ -2603,18 +2527,21 @@ debug_hook(void)
if (x)
return;
- efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, guid);
+ efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
+ SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) {
return;
}
- Print(L"add-symbol-file "DEBUGDIR
- L"shim" EFI_ARCH L".efi.debug 0x%08x -s .data 0x%08x\n", &_text,
- &_data);
+ FreePool(data);
+
+ console_print(L"add-symbol-file "DEBUGDIR
+ L"shim" EFI_ARCH L".efi.debug 0x%08x -s .data 0x%08x\n",
+ &_text, &_data);
- Print(L"Pausing for debugger attachment.\n");
- Print(L"To disable this, remove the EFI variable SHIM_DEBUG-%g .\n",
- &guid);
+ console_print(L"Pausing for debugger attachment.\n");
+ console_print(L"To disable this, remove the EFI variable SHIM_DEBUG-%g .\n",
+ &SHIM_LOCK_GUID);
x = 1;
while (x++) {
/* Make this so it can't /totally/ DoS us. */
@@ -2629,7 +2556,7 @@ debug_hook(void)
#else
if (x > 12000)
break;
- uefi_call_wrapper(BS->Stall, 1, 5000);
+ msleep(5000);
#endif
}
x = 1;
@@ -2639,6 +2566,7 @@ EFI_STATUS
efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
{
EFI_STATUS efi_status;
+ EFI_HANDLE image_handle;
verification_method = VERIFIED_BY_NOTHING;
@@ -2646,6 +2574,13 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
vendor_dbx_size = cert_table.vendor_dbx_size;
vendor_cert = (UINT8 *)&cert_table + cert_table.vendor_cert_offset;
vendor_dbx = (UINT8 *)&cert_table + cert_table.vendor_dbx_offset;
+ CHAR16 *msgs[] = {
+ L"import_mok_state() failed\n",
+ L"shim_int() failed\n",
+ NULL
+ };
+ int msg = 0;
+
/*
* Set up the shim lock protocol so that grub and MokManager can
@@ -2656,81 +2591,49 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
shim_lock_interface.Context = shim_read_header;
systab = passed_systab;
- image_handle = passed_image_handle;
+ image_handle = global_image_handle = passed_image_handle;
/*
* Ensure that gnu-efi functions are available
*/
InitializeLib(image_handle, systab);
+ init_openssl();
+
/*
* if SHIM_DEBUG is set, wait for a debugger to attach.
*/
debug_hook();
/*
- * Measure the MOK variables
+ * Before we do anything else, validate our non-volatile,
+ * boot-services-only state variables are what we think they are.
*/
- efi_status = measure_mok();
- if (efi_status != EFI_SUCCESS && efi_status != EFI_NOT_FOUND) {
- Print(L"Something has gone seriously wrong: %r\n", efi_status);
- Print(L"Shim was unable to measure state into the TPM\n");
- systab->BootServices->Stall(5000000);
- systab->RuntimeServices->ResetSystem(EfiResetShutdown,
- EFI_SECURITY_VIOLATION,
- 0, NULL);
+ efi_status = import_mok_state(image_handle);
+ if (EFI_ERROR(efi_status)) {
+die:
+ console_print(L"Something has gone seriously wrong: %s: %r\n",
+ msgs[msg], efi_status);
+ msleep(5000000);
+ gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
+ 0, NULL);
}
- /*
- * Check whether the user has configured the system to run in
- * insecure mode
- */
- check_mok_sb();
-
efi_status = shim_init();
if (EFI_ERROR(efi_status)) {
- Print(L"Something has gone seriously wrong: %r\n", efi_status);
- Print(L"shim cannot continue, sorry.\n");
- uefi_call_wrapper(BS->Stall, 1, 5000000);
- uefi_call_wrapper(systab->RuntimeServices->ResetSystem, 4,
- EfiResetShutdown, EFI_SECURITY_VIOLATION,
- 0, NULL);
+ msg = 1;
+ goto die;
}
/*
* Tell the user that we're in insecure mode if necessary
*/
if (user_insecure_mode) {
- Print(L"Booting in insecure mode\n");
- uefi_call_wrapper(BS->Stall, 1, 2000000);
+ console_print(L"Booting in insecure mode\n");
+ msleep(2000000);
}
/*
- * Enter MokManager if necessary
- */
- efi_status = check_mok_request(image_handle);
-
- /*
- * Copy the MOK list to a runtime variable so the kernel can
- * make use of it
- */
- efi_status = mirror_mok_list();
-
- efi_status = mirror_mok_list_x();
-
- /*
- * Copy the MOK SB State to a runtime variable so the kernel can
- * make use of it
- */
- efi_status = mirror_mok_sb_state();
-
- /*
- * Create the runtime MokIgnoreDB variable so the kernel can
- * make use of it
- */
- efi_status = mok_ignore_db();
-
- /*
* Hand over control to the second stage bootloader
*/
efi_status = init_grub(image_handle);