From 46adaaf3cf7cc853790343dd7f14a42c80078b28 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Sun, 14 Feb 2021 14:48:10 -0500 Subject: includes: include all gnu-efi includes at one place. Signed-off-by: Peter Jones --- include/guid.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/guid.h') diff --git a/include/guid.h b/include/guid.h index 114e8707..07a19a91 100644 --- a/include/guid.h +++ b/include/guid.h @@ -3,8 +3,6 @@ #ifndef SHIM_GUID_H #define SHIM_GUID_H -#include - extern EFI_GUID BDS_GUID; extern EFI_GUID GV_GUID; extern EFI_GUID SIG_DB; -- cgit v1.2.3 From 226fee25ffcbd29988399ba080c7706eb1d52251 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 2 Dec 2021 18:29:50 -0500 Subject: PE Loader: support and require NX This adds support in our PE loader for NX support utilizing the EFI_MEMORY_ATTRIBUTE protocol. Specifically, it changes the loader such that: - binaries without the EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT flag set in the Optional Header are rejected as EFI_UNSUPPORTED - binaries with non-discardable sections that have both the EFI_SCN_MEM_WRITE and EFI_SCN_MEM_EXECUTE flags set are rejected as EFI_UNSUPPORTED - if the EFI_MEMORY_ATTRIBUTE protocol is installed, then: - sections without the EFI_SCN_MEM_READ flag set will be marked with EFI_MEMORY_RP - sections without the EFI_SCN_MEM_WRITE flag set will be marked with EFI_MEMORY_RO - sections without the EFI_SCN_MEM_EXECUTE flag set will be marked with EFI_MEMORY_XP Signed-off-by: Peter Jones --- include/guid.h | 2 +- lib/guid.c | 2 +- pe.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shim.h | 4 ++ 4 files changed, 209 insertions(+), 2 deletions(-) (limited to 'include/guid.h') diff --git a/include/guid.h b/include/guid.h index 07a19a91..d9910ff1 100644 --- a/include/guid.h +++ b/include/guid.h @@ -33,8 +33,8 @@ extern EFI_GUID EFI_SECURE_BOOT_DB_GUID; extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID; extern EFI_GUID SECURITY_PROTOCOL_GUID; 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; #endif /* SHIM_GUID_H */ diff --git a/lib/guid.c b/lib/guid.c index 143e0bbd..e100c92e 100644 --- a/lib/guid.c +++ b/lib/guid.c @@ -32,6 +32,6 @@ EFI_GUID EFI_SECURE_BOOT_DB_GUID = { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; - +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} }; diff --git a/pe.c b/pe.c index 535d463a..9fa6fffd 100644 --- a/pe.c +++ b/pe.c @@ -696,6 +696,7 @@ read_header(void *data, unsigned int datasize, EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; unsigned long FileAlignment = 0; + UINT16 DllFlags; if (datasize < sizeof (PEHdr->Pe32)) { perror(L"Invalid image\n"); @@ -790,13 +791,20 @@ read_header(void *data, unsigned int datasize, context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics; } else { context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics; } + if (!(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) { + perror(L"Image does not support NX\n"); + return EFI_UNSUPPORTED; + } + context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)); if (context->ImageSize < context->SizeOfHeaders) { @@ -878,6 +886,139 @@ err: return efi_status; } +static inline uint64_t +shim_mem_attrs_to_uefi_mem_attrs (uint64_t attrs) +{ + uint64_t ret = EFI_MEMORY_RP | + EFI_MEMORY_RO | + EFI_MEMORY_XP; + + if (attrs & MEM_ATTR_R) + ret &= ~EFI_MEMORY_RP; + + if (attrs & MEM_ATTR_W) + ret &= ~EFI_MEMORY_RO; + + if (attrs & MEM_ATTR_X) + ret &= ~EFI_MEMORY_XP; + + return ret; +} + +static inline uint64_t +uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs) +{ + uint64_t ret = MEM_ATTR_R | + MEM_ATTR_W | + MEM_ATTR_X; + + if (attrs & EFI_MEMORY_RP) + ret &= ~MEM_ATTR_R; + + if (attrs & EFI_MEMORY_RO) + ret &= ~MEM_ATTR_W; + + if (attrs & EFI_MEMORY_XP) + ret &= ~MEM_ATTR_X; + + return ret; +} + +static EFI_STATUS +get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs) +{ + EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; + EFI_PHYSICAL_ADDRESS physaddr = addr; + EFI_STATUS efi_status; + + efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, + (VOID **)&proto); + if (EFI_ERROR(efi_status) || !proto) + return efi_status; + + if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) { + dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n", + __func__, (unsigned long long)physaddr, + (unsigned long long)(physaddr+size-1), + attrs); + return EFI_SUCCESS; + } + + efi_status = proto->GetMemoryAttributes(proto, physaddr, size, attrs); + *attrs = uefi_mem_attrs_to_shim_mem_attrs (*attrs); + + return efi_status; +} + +static EFI_STATUS +update_mem_attrs(uintptr_t addr, uint64_t size, + uint64_t set_attrs, uint64_t clear_attrs) +{ + EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; + EFI_PHYSICAL_ADDRESS physaddr = addr; + EFI_STATUS efi_status, ret; + uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; + + efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, + (VOID **)&proto); + if (EFI_ERROR(efi_status) || !proto) + return efi_status; + + efi_status = get_mem_attrs (addr, size, &before); + if (EFI_ERROR(efi_status)) + dprint(L"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n", + (unsigned long long)addr, (unsigned long long)size, + &before, efi_status); + + if (physaddr & 0xfff || size & 0xfff || size == 0) { + dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n", + __func__, (unsigned long long)physaddr, + (unsigned long long)(physaddr + size - 1), + (unsigned long long)size, + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : ""); + return 0; + } + + uefi_set_attrs = shim_mem_attrs_to_uefi_mem_attrs (set_attrs); + dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); + uefi_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs (clear_attrs); + dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); + efi_status = EFI_SUCCESS; + if (uefi_set_attrs) + efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs); + if (!EFI_ERROR(efi_status) && uefi_clear_attrs) + efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs); + ret = efi_status; + + efi_status = get_mem_attrs (addr, size, &after); + if (EFI_ERROR(efi_status)) + dprint(L"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n", + (unsigned long long)addr, (unsigned long long)size, + &after, efi_status); + + dprint(L"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n", + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : "", + (unsigned long long)addr, (unsigned long long)(addr + size - 1), + (before & MEM_ATTR_R) ? 'r' : '-', + (before & MEM_ATTR_W) ? 'w' : '-', + (before & MEM_ATTR_X) ? 'x' : '-', + (after & MEM_ATTR_R) ? 'r' : '-', + (after & MEM_ATTR_W) ? 'w' : '-', + (after & MEM_ATTR_X) ? 'x' : '-'); + + return ret; +} + EFI_STATUS verify_image(void *data, unsigned int datasize, EFI_LOADED_IMAGE *li, PE_COFF_LOADER_IMAGE_CONTEXT *context) @@ -1013,6 +1154,11 @@ handle_image (void *data, unsigned int datasize, } buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment); + dprint(L"Loading 0x%llx bytes at 0x%llx\n", + (unsigned long long)context.ImageSize, + (unsigned long long)(uintptr_t)buffer); + update_mem_attrs((uintptr_t)buffer, alloc_size, MEM_ATTR_R|MEM_ATTR_W, + MEM_ATTR_X); CopyMem(buffer, data, context.SizeOfHeaders); @@ -1049,6 +1195,19 @@ handle_image (void *data, unsigned int datasize, !Section->Misc.VirtualSize) continue; + /* + * Skip sections that aren't marked readable. + */ + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ)) + continue; + + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && + (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) && + (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE)) { + perror(L"Section %d is writable and executable\n", i); + return EFI_UNSUPPORTED; + } + base = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress); end = ImageAddress (buffer, context.ImageSize, @@ -1159,6 +1318,50 @@ handle_image (void *data, unsigned int datasize, } } + /* + * Now set the page permissions appropriately. + */ + Section = context.FirstSection; + for (i = 0; i < context.NumberOfSections; i++, Section++) { + uint64_t set_attrs = MEM_ATTR_R; + uint64_t clear_attrs = MEM_ATTR_W|MEM_ATTR_X; + uintptr_t addr; + uint64_t length; + + /* + * Skip discardable sections with zero size + */ + if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && + !Section->Misc.VirtualSize) + continue; + + /* + * Skip sections that aren't marked readable. + */ + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ)) + continue; + + base = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress); + end = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress + + Section->Misc.VirtualSize - 1); + + addr = (uintptr_t)base; + length = (uintptr_t)end - (uintptr_t)base + 1; + + if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) { + set_attrs |= MEM_ATTR_W; + clear_attrs &= ~MEM_ATTR_W; + } + if (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) { + set_attrs |= MEM_ATTR_X; + clear_attrs &= ~MEM_ATTR_X; + } + update_mem_attrs(addr, length, set_attrs, clear_attrs); + } + + /* * grub needs to know its location and size in memory, so fix up * the loaded image protocol values diff --git a/shim.h b/shim.h index 703c1145..dc3cda73 100644 --- a/shim.h +++ b/shim.h @@ -195,6 +195,10 @@ #include "Cryptlib/Include/OpenSslSupport.h" #endif +#define MEM_ATTR_R 4 +#define MEM_ATTR_W 2 +#define MEM_ATTR_X 1 + INTERFACE_DECL(_SHIM_LOCK); typedef -- cgit v1.2.3 From 4fd484e4c29364b4fdf4d043556fa0a210c5fdfc Mon Sep 17 00:00:00 2001 From: Lu Ken Date: Sun, 22 May 2022 16:02:20 +0800 Subject: Enable TDX measurement to RTMR register Intel Trust Domain Extensions (Intel TDX) extends Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption (MK-TME) with a new kind of virtual machine guest called a Trust Domain(TD)[1]. A TD runs in a CPU mode that is designed to protect the confidentiality of its memory contents and its CPU state from any other software, including the hosting Virtual Machine Monitor (VMM). Trust Domain Virtual Firmware (TDVF) is required to provide Intel TDX implementation and service for EFI_CC_MEASUREMENT_PROTOCOL[2]. The bugzilla for TDVF is at https://bugzilla.tianocore.org/show_bug.cgi?id=3625. To support CC measurement/attestation with Intel TDX technology, these 4 RTMR registers will be extended by TDX service like TPM/TPM2 PCR: - RTMR[0] for TDVF configuration - RTMR[1] for the TD OS loader and kernel - RTMR[2] for the OS application - RTMR[3] reserved for special usage only Add a TDX Implementation for CC Measurement protocol along with TPM/TPM2 protocol. References: [1] https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-whitepaper-v4.pdf [2] https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf [3] https://software.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf Signed-off-by: Lu Ken [rharwood: style pass on code and commit message] Signed-off-by: Robbie Harwood --- include/cc.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/guid.h | 1 + lib/guid.c | 1 + shim.h | 1 + tpm.c | 48 +++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 include/cc.h (limited to 'include/guid.h') diff --git a/include/cc.h b/include/cc.h new file mode 100644 index 00000000..8b127208 --- /dev/null +++ b/include/cc.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent + +#ifndef SHIM_CC_H +#define SHIM_CC_H + +typedef struct { + uint8_t Major; + uint8_t Minor; +} EFI_CC_VERSION; + +#define EFI_CC_TYPE_NONE 0 +#define EFI_CC_TYPE_SEV 1 +#define EFI_CC_TYPE_TDX 2 + +typedef struct { + uint8_t Type; + uint8_t SubType; +} EFI_CC_TYPE; + +typedef uint32_t EFI_CC_EVENT_LOG_BITMAP; +typedef uint32_t EFI_CC_EVENT_LOG_FORMAT; +typedef uint32_t EFI_CC_EVENT_ALGORITHM_BITMAP; +typedef uint32_t EFI_CC_MR_INDEX; + +#define TDX_MR_INDEX_MRTD 0 +#define TDX_MR_INDEX_RTMR0 1 +#define TDX_MR_INDEX_RTMR1 2 +#define TDX_MR_INDEX_RTMR2 3 +#define TDX_MR_INDEX_RTMR3 4 + +#define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 +#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 +#define EFI_CC_EVENT_HEADER_VERSION 1 + +typedef struct tdEFI_CC_EVENT_HEADER { + uint32_t HeaderSize; + uint16_t HeaderVersion; + EFI_CC_MR_INDEX MrIndex; + uint32_t EventType; +} __attribute__((packed)) EFI_CC_EVENT_HEADER; + +typedef struct tdEFI_CC_EVENT { + uint32_t Size; + EFI_CC_EVENT_HEADER Header; + uint8_t Event[1]; +} __attribute__((packed)) EFI_CC_EVENT; + +typedef struct tdEFI_CC_BOOT_SERVICE_CAPABILITY { + uint8_t Size; + EFI_CC_VERSION StructureVersion; + EFI_CC_VERSION ProtocolVersion; + EFI_CC_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; + EFI_CC_EVENT_LOG_BITMAP SupportedEventLogs; + EFI_CC_TYPE CcType; +} EFI_CC_BOOT_SERVICE_CAPABILITY; + +struct efi_cc_protocol +{ + EFI_STATUS (EFIAPI *get_capability) ( + struct efi_cc_protocol *this, + EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability); + EFI_STATUS (EFIAPI *get_event_log) ( + struct efi_cc_protocol *this, + EFI_CC_EVENT_LOG_FORMAT EventLogFormat, + EFI_PHYSICAL_ADDRESS *EventLogLocation, + EFI_PHYSICAL_ADDRESS *EventLogLastEntry, + BOOLEAN *EventLogTruncated); + EFI_STATUS (EFIAPI *hash_log_extend_event) ( + struct efi_cc_protocol *this, + uint64_t Flags, + EFI_PHYSICAL_ADDRESS DataToHash, + uint64_t DataToHashLen, + EFI_CC_EVENT *EfiCcEvent); + EFI_STATUS (EFIAPI *map_pcr_to_mr_index) ( + struct efi_cc_protocol *this, + uint32_t PcrIndex, + EFI_CC_MR_INDEX *MrIndex); +}; + +typedef struct efi_cc_protocol efi_cc_protocol_t; + +#define EFI_CC_FLAG_PE_COFF_IMAGE 0x0000000000000010 + +#endif /* SHIM_CC_H */ +// vim:fenc=utf-8:tw=75 diff --git a/include/guid.h b/include/guid.h index d9910ff1..dad63f0f 100644 --- a/include/guid.h +++ b/include/guid.h @@ -29,6 +29,7 @@ extern EFI_GUID EFI_IP6_CONFIG_GUID; extern EFI_GUID EFI_LOADED_IMAGE_GUID; extern EFI_GUID EFI_TPM_GUID; extern EFI_GUID EFI_TPM2_GUID; +extern EFI_GUID EFI_CC_MEASUREMENT_PROTOCOL_GUID; extern EFI_GUID EFI_SECURE_BOOT_DB_GUID; extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID; extern EFI_GUID SECURITY_PROTOCOL_GUID; diff --git a/lib/guid.c b/lib/guid.c index e100c92e..904629eb 100644 --- a/lib/guid.c +++ b/lib/guid.c @@ -28,6 +28,7 @@ EFI_GUID EFI_IP6_CONFIG_GUID = { 0x937fe521, 0x95ae, 0x4d1a, {0x89, 0x29, 0x48, EFI_GUID EFI_LOADED_IMAGE_GUID = EFI_LOADED_IMAGE_PROTOCOL_GUID; EFI_GUID EFI_TPM_GUID = { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd } }; EFI_GUID EFI_TPM2_GUID = { 0x607f766c, 0x7455, 0x42be, {0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f } }; +EFI_GUID EFI_CC_MEASUREMENT_PROTOCOL_GUID = { 0x96751a3d, 0x72f4, 0x41a6, {0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } }; EFI_GUID EFI_SECURE_BOOT_DB_GUID = { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } }; EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; diff --git a/shim.h b/shim.h index 7e9d10eb..14824c67 100644 --- a/shim.h +++ b/shim.h @@ -186,6 +186,7 @@ #include "include/simple_file.h" #include "include/str.h" #include "include/tpm.h" +#include "include/cc.h" #include "include/ucs2.h" #include "include/variables.h" #include "include/hexdump.h" diff --git a/tpm.c b/tpm.c index 41f36651..388f8d12 100644 --- a/tpm.c +++ b/tpm.c @@ -108,6 +108,45 @@ static EFI_STATUS tpm_locate_protocol(efi_tpm_protocol_t **tpm, return EFI_NOT_FOUND; } +static EFI_STATUS cc_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size, + UINT8 pcr, const CHAR8 *log, UINTN logsize, + UINT32 type, BOOLEAN is_pe_image) +{ + EFI_STATUS efi_status; + EFI_CC_EVENT *event; + efi_cc_protocol_t *cc; + EFI_CC_MR_INDEX mr; + uint64_t flags = is_pe_image ? EFI_CC_FLAG_PE_COFF_IMAGE : 0; + + efi_status = LibLocateProtocol(&EFI_CC_MEASUREMENT_PROTOCOL_GUID, + (VOID **)&cc); + if (EFI_ERROR(efi_status) || !cc) + return EFI_SUCCESS; + + efi_status = cc->map_pcr_to_mr_index(cc, pcr, &mr); + if (EFI_ERROR(efi_status)) + return EFI_NOT_FOUND; + + UINTN event_size = sizeof(*event) - sizeof(event->Event) + logsize; + + event = AllocatePool(event_size); + if (!event) { + perror(L"Unable to allocate event structure\n"); + return EFI_OUT_OF_RESOURCES; + } + + event->Header.HeaderSize = sizeof(EFI_CC_EVENT_HEADER); + event->Header.HeaderVersion = EFI_CC_EVENT_HEADER_VERSION; + event->Header.MrIndex = mr; + event->Header.EventType = type; + event->Size = event_size; + CopyMem(event->Event, (VOID *)log, logsize); + efi_status = cc->hash_log_extend_event(cc, flags, buf, (UINT64)size, + event); + FreePool(event); + return efi_status; +} + static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr, const CHAR8 *log, UINTN logsize, UINT32 type, CHAR8 *hash) @@ -118,6 +157,15 @@ static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size, BOOLEAN old_caps; EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; + /* CC guest like TDX or SEV will measure the buffer and log the event, + extend the result into a specific CC MR like TCG's PCR. It could + coexists with TCG's TPM 1.2 and TPM 2. + */ + efi_status = cc_log_event_raw(buf, size, pcr, log, logsize, type, + (hash != NULL)); + if (EFI_ERROR(efi_status)) + return efi_status; + efi_status = tpm_locate_protocol(&tpm, &tpm2, &old_caps, &caps); if (EFI_ERROR(efi_status)) { #ifdef REQUIRE_TPM -- cgit v1.2.3 From 7dfb6871b8a54710d9e9d8d56146e7c083d2e6a8 Mon Sep 17 00:00:00 2001 From: Jan Setje-Eilers Date: Fri, 28 Apr 2023 19:54:14 -0700 Subject: 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 --- include/guid.h | 1 + include/sbat.h | 10 ++- include/sbat_var_defs.h | 1 - include/ssp.h | 14 ++++ include/ssp_var_defs.h | 19 +++++ lib/guid.c | 1 + sbat.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++-- shim.c | 77 +++++++++++++----- shim.h | 1 + 9 files changed, 304 insertions(+), 31 deletions(-) create mode 100644 include/ssp.h create mode 100644 include/ssp_var_defs.h (limited to 'include/guid.h') 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 -- cgit v1.2.3 From bb114a3b92a96875dc71e5e4925bedba5c02f958 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 29 Jun 2023 17:58:18 +0200 Subject: Implement shim image load protocol Define a new protocol for loading and starting images, encapsulating shim's PE loading facilities and verification/authentication against the same set of certificates that shim_lock::verify() authenticates against. This removes the need for loaders like GRUB to implement their own PE loader in order to be able to invoke loaded images as PE applications, rather than implementing a bespoke OS dependent handover protocol (e.g., invoke Linux via its EFI stub) Signed-off-by: Ard Biesheuvel --- include/guid.h | 2 ++ lib/guid.c | 2 ++ replacements.c | 11 ++++++ shim.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- shim.h | 18 ++++++++++ 5 files changed, 134 insertions(+), 6 deletions(-) (limited to 'include/guid.h') diff --git a/include/guid.h b/include/guid.h index 898c4fad..e32dfc07 100644 --- a/include/guid.h +++ b/include/guid.h @@ -36,6 +36,8 @@ extern EFI_GUID SECURITY_PROTOCOL_GUID; extern EFI_GUID SECURITY2_PROTOCOL_GUID; extern EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; extern EFI_GUID SHIM_LOCK_GUID; +extern EFI_GUID SHIM_IMAGE_LOADER_GUID; +extern EFI_GUID SHIM_LOADED_IMAGE_GUID; extern EFI_GUID MOK_VARIABLE_STORE; extern EFI_GUID SECUREBOOT_EFI_NAMESPACE_GUID; diff --git a/lib/guid.c b/lib/guid.c index 6e92cea3..1dc90ca9 100644 --- a/lib/guid.c +++ b/lib/guid.c @@ -35,5 +35,7 @@ EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; 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 SHIM_IMAGE_LOADER_GUID = {0x1f492041, 0xfadb, 0x4e59, {0x9e, 0x57, 0x7c, 0xaf, 0xe7, 0x3a, 0x55, 0xab } }; +EFI_GUID SHIM_LOADED_IMAGE_GUID = {0x6e6baeb8, 0x7108, 0x4179, {0x94, 0x9d, 0xa3, 0x49, 0x34, 0x15, 0xec, 0x97 } }; 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/replacements.c b/replacements.c index 469e73aa..d840616f 100644 --- a/replacements.c +++ b/replacements.c @@ -148,6 +148,17 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus, UINTN ExitDataSize, CHAR16 *ExitData) { EFI_STATUS efi_status; + SHIM_LOADED_IMAGE *image; + + efi_status = BS->HandleProtocol(ImageHandle, &SHIM_LOADED_IMAGE_GUID, + (void **)&image); + if (!EFI_ERROR(efi_status)) { + image->exit_status = ExitStatus; + image->exit_data_size = ExitDataSize; + image->exit_data = ExitData; + + longjmp(image->longjmp_buf, 1); + } shim_fini(); diff --git a/shim.c b/shim.c index 14355d27..60b5e720 100644 --- a/shim.c +++ b/shim.c @@ -1314,6 +1314,7 @@ init_openssl(void) } static SHIM_LOCK shim_lock_interface; +static SHIM_IMAGE_LOADER shim_image_loader_interface; static EFI_HANDLE shim_lock_handle; EFI_STATUS @@ -1346,10 +1347,12 @@ install_shim_protocols(void) /* * Install the protocol */ - efi_status = BS->InstallProtocolInterface(&shim_lock_handle, - &SHIM_LOCK_GUID, - EFI_NATIVE_INTERFACE, - &shim_lock_interface); + efi_status = BS->InstallMultipleProtocolInterfaces(&shim_lock_handle, + &SHIM_LOCK_GUID, + &shim_lock_interface, + &SHIM_IMAGE_LOADER_GUID, + &shim_image_loader_interface, + NULL); if (EFI_ERROR(efi_status)) { console_error(L"Could not install security protocol", efi_status); @@ -1375,8 +1378,12 @@ uninstall_shim_protocols(void) /* * If we're back here then clean everything up before exiting */ - BS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID, - &shim_lock_interface); + BS->UninstallMultipleProtocolInterfaces(shim_lock_handle, + &SHIM_LOCK_GUID, + &shim_lock_interface, + &SHIM_IMAGE_LOADER_GUID, + &shim_image_loader_interface, + NULL); if (!secure_mode()) return; @@ -1908,6 +1915,91 @@ devel_egress(devel_egress_action action UNUSED) #endif } +static EFI_STATUS EFIAPI +shim_load_image(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH *FilePath, IN VOID *SourceBuffer, + IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle) +{ + SHIM_LOADED_IMAGE *image; + EFI_STATUS efi_status; + + (void)FilePath; + + if (BootPolicy || !SourceBuffer || !SourceSize) + return EFI_UNSUPPORTED; + + image = AllocatePool(sizeof(*image)); + if (!image) + return EFI_OUT_OF_RESOURCES; + + SetMem(image, sizeof(*image), 0); + + image->li.Revision = 0x1000; + image->li.ParentHandle = ParentImageHandle; + image->li.SystemTable = systab; + + efi_status = handle_image(SourceBuffer, SourceSize, &image->li, + &image->entry_point, &image->alloc_address, + &image->alloc_pages); + if (EFI_ERROR(efi_status)) + goto free_image; + + *ImageHandle = NULL; + efi_status = BS->InstallMultipleProtocolInterfaces(ImageHandle, + &SHIM_LOADED_IMAGE_GUID, image, + &EFI_LOADED_IMAGE_GUID, &image->li, + NULL); + if (EFI_ERROR(efi_status)) + goto free_alloc; + + return EFI_SUCCESS; + +free_alloc: + BS->FreePages(image->alloc_address, image->alloc_pages); +free_image: + FreePool(image); + return efi_status; +} + +static EFI_STATUS EFIAPI +shim_start_image(IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL) +{ + SHIM_LOADED_IMAGE *image; + EFI_STATUS efi_status; + + efi_status = BS->HandleProtocol(ImageHandle, &SHIM_LOADED_IMAGE_GUID, + (void **)&image); + if (EFI_ERROR(efi_status) || image->started) + return EFI_INVALID_PARAMETER; + + if (!setjmp(image->longjmp_buf)) { + image->started = true; + efi_status = + image->entry_point(ImageHandle, image->li.SystemTable); + } else { + if (ExitData) { + *ExitDataSize = image->exit_data_size; + *ExitData = (CHAR16 *)image->exit_data; + } + efi_status = image->exit_status; + } + + // + // We only support EFI applications, so we can unload and free the + // image unconditionally. + // + BS->UninstallMultipleProtocolInterfaces(ImageHandle, + &EFI_LOADED_IMAGE_GUID, image, + &SHIM_LOADED_IMAGE_GUID, &image->li, + NULL); + + BS->FreePages(image->alloc_address, image->alloc_pages); + FreePool(image); + + return efi_status; +} + EFI_STATUS efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) { @@ -1951,6 +2043,9 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) shim_lock_interface.Hash = shim_hash; shim_lock_interface.Context = shim_read_header; + shim_image_loader_interface.LoadImage = shim_load_image; + shim_image_loader_interface.StartImage = shim_start_image; + systab = passed_systab; image_handle = global_image_handle = passed_image_handle; diff --git a/shim.h b/shim.h index 43fcb191..704e34ea 100644 --- a/shim.h +++ b/shim.h @@ -55,6 +55,7 @@ #ifndef SHIM_UNIT_TEST #include #include +#include #undef uefi_call_wrapper #include #include @@ -237,6 +238,11 @@ typedef struct _SHIM_LOCK { EFI_SHIM_LOCK_CONTEXT Context; } SHIM_LOCK; +typedef struct _SHIM_IMAGE_LOADER { + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; +} SHIM_IMAGE_LOADER; + extern EFI_STATUS shim_init(void); extern void shim_fini(void); extern EFI_STATUS EFIAPI LogError_(const char *file, int line, const char *func, @@ -326,4 +332,16 @@ verify_buffer (char *data, int datasize, char *translate_slashes(char *out, const char *str); +typedef struct { + EFI_LOADED_IMAGE li; + EFI_IMAGE_ENTRY_POINT entry_point; + EFI_PHYSICAL_ADDRESS alloc_address; + UINTN alloc_pages; + EFI_STATUS exit_status; + CONST CHAR16 *exit_data; + UINTN exit_data_size; + jmp_buf longjmp_buf; + BOOLEAN started; +} SHIM_LOADED_IMAGE; + #endif /* SHIM_H_ */ -- cgit v1.2.3 From c41b1f066b9f279b70d933095f277eddbd7c6433 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 27 Jun 2024 15:19:38 -0400 Subject: Add support for DXE memory attribute updates. This adds DXE implementations of get_mem_attrs() and update_mem_attrs() for machines that implement DXE but don't yet have the EFI_MEMORY_ATTRIBUTE_PROTOCOL. Signed-off-by: Peter Jones --- include/guid.h | 10 ++ memattrs.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 290 insertions(+), 38 deletions(-) (limited to 'include/guid.h') diff --git a/include/guid.h b/include/guid.h index e32dfc07..26628d1e 100644 --- a/include/guid.h +++ b/include/guid.h @@ -3,6 +3,16 @@ #ifndef SHIM_GUID_H #define SHIM_GUID_H +#define LGUID_FMT L"%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +#define GUID_FMT "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +#define GUID_ARGS(guid) \ + ((EFI_GUID)guid).Data1, ((EFI_GUID)guid).Data2, ((EFI_GUID)guid).Data3, \ + ((EFI_GUID)guid).Data4[1], ((EFI_GUID)guid).Data4[0], \ + ((EFI_GUID)guid).Data4[2], ((EFI_GUID)guid).Data4[3], \ + ((EFI_GUID)guid).Data4[4], ((EFI_GUID)guid).Data4[5], \ + ((EFI_GUID)guid).Data4[6], ((EFI_GUID)guid).Data4[7] + extern EFI_GUID BDS_GUID; extern EFI_GUID GV_GUID; extern EFI_GUID SIG_DB; diff --git a/memattrs.c b/memattrs.c index 988459c3..a2c1777c 100644 --- a/memattrs.c +++ b/memattrs.c @@ -44,21 +44,227 @@ uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs) return ret; } -EFI_STATUS -get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs) +static void +get_dxe_services_table(EFI_DXE_SERVICES_TABLE **dstp) +{ + static EFI_DXE_SERVICES_TABLE *dst = NULL; + + if (dst == NULL) { + dprint(L"Looking for configuration table " LGUID_FMT L"\n", GUID_ARGS(gEfiDxeServicesTableGuid)); + + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *ct = &ST->ConfigurationTable[i]; + dprint(L"Testing configuration table " LGUID_FMT L"\n", GUID_ARGS(ct->VendorGuid)); + if (CompareMem(&ct->VendorGuid, &gEfiDxeServicesTableGuid, sizeof(EFI_GUID)) != 0) + continue; + + dst = (EFI_DXE_SERVICES_TABLE *)ct->VendorTable; + dprint(L"Looking for DXE Services Signature 0x%16llx, found signature 0x%16llx\n", + EFI_DXE_SERVICES_TABLE_SIGNATURE, dst->Hdr.Signature); + if (dst->Hdr.Signature != EFI_DXE_SERVICES_TABLE_SIGNATURE) + continue; + + if (!dst->GetMemorySpaceDescriptor || !dst->SetMemorySpaceAttributes) { + /* + * purposefully not treating this as an error so that HSIStatus + * can tell us about it later. + */ + dprint(L"DXE Services lacks Get/SetMemorySpace* functions\n"); + } + + dprint(L"Setting dxe_services_table to 0x%llx\n", dst); + *dstp = dst; + return; + } + } else { + *dstp = dst; + return; + } + + dst = NULL; + dprint(L"Couldn't find DXE services\n"); +} + +static EFI_STATUS +dxe_get_mem_attrs(uintptr_t physaddr, size_t size, uint64_t *attrs) +{ + EFI_STATUS status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR desc; + EFI_PHYSICAL_ADDRESS start, end, next; + EFI_DXE_SERVICES_TABLE *dst = NULL; + + get_dxe_services_table(&dst); + if (!dst) + return EFI_UNSUPPORTED; + + if (!dst->GetMemorySpaceDescriptor || !dst->SetMemorySpaceAttributes) + return EFI_UNSUPPORTED; + + if (!IS_PAGE_ALIGNED(physaddr) || !IS_PAGE_ALIGNED(size) || size == 0 || attrs == NULL) { + dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n", + __func__, (unsigned long long)physaddr, + (unsigned long long)(physaddr+size-1), + attrs); + return EFI_SUCCESS; + } + + start = ALIGN_DOWN(physaddr, EFI_PAGE_SIZE); + end = ALIGN_UP(physaddr + size, EFI_PAGE_SIZE); + + for (; start < end; start = next) { + status = dst->GetMemorySpaceDescriptor(start, &desc); + if (EFI_ERROR(status)) { + dprint(L"GetMemorySpaceDescriptor(0x%llx, ...): %r\n", + start, status); + return status; + } + + next = desc.BaseAddress + desc.Length; + + if (desc.GcdMemoryType != EFI_GCD_MEMORY_TYPE_SYSTEM_MEMORY) + continue; + + *attrs = uefi_mem_attrs_to_shim_mem_attrs(desc.Attributes); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +static EFI_STATUS +dxe_update_mem_attrs(uintptr_t addr, size_t size, + uint64_t set_attrs, uint64_t clear_attrs) +{ +#if 0 + EFI_STATUS status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR desc; + EFI_PHYSICAL_ADDRESS start, end, next; + uint64_t before = 0, after = 0, dxe_set_attrs, dxe_clear_attrs; +#endif + EFI_DXE_SERVICES_TABLE *dst = NULL; + + get_dxe_services_table(&dst); + if (!dst) + return EFI_UNSUPPORTED; + + if (!dst->GetMemorySpaceDescriptor || !dst->SetMemorySpaceAttributes) + return EFI_UNSUPPORTED; + + if (!IS_PAGE_ALIGNED(addr) || !IS_PAGE_ALIGNED(size) || size == 0) { + perror(L"Invalid call %a(addr:0x%llx-0x%llx, size:0x%llx, +%a%a%a, -%a%a%a)\n", + __func__, (unsigned long long)addr, + (unsigned long long)(addr + size - 1), + (unsigned long long)size, + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : ""); + if (!IS_PAGE_ALIGNED(addr)) + perror(L" addr is not page aligned\n"); + if (!IS_PAGE_ALIGNED(size)) + perror(L" size is not page aligned\n"); + if (size == 0) + perror(L" size is 0\n"); + return EFI_SUCCESS; + } + + /* + * We know this only works coincidentally, so nerfing it for now + * until we have a chance to debug more thoroughly on these niche + * systems. + */ +#if 0 + start = ALIGN_DOWN(addr, EFI_PAGE_SIZE); + end = ALIGN_UP(addr + size, EFI_PAGE_SIZE); + + for (; start < end; start = next) { + EFI_PHYSICAL_ADDRESS mod_start; + UINT64 mod_size; + + status = dst->GetMemorySpaceDescriptor(start, &desc); + if (EFI_ERROR(status)) { + dprint(L"GetMemorySpaceDescriptor(0x%llx, ...): %r\n", + start, status); + return status; + } + + next = desc.BaseAddress + desc.Length; + + if (desc.GcdMemoryType != EFI_GCD_MEMORY_TYPE_SYSTEM_MEMORY) + continue; + + mod_start = MAX(start, desc.BaseAddress); + mod_size = MIN(end, next) - mod_start; + + before = uefi_mem_attrs_to_shim_mem_attrs(desc.Attributes); + dxe_set_attrs = shim_mem_attrs_to_uefi_mem_attrs(set_attrs); + dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, dxe_set_attrs); + dxe_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs(clear_attrs); + dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, dxe_clear_attrs); + desc.Attributes |= dxe_set_attrs; + desc.Attributes &= ~dxe_clear_attrs; + after = uefi_mem_attrs_to_shim_mem_attrs(desc.Attributes); + + status = dst->SetMemorySpaceAttributes(mod_start, mod_size, desc.Attributes); + if (EFI_ERROR(status)) { + dprint(L"Failed to update memory attrs:0x%0x addr:0x%llx size:0x%0lx status:%r\n", + desc.Attributes, mod_start, mod_size, status); + return status; + } + + break; + } + + dprint(L"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n", + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : "", + (unsigned long long)addr, (unsigned long long)(addr + size - 1), + (before & MEM_ATTR_R) ? 'r' : '-', + (before & MEM_ATTR_W) ? 'w' : '-', + (before & MEM_ATTR_X) ? 'x' : '-', + (after & MEM_ATTR_R) ? 'r' : '-', + (after & MEM_ATTR_W) ? 'w' : '-', + (after & MEM_ATTR_X) ? 'x' : '-'); +#endif + + return EFI_SUCCESS; +} + +static void +get_efi_mem_attr_protocol(EFI_MEMORY_ATTRIBUTE_PROTOCOL **protop) +{ + static EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; + static bool has_mem_access_proto = true; + + if (proto == NULL && has_mem_access_proto == true) { + EFI_STATUS efi_status; + efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, + (VOID **)&proto); + if (EFI_ERROR(efi_status) || !proto) { + has_mem_access_proto = false; + *protop = NULL; + } + } + + *protop = proto; +} + +static EFI_STATUS +efi_get_mem_attrs(uintptr_t addr, size_t size, uint64_t *attrs) { EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; EFI_PHYSICAL_ADDRESS physaddr = addr; EFI_STATUS efi_status; - efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, - (VOID **)&proto); - if (EFI_ERROR(efi_status) || !proto) { - dprint(L"No memory attribute protocol found: %r\n", efi_status); - if (!EFI_ERROR(efi_status)) - efi_status = EFI_UNSUPPORTED; - return efi_status; - } + get_efi_mem_attr_protocol(&proto); + if (!proto) + return EFI_UNSUPPORTED; if (!IS_PAGE_ALIGNED(physaddr) || !IS_PAGE_ALIGNED(size) || size == 0 || attrs == NULL) { dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n", @@ -79,23 +285,22 @@ get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs) return efi_status; } -EFI_STATUS -update_mem_attrs(uintptr_t addr, uint64_t size, - uint64_t set_attrs, uint64_t clear_attrs) +static EFI_STATUS +efi_update_mem_attrs(uintptr_t addr, uint64_t size, + uint64_t set_attrs, uint64_t clear_attrs) { EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; EFI_PHYSICAL_ADDRESS physaddr = addr; EFI_STATUS efi_status, ret; uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; - efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, - (VOID **)&proto); - if (EFI_ERROR(efi_status) || !proto) - return efi_status; + get_efi_mem_attr_protocol(&proto); + if (!proto) + return EFI_UNSUPPORTED; - efi_status = get_mem_attrs (addr, size, &before); + efi_status = efi_get_mem_attrs(addr, size, &before); if (EFI_ERROR(efi_status)) - dprint(L"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n", + dprint(L"efi_get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n", (unsigned long long)addr, (unsigned long long)size, &before, efi_status); @@ -116,7 +321,7 @@ update_mem_attrs(uintptr_t addr, uint64_t size, perror(L" size is not page aligned\n"); if (size == 0) perror(L" size is 0\n"); - return 0; + return EFI_SUCCESS; } uefi_set_attrs = shim_mem_attrs_to_uefi_mem_attrs (set_attrs); @@ -140,9 +345,9 @@ update_mem_attrs(uintptr_t addr, uint64_t size, } ret = efi_status; - efi_status = get_mem_attrs (addr, size, &after); + efi_status = efi_get_mem_attrs(addr, size, &after); if (EFI_ERROR(efi_status)) - dprint(L"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n", + dprint(L"efi_get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n", (unsigned long long)addr, (unsigned long long)size, &after, efi_status); @@ -164,6 +369,37 @@ update_mem_attrs(uintptr_t addr, uint64_t size, return ret; } +EFI_STATUS +update_mem_attrs(uintptr_t addr, uint64_t size, + uint64_t set_attrs, uint64_t clear_attrs) +{ + EFI_STATUS efi_status; + + efi_status = efi_update_mem_attrs(addr, size, set_attrs, clear_attrs); + if (!EFI_ERROR(efi_status)) + return efi_status; + + if (efi_status == EFI_UNSUPPORTED) + efi_status = dxe_update_mem_attrs(addr, size, set_attrs, clear_attrs); + + return efi_status; +} + +EFI_STATUS +get_mem_attrs(uintptr_t addr, size_t size, uint64_t *attrs) +{ + EFI_STATUS efi_status; + + efi_status = efi_get_mem_attrs(addr, size, attrs); + if (!EFI_ERROR(efi_status)) + return efi_status; + + if (efi_status == EFI_UNSUPPORTED) + efi_status = dxe_get_mem_attrs(addr, size, attrs); + + return efi_status; +} + void get_hsi_mem_info(void) { @@ -171,22 +407,10 @@ get_hsi_mem_info(void) uintptr_t addr; uint64_t attrs = 0; uint32_t *tmp_alloc; + EFI_MEMORY_ATTRIBUTE_PROTOCOL *efiproto = NULL; - addr = ((uintptr_t)&get_hsi_mem_info) & ~EFI_PAGE_MASK; - - efi_status = get_mem_attrs(addr, EFI_PAGE_SIZE, &attrs); - if (EFI_ERROR(efi_status)) { -error: - /* - * In this case we can't actually tell anything, so assume - * and report the worst case scenario. - */ - hsi_status = SHIM_HSI_STATUS_HEAPX | - SHIM_HSI_STATUS_STACKX | - SHIM_HSI_STATUS_ROW; - dprint(L"Setting HSI to 0x%lx due to error: %r\n", hsi_status, efi_status); - return; - } else { + get_efi_mem_attr_protocol(&efiproto); + if (efiproto) { hsi_status = SHIM_HSI_STATUS_HASMAP; dprint(L"Setting HSI to 0x%lx\n", hsi_status); } @@ -196,7 +420,13 @@ error: return; } - hsi_status = SHIM_HSI_STATUS_HASMAP; + addr = ((uintptr_t)&get_hsi_mem_info) & ~EFI_PAGE_MASK; + efi_status = get_mem_attrs(addr, EFI_PAGE_SIZE, &attrs); + if (EFI_ERROR(efi_status)) { + dprint(L"get_mem_attrs(0x%016llx, 0x%x, &attrs) failed.\n", addr, EFI_PAGE_SIZE); + goto error; + } + if (attrs & MEM_ATTR_W) { dprint(L"get_hsi_mem_info() is on a writable page: 0x%x->0x%x\n", hsi_status, hsi_status | SHIM_HSI_STATUS_ROW); @@ -234,6 +464,18 @@ error: hsi_status, hsi_status | SHIM_HSI_STATUS_HEAPX); hsi_status |= SHIM_HSI_STATUS_HEAPX; } + + return; + +error: + /* + * In this case we can't actually tell anything, so assume + * and report the worst case scenario. + */ + hsi_status = SHIM_HSI_STATUS_HEAPX | + SHIM_HSI_STATUS_STACKX | + SHIM_HSI_STATUS_ROW; + dprint(L"Setting HSI to 0x%lx due to error: %r\n", hsi_status, efi_status); } // vim:fenc=utf-8:tw=75:noet -- cgit v1.2.3