summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sbat.h11
-rw-r--r--sbat.c81
-rw-r--r--shim.c48
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;
diff --git a/sbat.c b/sbat.c
index fec22a73..3f67136b 100644
--- a/sbat.c
+++ b/sbat.c
@@ -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
diff --git a/shim.c b/shim.c
index 5975feb8..ad01a07f 100644
--- a/shim.c
+++ b/shim.c
@@ -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();
/*