summaryrefslogtreecommitdiff
path: root/shim.c
diff options
context:
space:
mode:
Diffstat (limited to 'shim.c')
-rw-r--r--shim.c179
1 files changed, 123 insertions, 56 deletions
diff --git a/shim.c b/shim.c
index c69961b9..6e040c4f 100644
--- a/shim.c
+++ b/shim.c
@@ -62,7 +62,7 @@
#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_HANDLE global_image_handle;
static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
static CHAR16 *second_stage;
@@ -422,8 +422,6 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
X509_free(x509);
}
- OBJ_cleanup();
-
return TRUE;
}
@@ -567,31 +565,31 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
sha256hash) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
EFI_CERT_SHA256_GUID) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
EFI_CERT_SHA1_GUID) == DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
DATA_FOUND)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"MokListX", shim_var, sha256hash, SHA256_DIGEST_SIZE,
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
}
if (cert && check_db_cert(L"MokListX", shim_var, cert, sha256hash) ==
DATA_FOUND) {
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
}
return EFI_SUCCESS;
@@ -646,7 +644,7 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
}
update_verification_method(VERIFIED_BY_NOTHING);
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
}
/*
@@ -686,12 +684,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) { \
+ 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) { \
+ status = EFI_INVALID_PARAMETER; \
perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \
hashsize); \
goto done; \
@@ -887,6 +887,13 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
if (datasize > SumOfBytesHashed) {
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");
+ status = EFI_INVALID_PARAMETER;
+ goto done;
+ }
check_size(data, datasize_in, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
@@ -932,7 +939,7 @@ static EFI_STATUS verify_mok (void) {
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;
+ return EFI_SECURITY_VIOLATION;
}
}
@@ -950,7 +957,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
{
UINT8 sha256hash[SHA256_DIGEST_SIZE];
UINT8 sha1hash[SHA1_DIGEST_SIZE];
- EFI_STATUS status = EFI_ACCESS_DENIED;
+ EFI_STATUS status = EFI_SECURITY_VIOLATION;
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
unsigned int size = datasize;
@@ -996,7 +1003,6 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
* Ensure that the binary isn't blacklisted
*/
status = check_blacklist(cert, sha256hash, sha1hash);
-
if (status != EFI_SUCCESS) {
perror(L"Binary is blacklisted\n");
return status;
@@ -1019,6 +1025,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
shim_cert, sizeof(shim_cert), sha256hash,
SHA256_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
@@ -1031,13 +1038,13 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size,
sha256hash, SHA256_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
}
- status = EFI_ACCESS_DENIED;
-
+ status = EFI_SECURITY_VIOLATION;
return status;
}
@@ -1184,7 +1191,8 @@ 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;
+ EFI_PHYSICAL_ADDRESS alloc_address;
int found_entry_point = 0;
/*
@@ -1229,20 +1237,29 @@ 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);
- if (!buffer) {
+ efi_status = uefi_call_wrapper (BS->AllocatePages, 4,
+ AllocateAnyPages,
+ EfiLoaderCode,
+ alloc_size / PAGE_SIZE,
+ &alloc_address);
+
+ if (efi_status != EFI_SUCCESS) {
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) {
perror(L"Entry point is invalid\n");
- FreePool(buffer);
+ uefi_call_wrapper(BS->FreePages, 2, alloc_address,
+ alloc_size / PAGE_SIZE);
return EFI_UNSUPPORTED;
}
@@ -1276,7 +1293,8 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
if (end < base) {
perror(L"Section %d has negative size\n", i);
- FreePool(buffer);
+ uefi_call_wrapper(BS->FreePages, 2, alloc_address,
+ alloc_size / PAGE_SIZE);
return EFI_UNSUPPORTED;
}
@@ -1797,8 +1815,8 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
}
/* Measure the binary into the TPM */
- tpm_log_event((EFI_PHYSICAL_ADDRESS)data, datasize, 9,
- (CHAR8 *)"Second stage bootloader");
+ tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
+ 9, (CHAR8 *)"Second stage bootloader");
/*
* We need to modify the loaded image protocol entry before running
@@ -1848,8 +1866,8 @@ 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);
@@ -1883,8 +1901,8 @@ EFI_STATUS measure_mok()
if (efi_status != EFI_SUCCESS)
return efi_status;
- efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
- (CHAR8 *)"MokList");
+ efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
+ DataSize, 14, (CHAR8 *)"MokList");
FreePool(Data);
@@ -1897,8 +1915,8 @@ EFI_STATUS measure_mok()
if (efi_status != EFI_SUCCESS)
return efi_status;
- efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
- (CHAR8 *)"MokSBState");
+ efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
+ DataSize, 14, (CHAR8 *)"MokSBState");
FreePool(Data);
@@ -1962,13 +1980,15 @@ EFI_STATUS mirror_mok_list()
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);
+ if (FullDataSize) {
+ 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;
@@ -2013,18 +2033,32 @@ EFI_STATUS mirror_mok_sb_state()
UINTN DataSize = 0;
efi_status = get_variable(L"MokSBState", &Data, &DataSize, shim_lock_guid);
- if (efi_status != EFI_SUCCESS)
- return efi_status;
+ if (efi_status == EFI_SUCCESS) {
+ UINT8 *Data_RT = NULL;
+ UINTN DataSize_RT = 0;
+
+ efi_status = get_variable(L"MokSBStateRT", &Data_RT,
+ &DataSize_RT, shim_lock_guid);
+ if (efi_status == EFI_SUCCESS) {
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5,
+ L"MokSBStateRT",
+ &shim_lock_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ }
- 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);
+ 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;
}
@@ -2090,7 +2124,7 @@ static EFI_STATUS check_mok_sb (void)
status = uefi_call_wrapper(RT->GetVariable, 5, L"MokSBState", &shim_lock_guid,
&attributes, &MokSBStateSize, &MokSBState);
if (status != EFI_SUCCESS)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
/*
* Delete and ignore the variable if it's been set from or could be
@@ -2101,7 +2135,7 @@ static EFI_STATUS check_mok_sb (void)
if (LibDeleteVariable(L"MokSBState", &shim_lock_guid) != EFI_SUCCESS) {
perror(L"Failed to erase MokSBState\n");
}
- status = EFI_ACCESS_DENIED;
+ status = EFI_SECURITY_VIOLATION;
} else {
if (MokSBState == 1) {
user_insecure_mode = 1;
@@ -2126,7 +2160,7 @@ static EFI_STATUS check_mok_db (void)
status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDBState", &shim_lock_guid,
&attributes, &MokDBStateSize, &MokDBState);
if (status != EFI_SUCCESS)
- return EFI_ACCESS_DENIED;
+ return EFI_SECURITY_VIOLATION;
ignore_db = 0;
@@ -2139,7 +2173,7 @@ static EFI_STATUS check_mok_db (void)
if (LibDeleteVariable(L"MokDBState", &shim_lock_guid) != EFI_SUCCESS) {
perror(L"Failed to erase MokDBState\n");
}
- status = EFI_ACCESS_DENIED;
+ status = EFI_SECURITY_VIOLATION;
} else {
if (MokDBState == 1) {
ignore_db = 1;
@@ -2285,13 +2319,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;
+
+ Print(L"dppath: %s\n", dppath);
+ Print(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_LOADED_IMAGE *li = NULL;
CHAR16 *start = NULL;
int remaining_size = 0;
CHAR16 *loader_str = NULL;
@@ -2454,6 +2506,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,7 +2535,7 @@ 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;
}
@@ -2541,7 +2607,7 @@ shim_init(void)
dprinta(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) {
@@ -2639,6 +2705,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;
@@ -2656,7 +2723,7 @@ 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