summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Setje-Eilers <jan.setjeeilers@oracle.com>2023-04-28 19:54:14 -0700
committerPeter Jones <pjones@redhat.com>2023-12-05 13:20:00 -0500
commit7dfb6871b8a54710d9e9d8d56146e7c083d2e6a8 (patch)
tree529953a0f0b0031ed1ce5105f1b1279a259ef27a
parentb078ef274887a4cc0da64fd6668800d1e24a2871 (diff)
downloadefi-boot-shim-7dfb6871b8a54710d9e9d8d56146e7c083d2e6a8.tar.gz
efi-boot-shim-7dfb6871b8a54710d9e9d8d56146e7c083d2e6a8.zip
BS Variables for bootmgr revocations
This adds support for applying SkuSiPolicy UEFI BS variables. These varaibles are needed for non-dbx based Windows revocations and are described here: https://support.microsoft.com/en-us/topic/kb5027455-guidance-for-blocking-vulnerable-windows-boot-managers-522bb851-0a61-44ad-aa94-ad11119c5e91 Signed-off-by: Jan Setje-Eilers <Jan.SetjeEilers@oracle.com>
-rw-r--r--include/guid.h1
-rw-r--r--include/sbat.h10
-rw-r--r--include/sbat_var_defs.h1
-rw-r--r--include/ssp.h14
-rw-r--r--include/ssp_var_defs.h19
-rw-r--r--lib/guid.c1
-rw-r--r--sbat.c211
-rw-r--r--shim.c77
-rw-r--r--shim.h1
9 files changed, 304 insertions, 31 deletions
diff --git a/include/guid.h b/include/guid.h
index dad63f0f..898c4fad 100644
--- a/include/guid.h
+++ b/include/guid.h
@@ -37,5 +37,6 @@ extern EFI_GUID SECURITY2_PROTOCOL_GUID;
extern EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
extern EFI_GUID SHIM_LOCK_GUID;
extern EFI_GUID MOK_VARIABLE_STORE;
+extern EFI_GUID SECUREBOOT_EFI_NAMESPACE_GUID;
#endif /* SHIM_GUID_H */
diff --git a/include/sbat.h b/include/sbat.h
index 84f5ef01..af4c1a8f 100644
--- a/include/sbat.h
+++ b/include/sbat.h
@@ -30,11 +30,13 @@
#define SBAT_POLICY L"SbatPolicy"
#define SBAT_POLICY8 "SbatPolicy"
+#define SSP_POLICY L"SSPPolicy"
+#define SSP_POLICY8 "SSPPolicy"
-#define SBAT_POLICY_LATEST 1
-#define SBAT_POLICY_PREVIOUS 2
-#define SBAT_POLICY_RESET 3
-#define SBAT_POLICY_NOTREAD 255
+#define POLICY_LATEST 1
+#define POLICY_PREVIOUS 2
+#define POLICY_RESET 3
+#define POLICY_NOTREAD 255
extern UINTN _sbat, _esbat;
diff --git a/include/sbat_var_defs.h b/include/sbat_var_defs.h
index 2ea98e4e..772df972 100644
--- a/include/sbat_var_defs.h
+++ b/include/sbat_var_defs.h
@@ -42,5 +42,4 @@
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS
#endif /* ENABLE_SHIM_DEVEL */
-
#endif /* !SBAT_VAR_DEFS_H_ */
diff --git a/include/ssp.h b/include/ssp.h
new file mode 100644
index 00000000..f25590c6
--- /dev/null
+++ b/include/ssp.h
@@ -0,0 +1,14 @@
+#ifndef SSP_H_
+#define SSP_H_
+
+#define SSPVER_VAR_NAME L"SkuSiPolicyVersion"
+#define SSPSIG_VAR_NAME L"SkuSiPolicyUpdateSigners"
+#define SSP_VAR_ATTRS UEFI_VAR_NV_BS
+
+#define SSPVER_SIZE 8
+#define SSPSIG_SIZE 131
+
+EFI_STATUS set_ssp_uefi_variable_internal(void);
+EFI_STATUS set_ssp_uefi_variable(uint8_t*, uint8_t*, uint8_t*, uint8_t*);
+
+#endif /* !SSP_H_ */
diff --git a/include/ssp_var_defs.h b/include/ssp_var_defs.h
new file mode 100644
index 00000000..4bfad878
--- /dev/null
+++ b/include/ssp_var_defs.h
@@ -0,0 +1,19 @@
+/*
+ * variable definitions to enable bootmgr self revocation
+ */
+#ifndef SSP_VAR_DEFS_H_
+#define SSP_VAR_DEFS_H_
+
+uint8_t SkuSiPolicyVersion[] = { 0x2,0x0,0x0,0x0,0x0,0x0,0x2,0x0 };
+uint8_t SkuSiPolicyUpdateSigners[] = {
+0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+0x0b,0x00,0x00,0x00,0xd0,0x91,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x54,0xa6,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x5c,0xa6,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x64,0xa6,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x03,0x06,0x00,
+0x00,0x00,0x00 };
+
+#endif /* !SSP_VAR_DEFS_H_ */
diff --git a/lib/guid.c b/lib/guid.c
index 904629eb..6e92cea3 100644
--- a/lib/guid.c
+++ b/lib/guid.c
@@ -36,3 +36,4 @@ EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x
EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID = { 0xf4560cf6, 0x40ec, 0x4b4a, {0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89} };
EFI_GUID SHIM_LOCK_GUID = {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } };
EFI_GUID MOK_VARIABLE_STORE = {0xc451ed2b, 0x9694, 0x45d3, {0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89} };
+EFI_GUID SECUREBOOT_EFI_NAMESPACE_GUID = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b} };
diff --git a/sbat.c b/sbat.c
index 60669ba1..b33fe85c 100644
--- a/sbat.c
+++ b/sbat.c
@@ -4,13 +4,16 @@
*/
#include "shim.h"
+#include "ssp.h"
+#include "ssp_var_defs.h"
extern struct {
UINT32 previous_offset;
UINT32 latest_offset;
} sbat_var_payload_header;
-static UINT8 sbat_policy = SBAT_POLICY_NOTREAD;
+static UINT8 sbat_policy = POLICY_NOTREAD;
+static UINT8 ssp_policy = POLICY_NOTREAD;
EFI_STATUS
parse_sbat_section(char *section_base, size_t section_size,
@@ -398,6 +401,49 @@ preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes,
return false;
}
+/*
+ * This looks kind of weird, but it comes directly from the MS
+ * documentation:
+ * https://support.microsoft.com/en-us/topic/kb5027455-guidance-for-blocking-vulnerable-windows-boot-managers-522bb851-0a61-44ad-aa94-ad11119c5e91
+ */
+static UINT64
+ssp_ver_to_ull(UINT16 *ver)
+{
+ dprint("major: %u\n", ver[0]);
+ dprint("minor: %u\n", ver[1]);
+ dprint("rev: %u\n", ver[2]);
+ dprint("build: %u\n", ver[3]);
+
+ return ((UINT64)ver[0] << 48)
+ + ((UINT64)ver[1] << 32)
+ + ((UINT64)ver[2] << 16)
+ + ver[3];
+}
+
+static bool
+preserve_ssp_uefi_variable(UINT8 *ssp_applied, UINTN sspversize, UINT32 attributes,
+ uint8_t *ssp_candidate)
+{
+ UINT64 old, new;
+
+ if (ssp_applied == NULL || ssp_candidate == NULL)
+ return false;
+
+ if (sspversize != SSPVER_SIZE)
+ return false;
+
+ if (!check_sbat_var_attributes(attributes))
+ return false;
+
+ old = ssp_ver_to_ull((UINT16 *)ssp_applied);
+ new = ssp_ver_to_ull((UINT16 *)ssp_candidate);
+
+ if (new > old)
+ return false;
+ else
+ return true;
+}
+
static void
clear_sbat_policy()
{
@@ -422,7 +468,7 @@ set_sbat_uefi_variable(char *sbat_var_previous, char *sbat_var_latest)
char *sbat_var = NULL;
bool reset_sbat = false;
- if (sbat_policy == SBAT_POLICY_NOTREAD) {
+ if (sbat_policy == POLICY_NOTREAD) {
efi_status = get_variable_attr(SBAT_POLICY, &sbat_policyp,
&sbat_policysize, SHIM_LOCK_GUID,
&attributes);
@@ -477,9 +523,6 @@ set_sbat_uefi_variable(char *sbat_var_previous, char *sbat_var_latest)
SHIM_LOCK_GUID, &attributes);
/*
* Always set the SbatLevel UEFI variable if it fails to read.
- *
- * Don't try to set the SbatLevel UEFI variable if attributes match
- * and the signature matches.
*/
if (EFI_ERROR(efi_status)) {
dprint(L"SBAT read failed %r\n", efi_status);
@@ -532,7 +575,6 @@ set_sbat_uefi_variable(char *sbat_var_previous, char *sbat_var_latest)
}
FreePool(sbat);
-
return efi_status;
}
@@ -550,4 +592,161 @@ set_sbat_uefi_variable_internal(void)
return set_sbat_uefi_variable(sbat_var_previous, sbat_var_latest);
}
+static void
+clear_ssp_policy(void)
+{
+ EFI_STATUS efi_status = EFI_SUCCESS;
+
+ efi_status = del_variable(SSP_POLICY, SHIM_LOCK_GUID);
+ if (EFI_ERROR(efi_status))
+ console_error(L"Could not reset SSP Policy", efi_status);
+}
+
+static EFI_STATUS
+clear_ssp_uefi_variables(void)
+{
+ EFI_STATUS efi_status, rc = EFI_SUCCESS;
+
+ /* delete previous variable */
+ dprint("Deleting %s variable.\n", SSPVER_VAR_NAME);
+ efi_status = del_variable(SSPVER_VAR_NAME, SECUREBOOT_EFI_NAMESPACE_GUID);
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"%s variable delete failed %r\n", SSPVER_VAR_NAME,
+ efi_status);
+ rc = efi_status;
+ }
+ dprint("Deleting %s variable.\n", SSPSIG_VAR_NAME);
+ efi_status = del_variable(SSPSIG_VAR_NAME, SECUREBOOT_EFI_NAMESPACE_GUID);
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"%s variable delete failed %r\n", SSPSIG_VAR_NAME,
+ efi_status);
+ rc = efi_status;
+ }
+
+ return rc;
+}
+
+EFI_STATUS
+set_ssp_uefi_variable(uint8_t *ssp_ver_previous, uint8_t *ssp_sig_previous,
+ uint8_t *ssp_ver_latest, uint8_t *ssp_sig_latest)
+{
+ EFI_STATUS efi_status = EFI_SUCCESS;
+ UINT32 attributes = 0;
+
+ UINT8 *sspver = NULL;
+ UINT8 *policyp = NULL;
+ UINTN sspversize = 0;
+ UINTN policysize = 0;
+
+ uint8_t *ssp_ver = NULL;
+ uint8_t *ssp_sig = NULL;
+ bool reset_ssp = false;
+
+ _Static_assert(sizeof(SkuSiPolicyVersion) == SSPVER_SIZE,
+ "SkuSiPolicyVersion has unexpected size");
+ _Static_assert(sizeof(SkuSiPolicyUpdateSigners) == SSPSIG_SIZE,
+ "SkuSiPolicyUpdateSigners has unexpected size");
+
+ if (ssp_policy == POLICY_NOTREAD) {
+ efi_status = get_variable_attr(SSP_POLICY, &policyp,
+ &policysize, SHIM_LOCK_GUID,
+ &attributes);
+ if (!EFI_ERROR(efi_status)) {
+ ssp_policy = *policyp;
+ clear_ssp_policy();
+ }
+ }
+
+ if (EFI_ERROR(efi_status)) {
+ dprint("Default SSP policy: previous\n");
+ ssp_ver = ssp_ver_previous;
+ ssp_sig = ssp_sig_previous;
+ } else {
+ switch (ssp_policy) {
+ case POLICY_LATEST:
+ dprint("Custom SSP policy: latest\n");\
+ ssp_ver = ssp_ver_latest;
+ ssp_sig = ssp_sig_latest;
+ break;
+ case POLICY_PREVIOUS:
+ dprint("Custom SSP policy: previous\n");
+ ssp_ver = ssp_ver_previous;
+ ssp_sig = ssp_sig_previous;
+ break;
+ case POLICY_RESET:
+ if (secure_mode()) {
+ console_print(L"Cannot reset SSP policy: Secure Boot is enabled.\n");
+ ssp_ver = ssp_ver_previous;
+ ssp_sig = ssp_sig_previous;
+ } else {
+ dprint(L"Custom SSP policy: reset OK\n");
+ reset_ssp = true;
+ }
+ break;
+ default:
+ console_error(L"SSP policy state %llu is invalid",
+ EFI_INVALID_PARAMETER);
+ ssp_ver = ssp_ver_previous;
+ ssp_sig = ssp_sig_previous;
+ break;
+ }
+ }
+
+ if (!ssp_ver && !ssp_sig && !reset_ssp) {
+ dprint(L"No supplied SSP data, not setting variables\n");
+ return EFI_SUCCESS;
+ }
+
+ efi_status = get_variable_attr(SSPVER_VAR_NAME, &sspver, &sspversize,
+ SECUREBOOT_EFI_NAMESPACE_GUID, &attributes);
+ /*
+ * Since generally we want bootmgr to manage its own revocations,
+ * we are much less agressive trying to set those variables
+ */
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"SkuSiPolicyVersion read failed %r\n", efi_status);
+ } else if (preserve_ssp_uefi_variable(sspver, sspversize, attributes, ssp_ver)
+ && !reset_ssp) {
+ FreePool(sspver);
+
+ dprint(L"preserving %s variable it is %d bytes, attributes are 0x%08x\n",
+ SSPVER_VAR_NAME, sspversize, attributes);
+ return EFI_SUCCESS;
+ } else {
+ FreePool(sspver);
+
+ efi_status = clear_ssp_uefi_variables();
+ }
+
+ if (reset_ssp)
+ return efi_status;
+
+ /* set variable */
+ efi_status = set_variable(SSPVER_VAR_NAME, SECUREBOOT_EFI_NAMESPACE_GUID,
+ SSP_VAR_ATTRS, SSPVER_SIZE, ssp_ver);
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"%s variable writing failed %r\n", SSPVER_VAR_NAME,
+ efi_status);
+ return efi_status;
+ }
+ dprint("done setting %s variable.\n", SSPSIG_VAR_NAME);
+
+ efi_status = set_variable(SSPSIG_VAR_NAME, SECUREBOOT_EFI_NAMESPACE_GUID,
+ SSP_VAR_ATTRS, SSPSIG_SIZE, ssp_sig);
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"%s variable writing failed %r\n", SSPSIG_VAR_NAME,
+ efi_status);
+ return efi_status;
+ }
+ dprint("done setting %s variable.\n", SSPSIG_VAR_NAME);
+
+ return efi_status;
+}
+
+EFI_STATUS
+set_ssp_uefi_variable_internal(void)
+{
+ return set_ssp_uefi_variable(NULL, NULL, SkuSiPolicyVersion,
+ SkuSiPolicyUpdateSigners);
+}
// vim:fenc=utf-8:tw=75:noet
diff --git a/shim.c b/shim.c
index 12ce10d6..2ad1c063 100644
--- a/shim.c
+++ b/shim.c
@@ -1395,18 +1395,45 @@ uninstall_shim_protocols(void)
#endif
}
+static void
+check_section_helper(char *section_name, int len, void **pointer,
+ EFI_IMAGE_SECTION_HEADER *Section, void *data,
+ int datasize, size_t minsize)
+{
+ if (CompareMem(Section->Name, section_name, len) == 0) {
+ *pointer = ImageAddress(data, datasize, Section->PointerToRawData);
+ if (Section->SizeOfRawData < minsize) {
+ dprint(L"found and rejected %.*a bad size\n", len, section_name);
+ dprint(L"minsize: %d\n", minsize);
+ dprint(L"rawsize: %d\n", Section->SizeOfRawData);
+ return ;
+ }
+ if (!*pointer) {
+ return ;
+ }
+ dprint(L"found %.*a\n", len, section_name);
+ }
+}
+
+#define check_section(section_name, pointer, section, data, datasize, minsize) \
+ check_section_helper(section_name, sizeof(section_name) - 1, pointer, \
+ section, data, datasize, minsize)
+
EFI_STATUS
load_revocations_file(EFI_HANDLE image_handle, CHAR16 *PathName)
{
EFI_STATUS efi_status = EFI_SUCCESS;
PE_COFF_LOADER_IMAGE_CONTEXT context;
EFI_IMAGE_SECTION_HEADER *Section;
- void *pointer;
int datasize = 0;
void *data = NULL;
unsigned int i;
char *sbat_var_previous = NULL;
char *sbat_var_latest = NULL;
+ uint8_t *ssps_previous = NULL;
+ uint8_t *sspv_previous = NULL;
+ uint8_t *ssps_latest = NULL;
+ uint8_t *sspv_latest = NULL;
efi_status = read_image(image_handle, L"revocations.efi", &PathName,
&data, &datasize);
@@ -1422,25 +1449,19 @@ load_revocations_file(EFI_HANDLE image_handle, CHAR16 *PathName)
Section = context.FirstSection;
for (i = 0; i < context.NumberOfSections; i++, Section++) {
- dprint(L"checking section %a\n", (char *)Section->Name);
- if (CompareMem(Section->Name, ".sbatl", 6) == 0) {
- pointer = ImageAddress(data, datasize,
- Section->PointerToRawData);
- if (!pointer) {
- continue;
- }
- sbat_var_latest = (char *)pointer;
- dprint(L"found sbatl\n");
- }
- if (CompareMem(Section->Name, ".sbatp", 6) == 0) {
- pointer = ImageAddress(data, datasize,
- Section->PointerToRawData);
- if (!pointer) {
- continue;
- }
- sbat_var_previous = (char *)pointer;
- dprint(L"found sbatp\n");
- }
+ dprint(L"checking section \"%c%c%c%c%c%c%c%c\"\n", (char *)Section->Name);
+ check_section(".sbatp", (void **)&sbat_var_previous, Section,
+ data, datasize, sizeof(SBAT_VAR_ORIGINAL));
+ check_section(".sbatl", (void **)&sbat_var_latest, Section,
+ data, datasize, sizeof(SBAT_VAR_ORIGINAL));
+ check_section(".sspvp", (void **)&sspv_previous, Section,
+ data, datasize, SSPVER_SIZE);
+ check_section(".sspsp", (void **)&ssps_previous, Section,
+ data, datasize, SSPSIG_SIZE);
+ check_section(".sspvl", (void **)&sspv_latest, Section,
+ data, datasize, SSPVER_SIZE);
+ check_section(".sspsl", (void **)&ssps_latest, Section,
+ data, datasize, SSPSIG_SIZE);
}
if (sbat_var_latest && sbat_var_previous) {
@@ -1450,6 +1471,16 @@ load_revocations_file(EFI_HANDLE image_handle, CHAR16 *PathName)
} else {
dprint(L"no data for SBAT_LEVEL\n");
}
+
+ if ((sspv_previous && ssps_previous) || (sspv_latest && ssps_latest)) {
+ dprint(L"attempting to update SkuSiPolicy\n");
+ efi_status = set_ssp_uefi_variable(sspv_previous, ssps_previous,
+ sspv_latest, ssps_latest);
+
+ } else {
+ dprint(L"no data for SkuSiPolicy\n");
+ }
+
FreePool(data);
return efi_status;
}
@@ -1814,6 +1845,12 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
dprint(L"%s variable initialization failed: %r\n",
SBAT_VAR_NAME, efi_status);
}
+ efi_status = set_ssp_uefi_variable_internal();
+ if (EFI_ERROR(efi_status)) {
+ dprint(L"%s variable initialization failed: %r\n",
+ SSPVER_VAR_NAME, efi_status);
+ }
+ dprint(L"%s variable initialization done\n", SSPVER_VAR_NAME);
if (secure_mode()) {
char *sbat_start = (char *)&_sbat;
diff --git a/shim.h b/shim.h
index 652be45c..5791a031 100644
--- a/shim.h
+++ b/shim.h
@@ -180,6 +180,7 @@
#include "include/replacements.h"
#include "include/sbat.h"
#include "include/sbat_var_defs.h"
+#include "include/ssp.h"
#if defined(OVERRIDE_SECURITY_POLICY)
#include "include/security_policy.h"
#endif