mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-08-15 02:18:32 +00:00
shim: Make our variable validation and mirroring table driven.
This makes it so shim's idea of Mok variables all resides in one table of data, and we don't need a bunch of nearly identical ad-hoc functions to handle each of them. Signed-off-by: Peter Jones <pjones@redhat.com>
This commit is contained in:
parent
dd712378a7
commit
4181a16f62
4
Makefile
4
Makefile
@ -33,9 +33,9 @@ CFLAGS += -DENABLE_SHIM_CERT
|
|||||||
else
|
else
|
||||||
TARGETS += $(MMNAME) $(FBNAME)
|
TARGETS += $(MMNAME) $(FBNAME)
|
||||||
endif
|
endif
|
||||||
OBJS = shim.o netboot.o cert.o replacements.o tpm.o version.o errlog.o
|
OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o
|
||||||
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
|
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
|
||||||
ORIG_SOURCES = shim.c netboot.c replacements.c tpm.c errlog.c shim.h version.h $(wildcard include/*.h)
|
ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c shim.h version.h $(wildcard include/*.h)
|
||||||
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o
|
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o
|
||||||
ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h)
|
ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h)
|
||||||
FALLBACK_OBJS = fallback.o tpm.o
|
FALLBACK_OBJS = fallback.o tpm.o
|
||||||
|
334
mok.c
Normal file
334
mok.c
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
/*
|
||||||
|
* mok.c
|
||||||
|
* Copyright 2017 Peter Jones <pjones@redhat.com>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPLv3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shim.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if a variable exists
|
||||||
|
*/
|
||||||
|
static BOOLEAN check_var(CHAR16 *varname)
|
||||||
|
{
|
||||||
|
EFI_STATUS efi_status;
|
||||||
|
UINTN size = sizeof(UINT32);
|
||||||
|
UINT32 MokVar;
|
||||||
|
UINT32 attributes;
|
||||||
|
|
||||||
|
efi_status = gRT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
|
||||||
|
&size, (void *)&MokVar);
|
||||||
|
if (!EFI_ERROR(efi_status) || 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
|
||||||
|
*/
|
||||||
|
static 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_ERROR(efi_status)) {
|
||||||
|
perror(L"Failed to start MokManager: %r\n", efi_status);
|
||||||
|
return efi_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MoK variables that need to have their storage validated.
|
||||||
|
*
|
||||||
|
* The order here is important, since this is where we measure for the
|
||||||
|
* tpm as well.
|
||||||
|
*/
|
||||||
|
struct mok_state_variable {
|
||||||
|
CHAR16 *name;
|
||||||
|
char *name8;
|
||||||
|
CHAR16 *rtname;
|
||||||
|
EFI_GUID *guid;
|
||||||
|
UINT8 *data;
|
||||||
|
UINTN data_size;
|
||||||
|
/*
|
||||||
|
* These two are indirect pointers just to make initialization
|
||||||
|
* saner...
|
||||||
|
*/
|
||||||
|
UINT8 **addend_source;
|
||||||
|
UINT32 *addend_size;
|
||||||
|
UINT32 yes_attr;
|
||||||
|
UINT32 no_attr;
|
||||||
|
UINT32 flags;
|
||||||
|
UINTN pcr;
|
||||||
|
UINT8 *state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOK_MIRROR_KEYDB 0x01
|
||||||
|
#define MOK_MIRROR_DELETE_FIRST 0x02
|
||||||
|
#define MOK_VARIABLE_MEASURE 0x04
|
||||||
|
#define MOK_VARIABLE_LOG 0x08
|
||||||
|
|
||||||
|
struct mok_state_variable mok_state_variables[] = {
|
||||||
|
{.name = L"MokList",
|
||||||
|
.name8 = "MokList",
|
||||||
|
.rtname = L"MokListRT",
|
||||||
|
.guid = &SHIM_LOCK_GUID,
|
||||||
|
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_NON_VOLATILE,
|
||||||
|
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
.addend_source = &vendor_cert,
|
||||||
|
.addend_size = &vendor_cert_size,
|
||||||
|
.flags = MOK_MIRROR_KEYDB |
|
||||||
|
MOK_VARIABLE_LOG,
|
||||||
|
.pcr = 14,
|
||||||
|
},
|
||||||
|
{.name = L"MokListX",
|
||||||
|
.name8 = "MokListX",
|
||||||
|
.rtname = L"MokListXRT",
|
||||||
|
.guid = &SHIM_LOCK_GUID,
|
||||||
|
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_NON_VOLATILE,
|
||||||
|
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
.flags = MOK_MIRROR_KEYDB |
|
||||||
|
MOK_VARIABLE_LOG,
|
||||||
|
.pcr = 14,
|
||||||
|
},
|
||||||
|
{.name = L"MokSBState",
|
||||||
|
.name8 = "MokSBState",
|
||||||
|
.rtname = L"MokSBStateRT",
|
||||||
|
.guid = &SHIM_LOCK_GUID,
|
||||||
|
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_NON_VOLATILE,
|
||||||
|
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
.flags = MOK_MIRROR_DELETE_FIRST |
|
||||||
|
MOK_VARIABLE_MEASURE |
|
||||||
|
MOK_VARIABLE_LOG,
|
||||||
|
.pcr = 14,
|
||||||
|
.state = &user_insecure_mode,
|
||||||
|
},
|
||||||
|
{.name = L"MokDBState",
|
||||||
|
.name8 = "MokDBState",
|
||||||
|
.rtname = L"MokIgnoreDB",
|
||||||
|
.guid = &SHIM_LOCK_GUID,
|
||||||
|
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_NON_VOLATILE,
|
||||||
|
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
.state = &ignore_db,
|
||||||
|
},
|
||||||
|
{ NULL, }
|
||||||
|
};
|
||||||
|
|
||||||
|
static EFI_STATUS mirror_one_mok_variable(struct mok_state_variable *v)
|
||||||
|
{
|
||||||
|
EFI_STATUS efi_status = EFI_SUCCESS;
|
||||||
|
void *FullData = NULL;
|
||||||
|
UINTN FullDataSize = 0;
|
||||||
|
uint8_t *p = NULL;
|
||||||
|
|
||||||
|
if ((v->flags & MOK_MIRROR_KEYDB) &&
|
||||||
|
v->addend_source && *v->addend_source &&
|
||||||
|
v->addend_size && *v->addend_size) {
|
||||||
|
EFI_SIGNATURE_LIST *CertList = NULL;
|
||||||
|
EFI_SIGNATURE_DATA *CertData = NULL;
|
||||||
|
FullDataSize = v->data_size
|
||||||
|
+ sizeof (*CertList)
|
||||||
|
+ sizeof (EFI_GUID)
|
||||||
|
+ *v->addend_size;
|
||||||
|
FullData = AllocatePool(FullDataSize);
|
||||||
|
if (!FullData) {
|
||||||
|
perror(L"Failed to allocate space for MokListRT\n");
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
p = FullData;
|
||||||
|
|
||||||
|
if (!EFI_ERROR(efi_status) && v->data_size > 0) {
|
||||||
|
CopyMem(p, v->data, v->data_size);
|
||||||
|
p += v->data_size;
|
||||||
|
}
|
||||||
|
CertList = (EFI_SIGNATURE_LIST *)p;
|
||||||
|
p += sizeof (*CertList);
|
||||||
|
CertData = (EFI_SIGNATURE_DATA *)p;
|
||||||
|
p += sizeof (EFI_GUID);
|
||||||
|
|
||||||
|
CertList->SignatureType = EFI_CERT_TYPE_X509_GUID;
|
||||||
|
CertList->SignatureListSize = *v->addend_size
|
||||||
|
+ sizeof (*CertList)
|
||||||
|
+ sizeof (*CertData)
|
||||||
|
-1;
|
||||||
|
CertList->SignatureHeaderSize = 0;
|
||||||
|
CertList->SignatureSize = *v->addend_size + sizeof (EFI_GUID);
|
||||||
|
|
||||||
|
CertData->SignatureOwner = SHIM_LOCK_GUID;
|
||||||
|
CopyMem(p, *v->addend_source, *v->addend_size);
|
||||||
|
|
||||||
|
if (v->data && v->data_size)
|
||||||
|
FreePool(v->data);
|
||||||
|
v->data = FullData;
|
||||||
|
v->data_size = FullDataSize;
|
||||||
|
} else {
|
||||||
|
FullDataSize = v->data_size;
|
||||||
|
FullData = v->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FullDataSize) {
|
||||||
|
efi_status = gRT->SetVariable(v->rtname, v->guid,
|
||||||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
FullDataSize, FullData);
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
perror(L"Failed to set %s: %r\n",
|
||||||
|
v->rtname, efi_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return efi_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify our non-volatile MoK state. This checks the variables above
|
||||||
|
* accessable and have valid attributes. If they don't, it removes
|
||||||
|
* them. If any of them can't be removed, our ability to do this is
|
||||||
|
* comprimized, so return EFI_SECURITY_VIOLATION.
|
||||||
|
*
|
||||||
|
* Any variable that isn't deleted and has ->measure == TRUE is then
|
||||||
|
* measured into the tpm.
|
||||||
|
*
|
||||||
|
* Any variable with a ->rtname element is then mirrored to a
|
||||||
|
* runtime-accessable version. The new ones won't be marked NV, so the OS
|
||||||
|
* can't modify them.
|
||||||
|
*/
|
||||||
|
EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
EFI_STATUS ret = EFI_SUCCESS;
|
||||||
|
EFI_STATUS efi_status;
|
||||||
|
|
||||||
|
user_insecure_mode = 0;
|
||||||
|
ignore_db = 0;
|
||||||
|
|
||||||
|
for (i = 0; mok_state_variables[i].name != NULL; i++) {
|
||||||
|
struct mok_state_variable *v = &mok_state_variables[i];
|
||||||
|
UINT32 attrs = 0;
|
||||||
|
BOOLEAN delete = FALSE, present, addend;
|
||||||
|
|
||||||
|
efi_status = get_variable_attr(v->name,
|
||||||
|
&v->data, &v->data_size,
|
||||||
|
*v->guid, &attrs);
|
||||||
|
if (efi_status == EFI_NOT_FOUND)
|
||||||
|
continue;
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
perror(L"Could not verify %s: %r\n", v->name,
|
||||||
|
efi_status);
|
||||||
|
/*
|
||||||
|
* don't clobber EFI_SECURITY_VIOLATION from some
|
||||||
|
* other variable in the list.
|
||||||
|
*/
|
||||||
|
if (ret != EFI_SECURITY_VIOLATION)
|
||||||
|
ret = efi_status;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(attrs & v->yes_attr)) {
|
||||||
|
perror(L"Variable %s is missing attributes:\n",
|
||||||
|
v->name);
|
||||||
|
perror(L" 0x%08x should have 0x%08x set.\n",
|
||||||
|
attrs, v->yes_attr);
|
||||||
|
delete = TRUE;
|
||||||
|
}
|
||||||
|
if (attrs & v->no_attr) {
|
||||||
|
perror(L"Variable %s has incorrect attribute:\n",
|
||||||
|
v->name);
|
||||||
|
perror(L" 0x%08x should not have 0x%08x set.\n",
|
||||||
|
attrs, v->no_attr);
|
||||||
|
delete = TRUE;
|
||||||
|
}
|
||||||
|
if (delete == TRUE) {
|
||||||
|
perror(L"Deleting bad variable %s\n", v->name);
|
||||||
|
efi_status = LibDeleteVariable(v->name, v->guid);
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
perror(L"Failed to erase %s\n", v->name);
|
||||||
|
ret = EFI_SECURITY_VIOLATION;
|
||||||
|
}
|
||||||
|
FreePool(v->data);
|
||||||
|
v->data = NULL;
|
||||||
|
v->data_size = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->data && v->data_size == sizeof(UINT8) && v->state) {
|
||||||
|
*v->state = v->data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
present = (v->data && v->data_size) ? TRUE : FALSE;
|
||||||
|
addend = (v->addend_source && v->addend_size &&
|
||||||
|
*v->addend_source && *v->addend_size)
|
||||||
|
? TRUE : FALSE;
|
||||||
|
|
||||||
|
if (v->flags & MOK_VARIABLE_MEASURE && present) {
|
||||||
|
/*
|
||||||
|
* Measure this into PCR 7 in the Microsoft format
|
||||||
|
*/
|
||||||
|
efi_status = tpm_measure_variable(v->name, *v->guid,
|
||||||
|
v->data_size,
|
||||||
|
v->data);
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
if (ret != EFI_SECURITY_VIOLATION)
|
||||||
|
ret = efi_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->flags & MOK_VARIABLE_LOG && present) {
|
||||||
|
/*
|
||||||
|
* Log this variable into whichever PCR the table
|
||||||
|
* says.
|
||||||
|
*/
|
||||||
|
EFI_PHYSICAL_ADDRESS datap =
|
||||||
|
(EFI_PHYSICAL_ADDRESS)(UINTN)v->data,
|
||||||
|
efi_status = tpm_log_event(datap, v->data_size,
|
||||||
|
v->pcr, (CHAR8 *)v->name8);
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
if (ret != EFI_SECURITY_VIOLATION)
|
||||||
|
ret = efi_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->rtname && present && addend) {
|
||||||
|
if (v->flags & MOK_MIRROR_DELETE_FIRST)
|
||||||
|
LibDeleteVariable(v->rtname, v->guid);
|
||||||
|
|
||||||
|
efi_status = mirror_one_mok_variable(v);
|
||||||
|
if (EFI_ERROR(efi_status) &&
|
||||||
|
ret != EFI_SECURITY_VIOLATION)
|
||||||
|
ret = efi_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enter MokManager if necessary. Any actual *changes* here will
|
||||||
|
* cause MokManager to demand a machine reboot, so this is safe to
|
||||||
|
* have after the entire loop.
|
||||||
|
*/
|
||||||
|
efi_status = check_mok_request(image_handle);
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
if (ret != EFI_SECURITY_VIOLATION)
|
||||||
|
ret = efi_status;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim:fenc=utf-8:tw=75
|
@ -101,7 +101,7 @@ load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static EFI_STATUS EFIAPI
|
static EFI_STATUS EFIAPI
|
||||||
start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
|
replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
|
||||||
{
|
{
|
||||||
EFI_STATUS efi_status;
|
EFI_STATUS efi_status;
|
||||||
unhook_system_services();
|
unhook_system_services();
|
||||||
@ -187,9 +187,9 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
|
|||||||
/* We need LoadImage() hooked so that fallback.c can load shim
|
/* We need LoadImage() hooked so that fallback.c can load shim
|
||||||
* without having to fake LoadImage as well. This allows it
|
* without having to fake LoadImage as well. This allows it
|
||||||
* to call the system LoadImage(), and have us track the output
|
* to call the system LoadImage(), and have us track the output
|
||||||
* and mark loader_is_participating in start_image. This means
|
* and mark loader_is_participating in replacement_start_image. This
|
||||||
* anything added by fallback has to be verified by the system db,
|
* means anything added by fallback has to be verified by the system
|
||||||
* which we want to preserve anyway, since that's all launching
|
* db, which we want to preserve anyway, since that's all launching
|
||||||
* through BDS gives us. */
|
* through BDS gives us. */
|
||||||
system_load_image = systab->BootServices->LoadImage;
|
system_load_image = systab->BootServices->LoadImage;
|
||||||
systab->BootServices->LoadImage = load_image;
|
systab->BootServices->LoadImage = load_image;
|
||||||
@ -197,7 +197,7 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
|
|||||||
/* we need StartImage() so that we can allow chain booting to an
|
/* we need StartImage() so that we can allow chain booting to an
|
||||||
* image trusted by the firmware */
|
* image trusted by the firmware */
|
||||||
system_start_image = systab->BootServices->StartImage;
|
system_start_image = systab->BootServices->StartImage;
|
||||||
systab->BootServices->StartImage = start_image;
|
systab->BootServices->StartImage = replacement_start_image;
|
||||||
|
|
||||||
/* we need to hook ExitBootServices() so a) we can enforce the policy
|
/* we need to hook ExitBootServices() so a) we can enforce the policy
|
||||||
* and b) we can unwrap when we're done. */
|
* and b) we can unwrap when we're done. */
|
||||||
|
423
shim.c
423
shim.c
@ -52,9 +52,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define FALLBACK L"\\fb" EFI_ARCH L".efi"
|
|
||||||
#define MOK_MANAGER L"\\mm" EFI_ARCH L".efi"
|
|
||||||
|
|
||||||
#define OID_EKU_MODSIGN "1.3.6.1.4.1.2312.16.1.2"
|
#define OID_EKU_MODSIGN "1.3.6.1.4.1.2312.16.1.2"
|
||||||
|
|
||||||
static EFI_SYSTEM_TABLE *systab;
|
static EFI_SYSTEM_TABLE *systab;
|
||||||
@ -971,34 +968,6 @@ done:
|
|||||||
return efi_status;
|
return efi_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure that the MOK database hasn't been set or modified from an OS
|
|
||||||
*/
|
|
||||||
static EFI_STATUS verify_mok (void) {
|
|
||||||
EFI_STATUS efi_status;
|
|
||||||
UINT8 *MokListData = NULL;
|
|
||||||
UINTN MokListDataSize = 0;
|
|
||||||
UINT32 attributes;
|
|
||||||
|
|
||||||
efi_status = get_variable_attr(L"MokList", &MokListData,
|
|
||||||
&MokListDataSize, SHIM_LOCK_GUID,
|
|
||||||
&attributes);
|
|
||||||
if (!EFI_ERROR(efi_status) &&
|
|
||||||
attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
|
|
||||||
perror(L"MokList is compromised!\nErase all keys in MokList!\n");
|
|
||||||
efi_status = LibDeleteVariable(L"MokList", &SHIM_LOCK_GUID);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
perror(L"Failed to erase MokList\n");
|
|
||||||
return EFI_SECURITY_VIOLATION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MokListData)
|
|
||||||
FreePool(MokListData);
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the signature is valid and matches the binary
|
* Check that the signature is valid and matches the binary
|
||||||
*/
|
*/
|
||||||
@ -1053,15 +1022,6 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
|||||||
return efi_status;
|
return efi_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that the MOK database hasn't been modified
|
|
||||||
*/
|
|
||||||
efi_status = verify_mok();
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
LogError(L"verify_mok: %r\n", efi_status);
|
|
||||||
return efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that the binary isn't blacklisted
|
* Ensure that the binary isn't blacklisted
|
||||||
*/
|
*/
|
||||||
@ -1997,337 +1957,6 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
|
|||||||
return efi_status;
|
return efi_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Measure some of the MOK variables into the TPM. We measure the entirety
|
|
||||||
* of MokList into PCR 14, and also measure the raw MokSBState there. PCR 7
|
|
||||||
* will be extended with MokSBState in the Microsoft format, and we'll
|
|
||||||
* measure any matching hashes or certificates later on in order to behave
|
|
||||||
* consistently with the PCR 7 spec.
|
|
||||||
*/
|
|
||||||
EFI_STATUS measure_mok()
|
|
||||||
{
|
|
||||||
EFI_STATUS efi_status, ret = EFI_SUCCESS;
|
|
||||||
UINT8 *Data = NULL;
|
|
||||||
UINTN DataSize = 0;
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokList", &Data, &DataSize, SHIM_LOCK_GUID);
|
|
||||||
if (!EFI_ERROR(efi_status)) {
|
|
||||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
|
|
||||||
DataSize, 14, (CHAR8 *)"MokList");
|
|
||||||
FreePool(Data);
|
|
||||||
|
|
||||||
if (EFI_ERROR(efi_status))
|
|
||||||
ret = efi_status;
|
|
||||||
} else {
|
|
||||||
ret = efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokListX", &Data, &DataSize, SHIM_LOCK_GUID);
|
|
||||||
if (!EFI_ERROR(efi_status)) {
|
|
||||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
|
|
||||||
DataSize, 14, (CHAR8 *)"MokListX");
|
|
||||||
FreePool(Data);
|
|
||||||
|
|
||||||
if (EFI_ERROR(efi_status) && !EFI_ERROR(ret))
|
|
||||||
ret = efi_status;
|
|
||||||
|
|
||||||
} else if (!EFI_ERROR(ret)) {
|
|
||||||
ret = efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokSBState", &Data, &DataSize,
|
|
||||||
SHIM_LOCK_GUID);
|
|
||||||
if (!EFI_ERROR(efi_status)) {
|
|
||||||
efi_status = tpm_measure_variable(L"MokSBState",
|
|
||||||
SHIM_LOCK_GUID,
|
|
||||||
DataSize, Data);
|
|
||||||
if (!EFI_ERROR(efi_status)) {
|
|
||||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)
|
|
||||||
(UINTN)Data, DataSize, 14,
|
|
||||||
(CHAR8 *)"MokSBState");
|
|
||||||
}
|
|
||||||
|
|
||||||
FreePool(Data);
|
|
||||||
|
|
||||||
if (EFI_ERROR(efi_status) && !EFI_ERROR(ret))
|
|
||||||
ret = efi_status;
|
|
||||||
} else if (!EFI_ERROR(ret)) {
|
|
||||||
ret = efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_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_ERROR(efi_status))
|
|
||||||
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_ERROR(efi_status) && 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_TYPE_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FullDataSize) {
|
|
||||||
efi_status = gRT->SetVariable(L"MokListRT", &SHIM_LOCK_GUID,
|
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
||||||
FullDataSize, FullData);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
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_STATUS efi_status;
|
|
||||||
UINT8 *Data = NULL;
|
|
||||||
UINTN DataSize = 0;
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokListX", &Data, &DataSize,
|
|
||||||
SHIM_LOCK_GUID);
|
|
||||||
if (EFI_ERROR(efi_status))
|
|
||||||
return efi_status;
|
|
||||||
|
|
||||||
efi_status = gRT->SetVariable(L"MokListXRT", &SHIM_LOCK_GUID,
|
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
||||||
DataSize, Data);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
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_STATUS efi_status;
|
|
||||||
UINT8 *Data = NULL;
|
|
||||||
UINTN DataSize = 0;
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokSBState", &Data, &DataSize,
|
|
||||||
SHIM_LOCK_GUID);
|
|
||||||
if (!EFI_ERROR(efi_status)) {
|
|
||||||
UINT8 *Data_RT = NULL;
|
|
||||||
UINTN DataSize_RT = 0;
|
|
||||||
|
|
||||||
efi_status = get_variable(L"MokSBStateRT",
|
|
||||||
&Data_RT, &DataSize_RT,
|
|
||||||
SHIM_LOCK_GUID);
|
|
||||||
if (!EFI_ERROR(efi_status) || efi_status != EFI_NOT_FOUND)
|
|
||||||
LibDeleteVariable(L"MokSBStateRT", &SHIM_LOCK_GUID);
|
|
||||||
|
|
||||||
efi_status = gRT->SetVariable(L"MokSBStateRT", &SHIM_LOCK_GUID,
|
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
||||||
DataSize, Data);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
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;
|
|
||||||
UINTN size = sizeof(UINT32);
|
|
||||||
UINT32 MokVar;
|
|
||||||
UINT32 attributes;
|
|
||||||
|
|
||||||
efi_status = gRT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
|
|
||||||
&size, (void *)&MokVar);
|
|
||||||
if (!EFI_ERROR(efi_status) || 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_ERROR(efi_status)) {
|
|
||||||
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_STATUS efi_status;
|
|
||||||
UINT8 MokSBState;
|
|
||||||
UINTN MokSBStateSize = sizeof(MokSBState);
|
|
||||||
UINT32 attributes;
|
|
||||||
|
|
||||||
user_insecure_mode = 0;
|
|
||||||
ignore_db = 0;
|
|
||||||
|
|
||||||
efi_status = gRT->GetVariable(L"MokSBState", &SHIM_LOCK_GUID,
|
|
||||||
&attributes, &MokSBStateSize,
|
|
||||||
&MokSBState);
|
|
||||||
if (EFI_ERROR(efi_status))
|
|
||||||
return EFI_SECURITY_VIOLATION;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
efi_status = LibDeleteVariable(L"MokSBState", &SHIM_LOCK_GUID);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
perror(L"Failed to erase MokSBState\n");
|
|
||||||
}
|
|
||||||
efi_status = EFI_SECURITY_VIOLATION;
|
|
||||||
} else {
|
|
||||||
if (MokSBState == 1) {
|
|
||||||
user_insecure_mode = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Verify that MokDBState is valid, and if appropriate set ignore db mode
|
|
||||||
*/
|
|
||||||
|
|
||||||
static EFI_STATUS check_mok_db (void)
|
|
||||||
{
|
|
||||||
EFI_STATUS efi_status;
|
|
||||||
UINT8 MokDBState;
|
|
||||||
UINTN MokDBStateSize = sizeof(MokDBState);
|
|
||||||
UINT32 attributes;
|
|
||||||
|
|
||||||
efi_status = gRT->GetVariable(L"MokDBState", &SHIM_LOCK_GUID,
|
|
||||||
&attributes, &MokDBStateSize,
|
|
||||||
&MokDBState);
|
|
||||||
if (EFI_ERROR(efi_status))
|
|
||||||
return EFI_SECURITY_VIOLATION;
|
|
||||||
|
|
||||||
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");
|
|
||||||
efi_status = LibDeleteVariable(L"MokDBState", &SHIM_LOCK_GUID);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
perror(L"Failed to erase MokDBState\n");
|
|
||||||
}
|
|
||||||
efi_status = EFI_SECURITY_VIOLATION;
|
|
||||||
} else {
|
|
||||||
if (MokDBState == 1) {
|
|
||||||
ignore_db = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return efi_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EFI_STATUS mok_ignore_db()
|
|
||||||
{
|
|
||||||
EFI_STATUS efi_status = EFI_SUCCESS;
|
|
||||||
UINT8 Data = 1;
|
|
||||||
UINTN DataSize = sizeof(UINT8);
|
|
||||||
|
|
||||||
check_mok_db();
|
|
||||||
|
|
||||||
if (ignore_db) {
|
|
||||||
efi_status = gRT->SetVariable(L"MokIgnoreDB", &SHIM_LOCK_GUID,
|
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
||||||
DataSize, (void *)&Data);
|
|
||||||
if (EFI_ERROR(efi_status)) {
|
|
||||||
perror(L"Failed to set MokIgnoreDB: %r\n", efi_status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return efi_status;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline EFI_STATUS
|
static inline EFI_STATUS
|
||||||
get_load_option_optional_data(UINT8 *data, UINTN data_size,
|
get_load_option_optional_data(UINT8 *data, UINTN data_size,
|
||||||
UINT8 **od, UINTN *ods)
|
UINT8 **od, UINTN *ods)
|
||||||
@ -2922,31 +2551,22 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
|||||||
debug_hook();
|
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();
|
efi_status = import_mok_state(image_handle);
|
||||||
if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
|
if (EFI_ERROR(efi_status)) {
|
||||||
Print(L"Something has gone seriously wrong: %r\n", efi_status);
|
die:
|
||||||
Print(L"Shim was unable to measure state into the TPM\n");
|
Print(L"Something has gone seriously wrong: %r\n",
|
||||||
|
efi_status);
|
||||||
msleep(5000000);
|
msleep(5000000);
|
||||||
gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
|
gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
|
||||||
0, NULL);
|
0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether the user has configured the system to run in
|
|
||||||
* insecure mode
|
|
||||||
*/
|
|
||||||
check_mok_sb();
|
|
||||||
|
|
||||||
efi_status = shim_init();
|
efi_status = shim_init();
|
||||||
if (EFI_ERROR(efi_status)) {
|
if (EFI_ERROR(efi_status))
|
||||||
Print(L"Something has gone seriously wrong: %r\n", efi_status);
|
goto die;
|
||||||
Print(L"shim cannot continue, sorry.\n");
|
|
||||||
msleep(5000000);
|
|
||||||
gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
|
|
||||||
0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the user that we're in insecure mode if necessary
|
* Tell the user that we're in insecure mode if necessary
|
||||||
@ -2956,31 +2576,6 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
|||||||
msleep(2000000);
|
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
|
|
||||||
*/
|
|
||||||
mok_ignore_db();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hand over control to the second stage bootloader
|
* Hand over control to the second stage bootloader
|
||||||
*/
|
*/
|
||||||
|
8
shim.h
8
shim.h
@ -92,6 +92,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FALLBACK L"\\fb" EFI_ARCH L".efi"
|
||||||
|
#define MOK_MANAGER L"\\mm" EFI_ARCH L".efi"
|
||||||
|
|
||||||
#include "include/configtable.h"
|
#include "include/configtable.h"
|
||||||
#include "include/console.h"
|
#include "include/console.h"
|
||||||
#include "include/crypt_blowfish.h"
|
#include "include/crypt_blowfish.h"
|
||||||
@ -160,13 +163,18 @@ extern EFI_STATUS LogError_(const char *file, int line, const char *func, CHAR16
|
|||||||
extern EFI_STATUS VLogError(const char *file, int line, const char *func, CHAR16 *fmt, va_list args);
|
extern EFI_STATUS VLogError(const char *file, int line, const char *func, CHAR16 *fmt, va_list args);
|
||||||
extern VOID PrintErrors(VOID);
|
extern VOID PrintErrors(VOID);
|
||||||
extern VOID ClearErrors(VOID);
|
extern VOID ClearErrors(VOID);
|
||||||
|
extern EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath);
|
||||||
|
extern EFI_STATUS import_mok_state(EFI_HANDLE image_handle);
|
||||||
|
|
||||||
extern UINT32 vendor_cert_size;
|
extern UINT32 vendor_cert_size;
|
||||||
extern UINT32 vendor_dbx_size;
|
extern UINT32 vendor_dbx_size;
|
||||||
extern UINT8 *vendor_cert;
|
extern UINT8 *vendor_cert;
|
||||||
extern UINT8 *vendor_dbx;
|
extern UINT8 *vendor_dbx;
|
||||||
|
|
||||||
|
extern UINT8 user_insecure_mode;
|
||||||
|
extern UINT8 ignore_db;
|
||||||
extern UINT8 in_protocol;
|
extern UINT8 in_protocol;
|
||||||
|
|
||||||
#define perror_(file, line, func, fmt, ...) ({ \
|
#define perror_(file, line, func, fmt, ...) ({ \
|
||||||
UINTN __perror_ret = 0; \
|
UINTN __perror_ret = 0; \
|
||||||
if (!in_protocol) \
|
if (!in_protocol) \
|
||||||
|
Loading…
Reference in New Issue
Block a user