From 701f6bf05d85080c670054b8a66655b4e36928a3 Mon Sep 17 00:00:00 2001 From: Yifan Liu Date: Thu, 27 May 2021 11:26:19 +0800 Subject: [PATCH] misc: efi-stub: Set MOR bit before jumping to hypervisor This patch sets the MemoryOverwriteRequestControl (MORCtrl for short) EFI variable before jumping to hypervisor. Setting variable MemoryOverwriteRequestControlLock (MORCtrlLock for short) can also be enabled by manually adding -DMORCTRL_LOCK_ENABLED to CFLAGS. Setting MORCtrl indicates to the platform firmware that memory be cleared upon system reset. Setting MORCtrlLock for the first time will render both MORCtrl and MORCtrlLock to read-only, until next reset. Tracked-On: #6097 Signed-off-by: Yifan Liu --- misc/efi-stub/boot.c | 85 ++++++++++++++++++++++++++++++++++++++++ misc/efi-stub/boot.h | 7 ++++ misc/efi-stub/efilinux.h | 11 ++++++ 3 files changed, 103 insertions(+) diff --git a/misc/efi-stub/boot.c b/misc/efi-stub/boot.c index b587e168c..e47ea5d60 100644 --- a/misc/efi-stub/boot.c +++ b/misc/efi-stub/boot.c @@ -42,6 +42,7 @@ EFI_SYSTEM_TABLE *sys_table; EFI_BOOT_SERVICES *boot; +EFI_RUNTIME_SERVICES *runtime; HV_LOADER hvld; static EFI_STATUS @@ -103,6 +104,84 @@ out: return err; } +static EFI_STATUS +set_mor_bit() +{ + EFI_STATUS err; + UINT32 attrs; + UINTN size = 1; + uint8_t data = 0; + EFI_GUID efi_var_morctl_guid = EFI_VAR_MORCTL_GUID; +#ifdef MORCTRL_LOCK_ENABLED + EFI_GUID efi_var_morctllock_guid = EFI_VAR_MORCTLLOCK_GUID; +#endif + + /* + * Per TCG Platform Reset Attack Mitigation Spec 1.10 rev 17, Chp 4.1 + * MORCtrl is a 1-byte unsigned number and should be created by the firmware. + */ + err = get_variable(EFI_VAR_MORCTL_NAME, &efi_var_morctl_guid, &attrs, &size, (void *)&data); + if (err != EFI_SUCCESS) { + if (err == EFI_BUFFER_TOO_SMALL) { + Print(L"Wrong MORCtrl variable size: 0x%x byte, should be 1 byte\n", size); + } else if (err == EFI_NOT_FOUND) { + Print(L"Warning: MORCtrl variable not found\n"); + } + + goto out; + } + + if (attrs != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) { + Print(L"Wrong MORCtrl attributes: 0x%x\n", attrs); + goto out; + } + + /* Bit 0 set: Firmware MUST set the MOR bit */ + /* Bit 4 cleared: Firmware MAY autodetect a clean shutdown of the Static RTM OS. */ + data = 0x1; + + err = set_variable(EFI_VAR_MORCTL_NAME, &efi_var_morctl_guid, attrs, size, &data); + if (err != EFI_SUCCESS) + goto out; + +#ifdef MORCTRL_LOCK_ENABLED + /* + * MORCTRL_LOCK_ENABLED is NOT part of the board configuration. + * To activate MORCTRL_LOCK_ENABLED, manually add -DMORCTRL_LOCK_ENABLED to the CFLAGS. + */ + + /* Lock MORCtrl with MORCtrlLock */ + size = 1; + err = get_variable(EFI_VAR_MORCTLLOCK_NAME, &efi_var_morctllock_guid, &attrs, &size, (void *)&data); + if (err != EFI_SUCCESS) + goto out; + + if (attrs != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) { + Print(L"Wrong MORCtrlLock attributes: 0x%x\n", attrs); + goto out; + } + + if (data == 0x1 || data == 0x2) { + Print(L"Warning: MORCtrl already locked. No locking operation performed.\n"); + goto out; + } + + /* + * Input value 1, size 1: Lock without key + * Try to lock MemoryOverwriteRequestControlLock and MemoryOverwriteRequestControl + * If success, MORCtrl and MORCtrlLock will be read-only until next boot, and reboot + * is the only way to unlock these variables. + */ + data = 0x1; + size = 0x1; + err = set_variable(EFI_VAR_MORCTLLOCK_NAME, &efi_var_morctllock_guid, attrs, size, (void *)&data); + if (err != EFI_SUCCESS) + goto out; +#endif +out: + return err; +} + static EFI_STATUS terminate_boot_services(EFI_HANDLE image, struct efi_memmap_info *mmap_info) { @@ -518,6 +597,11 @@ run_acrn(EFI_HANDLE image, HV_LOADER hvld) struct efi_memmap_info memmapinfo; struct multiboot_info *mbi; + err = set_mor_bit(); + /* If MOR not supported, emit a warning and proceed */ + if (err != EFI_SUCCESS && err != EFI_NOT_FOUND) + goto out; + #ifdef CONFIG_MULTIBOOT2 /* MB2 has no fixed mbinfo layout. The mbi as output will * NOT conform to the layout of struct multiboot_info. @@ -557,6 +641,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table) InitializeLib(image, _table); sys_table = _table; boot = sys_table->BootServices; + runtime = sys_table->RuntimeServices; if (CheckCrc(sys_table->Hdr.HeaderSize, &sys_table->Hdr) != TRUE) return EFI_LOAD_ERROR; diff --git a/misc/efi-stub/boot.h b/misc/efi-stub/boot.h index 43b8fc2a3..665f49f40 100644 --- a/misc/efi-stub/boot.h +++ b/misc/efi-stub/boot.h @@ -59,6 +59,13 @@ #define UEFI_BOOT_LOADER_NAME "ACRN UEFI loader" +#define EFI_VAR_MORCTL_NAME L"MemoryOverwriteRequestControl" +#define EFI_VAR_MORCTL_GUID \ + { 0xe20939be, 0x32d4, 0x41be, { 0xa1, 0x50, 0x89, 0x7f, 0x85, 0xd4, 0x98, 0x29 } } +#define EFI_VAR_MORCTLLOCK_NAME L"MemoryOverwriteRequestControlLock" +#define EFI_VAR_MORCTLLOCK_GUID \ + { 0xBB983CCF, 0x151D, 0x40E1, { 0xA0, 0x7B, 0x4A, 0x17, 0xBE, 0x16, 0x82, 0x92 } } + #define ALIGN_UP(addr, align) \ (((addr) + (typeof (addr)) (align) - 1) & ~((typeof (addr)) (align) - 1)) diff --git a/misc/efi-stub/efilinux.h b/misc/efi-stub/efilinux.h index 7f0d5f211..14b13fd97 100644 --- a/misc/efi-stub/efilinux.h +++ b/misc/efi-stub/efilinux.h @@ -51,6 +51,7 @@ extern EFI_SYSTEM_TABLE *sys_table; extern EFI_BOOT_SERVICES *boot; +extern EFI_RUNTIME_SERVICES *runtime; extern EFI_STATUS emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align, @@ -223,6 +224,16 @@ static inline EFI_STATUS emalloc_fixed_addr(EFI_PHYSICAL_ADDRESS *addr, EFI_SIZE_TO_PAGES(size), addr); } +static inline EFI_STATUS get_variable(const CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, void *data) +{ + return uefi_call_wrapper(runtime->GetVariable, 5, name, guid, attrs, size, data); +} + +static inline EFI_STATUS set_variable(const CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, void *data) +{ + return uefi_call_wrapper(runtime->SetVariable, 5, name, guid, attrs, size, data); +} + /** * exit - Terminate a loaded EFI image * @image: firmware-allocated handle that identifies the image