diff options
| -rw-r--r-- | include/sbat.h | 11 | ||||
| -rw-r--r-- | sbat.c | 81 | ||||
| -rw-r--r-- | shim.c | 48 |
3 files changed, 123 insertions, 17 deletions
diff --git a/include/sbat.h b/include/sbat.h index 5b64f20a..95fa6a56 100644 --- a/include/sbat.h +++ b/include/sbat.h @@ -6,6 +6,16 @@ #ifndef SBAT_H_ #define SBAT_H_ +#define SBAT_VAR_SIG "sbat," +#define SBAT_VAR_VERSION "1," +#define SBAT_VAR_DATE "2021030218" +#define SBAT_VAR SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_DATE "\n" + +#define UEFI_VAR_NV_BS \ + (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS) +#define UEFI_VAR_NV_BS_TIMEAUTH \ + (UEFI_VAR_NV_BS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + extern UINTN _sbat, _esbat; struct sbat_var_entry { @@ -23,6 +33,7 @@ extern list_t sbat_var; EFI_STATUS parse_sbat_var(list_t *entries); void cleanup_sbat_var(list_t *entries); +EFI_STATUS set_sbat_uefi_variable(void); struct sbat_section_entry { const CHAR8 *component_name; @@ -293,4 +293,85 @@ parse_sbat_var(list_t *entries) return parse_sbat_var_data(entries, data, datasize+1); } +EFI_STATUS +set_sbat_uefi_variable(void) +{ + EFI_STATUS efi_status = EFI_SUCCESS; + UINT32 attributes = 0; + + UINT8 *sbat = NULL; + UINTN sbatsize = 0; + + efi_status = get_variable_size(L"SBAT", SHIM_LOCK_GUID, &sbatsize); + if (EFI_ERROR(efi_status)) + dprint(L"SBAT size probe failed %r\n", efi_status); + + if (sbatsize != 0) { + sbat = AllocateZeroPool(sbatsize + 1); + if (!sbat) + return EFI_OUT_OF_RESOURCES; + + efi_status = get_variable_attr(L"SBAT", &sbat, &sbatsize, + SHIM_LOCK_GUID, &attributes); + } + + /* + * Always set the SBAT UEFI variable if it fails to read. + * + * Don't try to set the SBAT UEFI variable if attributes match, the + * signature matches and it has the same or newer version. + */ + if (EFI_ERROR(efi_status)) { + dprint(L"SBAT read failed %r\n", efi_status); + } else if ((attributes == UEFI_VAR_NV_BS || + attributes == UEFI_VAR_NV_BS_TIMEAUTH) && + strncmp(sbat, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG)) == 0) { + FreePool(sbat); + return EFI_SUCCESS; + } + + /* delete previous variable */ + efi_status = set_variable(L"SBAT", SHIM_LOCK_GUID, attributes, 0, ""); + if (EFI_ERROR(efi_status)) + dprint(L"SBAT variable delete failed %r\n", efi_status); + + /* verify that it's gone */ + efi_status = get_variable(L"SBAT", &sbat, &sbatsize, SHIM_LOCK_GUID); + if (EFI_ERROR(efi_status) || (sbatsize != 0)) + dprint(L"SBAT variable clearing failed %r\n", efi_status); + + /* set variable */ + efi_status = set_variable(L"SBAT", SHIM_LOCK_GUID, + UEFI_VAR_NV_BS, sizeof (SBAT_VAR), SBAT_VAR); + if (EFI_ERROR(efi_status)) + dprint(L"SBAT variable writing failed %r\n", efi_status); + + FreePool(sbat); + + /* verify that the expected data is there */ + efi_status = get_variable_size(L"SBAT", SHIM_LOCK_GUID, &sbatsize); + if (EFI_ERROR(efi_status) || sbatsize == 0) { + dprint(L"SBAT read failed %r\n", efi_status); + return EFI_INVALID_PARAMETER; + } + + sbat = AllocateZeroPool(sbatsize); + if (!sbat) + return EFI_OUT_OF_RESOURCES; + + efi_status = get_variable(L"SBAT", &sbat, &sbatsize, SHIM_LOCK_GUID); + if (EFI_ERROR(efi_status)) + dprint(L"SBAT read failed %r\n", efi_status); + + if (strncmp(sbat, SBAT_VAR, strlen(SBAT_VAR)) != 0) { + efi_status = EFI_INVALID_PARAMETER; + } else { + dprint(L"SBAT variable initialization succeeded\n"); + efi_status = EFI_SUCCESS; + } + + FreePool(sbat); + return efi_status; +} + // vim:fenc=utf-8:tw=75:noet @@ -1763,7 +1763,8 @@ shim_init(void) void shim_fini(void) { - cleanup_sbat_var(&sbat_var); + if (secure_mode()) + cleanup_sbat_var(&sbat_var); /* * Remove our protocols @@ -1869,6 +1870,7 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) L"shim_init() failed", L"import of SBAT data failed", L"SBAT self-check failed", + L"SBAT UEFI variable setting failed", NULL }; enum { @@ -1876,6 +1878,7 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) SHIM_INIT, IMPORT_SBAT, SBAT_SELF_CHECK, + SET_SBAT, } msg = IMPORT_MOK_STATE; /* @@ -1905,25 +1908,28 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) */ debug_hook(); - INIT_LIST_HEAD(&sbat_var); - efi_status = parse_sbat_var(&sbat_var); - /* - * Until a SBAT variable is installed into the systems, it is expected that - * attempting to parse the variable will fail with an EFI_NOT_FOUND error. - * - * Do not consider that error fatal for now. - */ - if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) { - perror(L"Parsing SBAT variable failed: %r\n", - efi_status); - msg = IMPORT_SBAT; - goto die; - } - - if (secure_mode ()) { + if (secure_mode()) { char *sbat_start = (char *)&_sbat; char *sbat_end = (char *)&_esbat; + INIT_LIST_HEAD(&sbat_var); + efi_status = parse_sbat_var(&sbat_var); + if (EFI_ERROR(efi_status)) { + efi_status = set_sbat_uefi_variable(); + if (efi_status == EFI_INVALID_PARAMETER) { + perror(L"SBAT variable initialization failed\n"); + msg = SET_SBAT; + goto die; + } + efi_status = parse_sbat_var(&sbat_var); + if (EFI_ERROR(efi_status)) { + perror(L"Parsing SBAT variable failed: %r\n", + efi_status); + msg = IMPORT_SBAT; + goto die; + } + } + efi_status = handle_sbat(sbat_start, sbat_end - sbat_start); if (EFI_ERROR(efi_status)) { perror(L"Verifiying shim SBAT data failed: %r\n", @@ -1933,6 +1939,14 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) } } + efi_status = set_sbat_uefi_variable(); + if (efi_status == EFI_INVALID_PARAMETER) { + perror(L"SBAT variable initialization failed\n"); + msg = SET_SBAT; + if (secure_mode()) + goto die; + } + init_openssl(); /* |
