diff options
| -rw-r--r-- | MokVars.txt | 10 | ||||
| -rw-r--r-- | globals.c | 1 | ||||
| -rw-r--r-- | include/memattrs.h | 2 | ||||
| -rw-r--r-- | include/mok.h | 10 | ||||
| -rw-r--r-- | include/test-data-efivars-1.h | 6 | ||||
| -rw-r--r-- | memattrs.c | 72 | ||||
| -rw-r--r-- | mok.c | 46 | ||||
| -rw-r--r-- | shim.c | 1 | ||||
| -rw-r--r-- | test-mok-mirror.c | 13 |
9 files changed, 161 insertions, 0 deletions
diff --git a/MokVars.txt b/MokVars.txt index 71b42c82..e6e68ce4 100644 --- a/MokVars.txt +++ b/MokVars.txt @@ -93,3 +93,13 @@ to trust CA keys in the MokList. BS,NV MokListTrustedRT: A copy of MokListTrusted made available to the kernel at runtime. BS,RT + +HSIStatus: Status of various security features: + heap-is-executable: 0: heap allocations are not executable by default + 1: heap allocations are executable + stack-is-executable: 0: UEFI stack is not executable + 1: UEFI stack is executable + ro-sections-are-writable: 0: read-only sections are not writable + 1: read-only sections are writable + has-memory-attribute-protocol: 0: platform does not provide the EFI Memory Attribute Protocol + 1: platform does provide the EFI Memory Attribute Protocol @@ -28,6 +28,7 @@ verification_method_t verification_method; SHIM_IMAGE_LOADER shim_image_loader_interface; UINT8 user_insecure_mode; +UINTN hsi_status = 0; UINT8 ignore_db; UINT8 trust_mok_list; UINT8 mok_policy = 0; diff --git a/include/memattrs.h b/include/memattrs.h index 8fefef22..5c40b4cc 100644 --- a/include/memattrs.h +++ b/include/memattrs.h @@ -11,5 +11,7 @@ extern EFI_STATUS get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs); extern EFI_STATUS update_mem_attrs(uintptr_t addr, uint64_t size, uint64_t set_attrs, uint64_t clear_attrs); +extern void get_hsi_mem_info(void); + #endif /* !SHIM_MEMATTRS_H_ */ // vim:fenc=utf-8:tw=75:noet diff --git a/include/mok.h b/include/mok.h index c37ccba5..e6921e09 100644 --- a/include/mok.h +++ b/include/mok.h @@ -125,5 +125,15 @@ struct mok_variable_config_entry { */ #define MOK_POLICY_REQUIRE_NX 1 +extern UINTN hsi_status; +/* heap is executable */ +#define SHIM_HSI_STATUS_HEAPX 0x00000001ULL +/* stack is executable */ +#define SHIM_HSI_STATUS_STACKX 0x00000002ULL +/* read-only sections are writable */ +#define SHIM_HSI_STATUS_ROW 0x00000004ULL +/* platform provides the EFI Memory Attribute Protocol */ +#define SHIM_HSI_STATUS_HASMAP 0x00000008ULL + #endif /* !SHIM_MOK_H_ */ // vim:fenc=utf-8:tw=75:noet diff --git a/include/test-data-efivars-1.h b/include/test-data-efivars-1.h index 2831bd23..d97a4d6d 100644 --- a/include/test-data-efivars-1.h +++ b/include/test-data-efivars-1.h @@ -106,5 +106,11 @@ static const unsigned char test_data_efivars_1_MokListTrustedRT[] ={ 0x01 }; +static const unsigned char test_data_efivars_1_HSIStatus[] = + "heap-is-executable: 0\n" + "stack-is-executable: 0\n" + "ro-sections-are-writable: 0\n" + "has-memory-attribute-protocol: 0\n"; + #endif /* !TEST_DATA_EFIVARS_1_H_ */ // vim:fenc=utf-8:tw=75:noet @@ -164,4 +164,76 @@ update_mem_attrs(uintptr_t addr, uint64_t size, return ret; } +void +get_hsi_mem_info(void) +{ + EFI_STATUS efi_status; + uintptr_t addr; + uint64_t attrs = 0; + uint32_t *tmp_alloc; + + 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 { + hsi_status = SHIM_HSI_STATUS_HASMAP; + dprint(L"Setting HSI to 0x%lx\n", hsi_status); + } + + if (!(hsi_status & SHIM_HSI_STATUS_HASMAP)) { + dprint(L"No memory protocol, not testing further\n"); + return; + } + + hsi_status = SHIM_HSI_STATUS_HASMAP; + 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); + hsi_status |= SHIM_HSI_STATUS_ROW; + } + + addr = ((uintptr_t)&addr) & ~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_X) { + dprint(L"Stack variable is on an executable page: 0x%x->0x%x\n", + hsi_status, hsi_status | SHIM_HSI_STATUS_STACKX); + hsi_status |= SHIM_HSI_STATUS_STACKX; + } + + tmp_alloc = AllocatePool(EFI_PAGE_SIZE); + if (!tmp_alloc) { + dprint(L"Failed to allocate heap variable.\n"); + goto error; + } + + addr = ((uintptr_t)tmp_alloc) & ~EFI_PAGE_MASK; + efi_status = get_mem_attrs(addr, EFI_PAGE_SIZE, &attrs); + FreePool(tmp_alloc); + 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_X) { + dprint(L"Heap variable is on an executable page: 0x%x->0x%x\n", + hsi_status, hsi_status | SHIM_HSI_STATUS_HEAPX); + hsi_status |= SHIM_HSI_STATUS_HEAPX; + } +} + // vim:fenc=utf-8:tw=75:noet @@ -34,6 +34,44 @@ static BOOLEAN check_var(CHAR16 *varname) efi_status_; \ }) +static UINTN +format_hsi_status(UINT8 *buf, size_t sz, + struct mok_state_variable *msv UNUSED) +{ + const char heapx[] = "heap-is-executable: "; + const char stackx[] = "\nstack-is-executable: "; + const char row[] = "\nro-sections-are-writable: "; + const char hasmap[] = "\nhas-memory-attribute-protocol: "; + const char finale[] = "\n"; + char *pos; + + /* + * sizeof includes the trailing NUL which is where our 0 or 1 value + * fits + */ + UINTN ret = sizeof(heapx) + sizeof(stackx) + + sizeof(row) + sizeof(hasmap) + + sizeof(finale); + + if (buf == 0 || sz < ret) { + return ret; + } + + buf[0] = 0; + pos = (char *)buf; + pos = stpcpy(pos, heapx); + pos = stpcpy(pos, (hsi_status & SHIM_HSI_STATUS_HEAPX) ? "1" : "0"); + pos = stpcpy(pos, stackx); + pos = stpcpy(pos, (hsi_status & SHIM_HSI_STATUS_STACKX) ? "1" : "0"); + pos = stpcpy(pos, row); + pos = stpcpy(pos, (hsi_status & SHIM_HSI_STATUS_ROW) ? "1" : "0"); + pos = stpcpy(pos, hasmap); + pos = stpcpy(pos, (hsi_status & SHIM_HSI_STATUS_HASMAP) ? "1" : "0"); + stpcpy(pos, finale); + + return ret; +} + /* * If the OS has set any of these variables we need to drop into MOK and * handle them appropriately @@ -223,6 +261,14 @@ struct mok_state_variable mok_state_variable_data[] = { .pcr = 14, .state = &mok_policy, }, + {.name = L"HSIStatus", + .name8 = "HSIStatus", + .rtname = L"HSIStatus", + .rtname8 = "HSIStatus", + .guid = &SHIM_LOCK_GUID, + .flags = MOK_VARIABLE_CONFIG_ONLY, + .format = format_hsi_status, + }, { NULL, } }; size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]); @@ -2033,6 +2033,7 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) } init_openssl(); + get_hsi_mem_info(); efi_status = load_unbundled_trust(global_image_handle); if (EFI_ERROR(efi_status)) { diff --git a/test-mok-mirror.c b/test-mok-mirror.c index 316424ad..38b7ed97 100644 --- a/test-mok-mirror.c +++ b/test-mok-mirror.c @@ -398,6 +398,11 @@ test_mok_mirror_with_enough_space(void) EFI_VARIABLE_RUNTIME_ACCESS, .ops = { NONE, }, }, + {.guid = SHIM_LOCK_GUID, + .name = L"HSIStatus", + .attrs = 0, + .ops = { NONE, }, + }, {.guid = { 0, }, .name = NULL, } @@ -424,6 +429,10 @@ test_mok_mirror_with_enough_space(void) .data_size = sizeof(test_data_efivars_1_MokListTrustedRT), .data = test_data_efivars_1_MokListTrustedRT }, + {.name = "HSIStatus", + .data_size = sizeof(test_data_efivars_1_HSIStatus), + .data = test_data_efivars_1_HSIStatus + }, {.name = { 0, }, .data_size = 0, .data = NULL, @@ -614,6 +623,10 @@ test_mok_mirror_setvar_out_of_resources(void) .data_size = sizeof(test_data_efivars_1_MokListTrustedRT), .data = test_data_efivars_1_MokListTrustedRT }, + {.name = "HSIStatus", + .data_size = sizeof(test_data_efivars_1_HSIStatus), + .data = test_data_efivars_1_HSIStatus + }, {.name = { 0, }, .data_size = 0, .data = NULL, |
