From bc314f8e5f9b646e5ed09ccee2a2ddb012519305 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 11 Jan 2022 16:03:38 +0100 Subject: cmd: part: list all 128 GPT partitions A GPT partition table typically has 128 entries. If a partition table contains a partition 128 'part list' should be able to list it. Signed-off-by: Heinrich Schuchardt --- cmd/part.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/part.c b/cmd/part.c index e0463b5a541..9d419c967cb 100644 --- a/cmd/part.c +++ b/cmd/part.c @@ -89,10 +89,10 @@ static int do_part_list(int argc, char *const argv[]) if (var != NULL) { int p; - char str[512] = { '\0', }; + char str[3 * MAX_SEARCH_PARTITIONS] = { '\0', }; struct disk_partition info; - for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { + for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { char t[5]; int r = part_get_info(desc, p, &info); -- cgit v1.2.3 From a2f1482fc0e6c5dbdbafecd360d168f9c12fc529 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Mon, 3 Jan 2022 14:07:37 +0200 Subject: efi_loader: Get rid of kaslr-seed if EFI_RNG_PROTOCOL is installed U-Boot, in some occasions, injects a 'kaslr-seed' property on the /chosen node. That would be problematic in case we want to measure the DTB we install in the configuration table, since it would change across reboots. The Linux kernel EFI-stub completely ignores it and only relies on EFI_RNG_PROTOCOL for it's own randomness needs (i.e the randomization of the physical placement of the kernel). In fact it (blindly) overwrites the existing seed if the protocol is installed. However it still uses it for randomizing it's virtual placement. So let's get rid of it in the presence of the RNG protocol. It's worth noting that TPMs also provide an RNG. So if we tweak our EFI_RNG_PROTOCOL slightly and install the protocol when a TPM device is present the 'kaslr-seed' property will always be removed, allowing us to reliably measure our DTB. Acked-by: Ard Biesheuvel Signed-off-by: Ilias Apalodimas Reviewed-by: Mark Kettenis --- cmd/bootefi.c | 2 ++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_dt_fixup.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 83eab0bd7f1..3a8b2b60618 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -310,6 +310,8 @@ efi_status_t efi_install_fdt(void *fdt) /* Create memory reservations as indicated by the device tree */ efi_carve_out_dt_rsv(fdt); + efi_try_purge_kaslr_seed(fdt); + /* Install device tree as UEFI table */ ret = efi_install_configuration_table(&efi_guid_fdt, fdt); if (ret != EFI_SUCCESS) { diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc1..f20d3618765 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -517,6 +517,8 @@ efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition, void **address); /* Carve out DT reserved memory ranges */ void efi_carve_out_dt_rsv(void *fdt); +/* Purge unused kaslr-seed */ +void efi_try_purge_kaslr_seed(void *fdt); /* Called by bootefi to make console interface available */ efi_status_t efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index b6fe5d2e5a3..d3923e5dba1 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,38 @@ static void efi_reserve_memory(u64 addr, u64 size, bool nomap) addr, size); } +/** + * efi_try_purge_kaslr_seed() - Remove unused kaslr-seed + * + * Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization + * and completely ignores the kaslr-seed for its own randomness needs + * (i.e the randomization of the physical placement of the kernel). + * Weed it out from the DTB we hand over, which would mess up our DTB + * TPM measurements as well. + * + * @fdt: Pointer to device tree + */ +void efi_try_purge_kaslr_seed(void *fdt) +{ + const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID; + struct efi_handler *handler; + efi_status_t ret; + int nodeoff = 0; + int err = 0; + + ret = efi_search_protocol(efi_root, &efi_guid_rng_protocol, &handler); + if (ret != EFI_SUCCESS) + return; + + nodeoff = fdt_path_offset(fdt, "/chosen"); + if (nodeoff < 0) + return; + + err = fdt_delprop(fdt, nodeoff, "kaslr-seed"); + if (err < 0 && err != -FDT_ERR_NOTFOUND) + log_err("Error deleting kaslr-seed\n"); +} + /** * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges * -- cgit v1.2.3 From ce1dc0cc17e94a0bf1c17bd1465cb0afd5bfb214 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 4 Jan 2022 03:51:11 -0700 Subject: x86: efi: Update efi_get_next_mem_desc() to avoid needing a map At present this function requires a pointer to struct efi_entry_memmap but the only field used in there is the desc_size. We want to be able to use it from the app, so update it to use desc_size directly. Signed-off-by: Simon Glass --- arch/x86/cpu/efi/payload.c | 8 ++++---- cmd/efi.c | 34 ++++++++++++++++++---------------- include/efi.h | 4 ++-- 3 files changed, 24 insertions(+), 22 deletions(-) (limited to 'cmd') diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 04ce1880b4d..b7778565b19 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -51,7 +51,7 @@ ulong board_get_usable_ram_top(ulong total_size) end = (struct efi_mem_desc *)((ulong)map + size); desc = map->desc; - for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->type != EFI_CONVENTIONAL_MEMORY || desc->physical_start >= 1ULL << 32) continue; @@ -89,7 +89,7 @@ int dram_init(void) end = (struct efi_mem_desc *)((ulong)map + size); gd->ram_size = 0; desc = map->desc; - for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->type < EFI_MMAP_IO) gd->ram_size += desc->num_pages << EFI_PAGE_SHIFT; } @@ -114,7 +114,7 @@ int dram_init_banksize(void) desc = map->desc; for (num_banks = 0; desc < end && num_banks < CONFIG_NR_DRAM_BANKS; - desc = efi_get_next_mem_desc(map, desc)) { + desc = efi_get_next_mem_desc(desc, map->desc_size)) { /* * We only use conventional memory and ignore * anything less than 1MB. @@ -197,7 +197,7 @@ unsigned int install_e820_map(unsigned int max_entries, end = (struct efi_mem_desc *)((ulong)map + size); for (desc = map->desc; desc < end; - desc = efi_get_next_mem_desc(map, desc)) { + desc = efi_get_next_mem_desc(desc, map->desc_size)) { if (desc->num_pages == 0) continue; diff --git a/cmd/efi.c b/cmd/efi.c index f2ed26bd4b2..d2400acbbba 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -75,16 +75,17 @@ static int h_cmp_entry(const void *v1, const void *v2) /** * efi_build_mem_table() - make a sorted copy of the memory table * - * @map: Pointer to EFI memory map table + * @desc_base: Pointer to EFI memory map table * @size: Size of table in bytes + * @desc_size: Size of each @desc_base record * @skip_bs: True to skip boot-time memory and merge it with conventional * memory. This will significantly reduce the number of table * entries. * Return: pointer to the new table. It should be freed with free() by the * caller. */ -static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, - bool skip_bs) +static void *efi_build_mem_table(struct efi_mem_desc *desc_base, int size, + int desc_size, bool skip_bs) { struct efi_mem_desc *desc, *end, *base, *dest, *prev; int count; @@ -95,15 +96,16 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, debug("%s: Cannot allocate %#x bytes\n", __func__, size); return NULL; } - end = (struct efi_mem_desc *)((ulong)map + size); - count = ((ulong)end - (ulong)map->desc) / map->desc_size; - memcpy(base, map->desc, (ulong)end - (ulong)map->desc); - qsort(base, count, map->desc_size, h_cmp_entry); + end = (void *)desc_base + size; + count = ((ulong)end - (ulong)desc_base) / desc_size; + memcpy(base, desc_base, (ulong)end - (ulong)desc_base); + qsort(base, count, desc_size, h_cmp_entry); prev = NULL; addr = 0; dest = base; - end = (struct efi_mem_desc *)((ulong)base + count * map->desc_size); - for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) { + end = (struct efi_mem_desc *)((ulong)base + count * desc_size); + for (desc = base; desc < end; + desc = efi_get_next_mem_desc(desc, desc_size)) { bool merge = true; u32 type = desc->type; @@ -116,7 +118,7 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, if (skip_bs && is_boot_services(desc->type)) type = EFI_CONVENTIONAL_MEMORY; - memcpy(dest, desc, map->desc_size); + memcpy(dest, desc, desc_size); dest->type = type; if (!skip_bs || !prev) merge = false; @@ -131,7 +133,7 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, prev->num_pages += desc->num_pages; } else { prev = dest; - dest = efi_get_next_mem_desc(map, dest); + dest = efi_get_next_mem_desc(dest, desc_size); } addr = desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT); @@ -143,8 +145,8 @@ static void *efi_build_mem_table(struct efi_entry_memmap *map, int size, return base; } -static void efi_print_mem_table(struct efi_entry_memmap *map, - struct efi_mem_desc *desc, bool skip_bs) +static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, + bool skip_bs) { u64 attr_seen[ATTR_SEEN_MAX]; int attr_seen_count; @@ -158,7 +160,7 @@ static void efi_print_mem_table(struct efi_entry_memmap *map, attr_seen_count = 0; addr = 0; for (upto = 0; desc->type != EFI_MAX_MEMORY_TYPE; - upto++, desc = efi_get_next_mem_desc(map, desc)) { + upto++, desc = efi_get_next_mem_desc(desc, desc_size)) { const char *name; u64 size; @@ -238,13 +240,13 @@ static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, goto done; } - desc = efi_build_mem_table(map, size, skip_bs); + desc = efi_build_mem_table(map->desc, size, map->desc_size, skip_bs); if (!desc) { ret = -ENOMEM; goto done; } - efi_print_mem_table(map, desc, skip_bs); + efi_print_mem_table(desc, map->desc_size, skip_bs); free(desc); done: if (ret) diff --git a/include/efi.h b/include/efi.h index dc9907fa16e..3508ff8f639 100644 --- a/include/efi.h +++ b/include/efi.h @@ -395,9 +395,9 @@ struct efi_entry_systable { }; static inline struct efi_mem_desc *efi_get_next_mem_desc( - struct efi_entry_memmap *map, struct efi_mem_desc *desc) + struct efi_mem_desc *desc, int desc_size) { - return (struct efi_mem_desc *)((ulong)desc + map->desc_size); + return (struct efi_mem_desc *)((ulong)desc + desc_size); } /** -- cgit v1.2.3 From 25a326b0066b3c449a0a91889b0ce19cb7320237 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 4 Jan 2022 03:51:12 -0700 Subject: efi: Support the efi command in the app At present the 'efi' command only works in the EFI payload. Update it to work in the app too, so the memory map can be examined. Signed-off-by: Simon Glass Signed-off-by: Heinrich Schuchardt --- cmd/Makefile | 2 +- cmd/efi.c | 48 +++++++++++++++++++++++++++++++++--------------- include/efi.h | 15 +++++++++++++++ lib/efi/efi_app.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 16 deletions(-) (limited to 'cmd') diff --git a/cmd/Makefile b/cmd/Makefile index e31ac15ef75..6623d7eaa05 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_CMD_EXTENSION) += extension_board.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o -obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o diff --git a/cmd/efi.c b/cmd/efi.c index d2400acbbba..c0384e0db28 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -13,6 +13,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + static const char *const type_name[] = { "reserved", "loader_code", @@ -217,37 +219,53 @@ static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct efi_mem_desc *desc; - struct efi_entry_memmap *map; + struct efi_mem_desc *orig, *desc; + uint version, key; + int desc_size; int size, ret; bool skip_bs; skip_bs = !argc || *argv[0] != 'a'; - ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); - switch (ret) { - case -ENOENT: - printf("No EFI table available\n"); - goto done; - case -EPROTONOSUPPORT: - printf("Incorrect EFI table version\n"); - goto done; + if (IS_ENABLED(CONFIG_EFI_APP)) { + ret = efi_get_mmap(&orig, &size, &key, &desc_size, &version); + if (ret) { + printf("Cannot read memory map (err=%d)\n", ret); + return CMD_RET_FAILURE; + } + } else { + struct efi_entry_memmap *map; + + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + switch (ret) { + case -ENOENT: + printf("No EFI table available\n"); + goto done; + case -EPROTONOSUPPORT: + printf("Incorrect EFI table version\n"); + goto done; + } + orig = map->desc; + desc_size = map->desc_size; + version = map->version; } - printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n", - gd->arch.table, map, size, map->version, map->desc_size); - if (map->version != EFI_MEM_DESC_VERSION) { + printf("EFI table at %lx, memory map %p, size %x, key %x, version %x, descr. size %#x\n", + gd->arch.table, orig, size, key, version, desc_size); + if (version != EFI_MEM_DESC_VERSION) { printf("Incorrect memory map version\n"); ret = -EPROTONOSUPPORT; goto done; } - desc = efi_build_mem_table(map->desc, size, map->desc_size, skip_bs); + desc = efi_build_mem_table(orig, size, desc_size, skip_bs); if (!desc) { ret = -ENOMEM; goto done; } - efi_print_mem_table(desc, map->desc_size, skip_bs); + efi_print_mem_table(desc, desc_size, skip_bs); free(desc); + if (IS_ENABLED(CONFIG_EFI_APP)) + free(orig); done: if (ret) printf("Error: %d\n", ret); diff --git a/include/efi.h b/include/efi.h index 3508ff8f639..9b7ba0d54d3 100644 --- a/include/efi.h +++ b/include/efi.h @@ -610,4 +610,19 @@ int efi_store_memory_map(struct efi_priv *priv); */ int efi_call_exit_boot_services(void); +/** + * efi_get_mmap() - Get the memory map from EFI + * + * This is used in the app. The caller must free *@descp when done + * + * @descp: Returns allocated pointer to EFI memory map table + * @sizep: Returns size of table in bytes + * @keyp: Returns memory-map key + * @desc_sizep: Returns size of each @desc_base record + * @versionp: Returns version number of memory map + * @return 0 on success, -ve on error + */ +int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp); + #endif /* _LINUX_EFI_H */ diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 5c2593bc4d9..6980933d7ea 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -32,6 +32,39 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; } +int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp) +{ + struct efi_priv *priv = efi_get_priv(); + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size, key; + struct efi_mem_desc *desc; + efi_status_t ret; + u32 version; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) + return log_msg_ret("get", -ENOMEM); + + desc = malloc(size); + if (!desc) + return log_msg_ret("mem", -ENOMEM); + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) + return log_msg_ret("get", -EINVAL); + + *descp = desc; + *sizep = size; + *desc_sizep = desc_size; + *versionp = version; + *keyp = key; + + return 0; +} + /** * efi_bind_block() - bind a new block device to an EFI device * -- cgit v1.2.3