From: Linus Torvalds Date: Wed, 13 Mar 2024 19:37:41 +0000 (-0700) Subject: Merge tag 'efi-next-for-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi X-Git-Tag: v6.9-rc1~133 X-Git-Url: https://repo.jachan.dev/linux.git/commitdiff_plain/70ef654469b371d0a71bcf967fa3dcbca05d4b25?hp=-c Merge tag 'efi-next-for-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi Pull EFI updates from Ard Biesheuvel: - Measure initrd and command line using the CC protocol if the ordinary TCG2 protocol is not implemented, typically on TDX confidential VMs - Avoid creating mappings that are both writable and executable while running in the EFI boot services. This is a prerequisite for getting the x86 shim loader signed by MicroSoft again, which allows the distros to install on x86 PCs that ship with EFI secure boot enabled. - API update for struct platform_driver::remove() * tag 'efi-next-for-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: virt: efi_secret: Convert to platform remove callback returning void x86/efistub: Remap kernel text read-only before dropping NX attribute efi/libstub: Add get_event_log() support for CC platforms efi/libstub: Measure into CC protocol if TCG2 protocol is absent efi/libstub: Add Confidential Computing (CC) measurement typedefs efi/tpm: Use symbolic GUID name from spec for final events table efi/libstub: Use TPM event typedefs from the TCG PC Client spec --- 70ef654469b371d0a71bcf967fa3dcbca05d4b25 diff --combined arch/x86/boot/compressed/misc.c index 4535242cc1b1,044e9add713d..b70e4a21c15f --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@@ -52,7 -52,6 +52,7 @@@ struct port_io_ops pio_ops memptr free_mem_ptr; memptr free_mem_end_ptr; +int spurious_nmi_count; static char *vidmem; static int vidport; @@@ -165,34 -164,21 +165,34 @@@ void __putstr(const char *s outb(0xff & (pos >> 1), vidport+1); } -void __puthex(unsigned long value) +static noinline void __putnum(unsigned long value, unsigned int base, + int mindig) { - char alpha[2] = "0"; - int bits; + char buf[8*sizeof(value)+1]; + char *p; - for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) { - unsigned long digit = (value >> bits) & 0xf; + p = buf + sizeof(buf); + *--p = '\0'; - if (digit < 0xA) - alpha[0] = '0' + digit; - else - alpha[0] = 'a' + (digit - 0xA); + while (mindig-- > 0 || value) { + unsigned char digit = value % base; + digit += (digit >= 10) ? ('a'-10) : '0'; + *--p = digit; - __putstr(alpha); + value /= base; } + + __putstr(p); +} + +void __puthex(unsigned long value) +{ + __putnum(value, 16, sizeof(value)*2); +} + +void __putdec(unsigned long value) +{ + __putnum(value, 10, 1); } #ifdef CONFIG_X86_NEED_RELOCS @@@ -344,6 -330,7 +344,7 @@@ static size_t parse_elf(void *output return ehdr.e_entry - LOAD_PHYSICAL_ADDR; } + const unsigned long kernel_text_size = VO___start_rodata - VO__text; const unsigned long kernel_total_size = VO__end - VO__text; static u8 boot_heap[BOOT_HEAP_SIZE] __aligned(4); @@@ -371,19 -358,6 +372,19 @@@ unsigned long decompress_kernel(unsigne return entry; } +/* + * Set the memory encryption xloadflag based on the mem_encrypt= command line + * parameter, if provided. + */ +static void parse_mem_encrypt(struct setup_header *hdr) +{ + int on = cmdline_find_option_bool("mem_encrypt=on"); + int off = cmdline_find_option_bool("mem_encrypt=off"); + + if (on > off) + hdr->xloadflags |= XLF_MEM_ENCRYPTION; +} + /* * The compressed kernel image (ZO), has been moved so that its position * is against the end of the buffer used to hold the uncompressed kernel @@@ -414,8 -388,6 +415,8 @@@ asmlinkage __visible void *extract_kern /* Clear flags intended for solely in-kernel use. */ boot_params_ptr->hdr.loadflags &= ~KASLR_FLAG; + parse_mem_encrypt(&boot_params_ptr->hdr); + sanitize_boot_params(boot_params_ptr); if (boot_params_ptr->screen_info.orig_video_mode == 7) { @@@ -522,16 -494,10 +523,16 @@@ /* Disable exception handling before booting the kernel */ cleanup_exception_handling(); + if (spurious_nmi_count) { + error_putstr("Spurious early NMIs ignored: "); + error_putdec(spurious_nmi_count); + error_putstr("\n"); + } + return output + entry_offset; } -void fortify_panic(const char *name) +void __fortify_panic(const u8 reason, size_t avail, size_t size) { error("detected buffer overflow"); } diff --combined drivers/firmware/efi/libstub/efi-stub-helper.c index 3dc2f9aaf08d,dbe43ffcee07..de659f6a815f --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@@ -11,6 -11,7 +11,7 @@@ #include #include + #include #include #include @@@ -24,8 -25,6 +25,8 @@@ static bool efi_noinitrd static bool efi_nosoftreserve; static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); +int efi_mem_encrypt; + bool __pure __efi_soft_reserve_enabled(void) { return !efi_nosoftreserve; @@@ -77,12 -76,6 +78,12 @@@ efi_status_t efi_parse_options(char con efi_noinitrd = true; } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) { efi_no5lvl = true; + } else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) && + !strcmp(param, "mem_encrypt") && val) { + if (parse_option_str(val, "on")) + efi_mem_encrypt = 1; + else if (parse_option_str(val, "off")) + efi_mem_encrypt = -1; } else if (!strcmp(param, "efi") && val) { efi_nochunk = parse_option_str(val, "nochunk"); efi_novamap |= parse_option_str(val, "novamap"); @@@ -201,7 -194,7 +202,7 @@@ void efi_apply_loadoptions_quirk(const *load_options_size = load_option_unpacked.optional_data_size; } - enum efistub_event { + enum efistub_event_type { EFISTUB_EVT_INITRD, EFISTUB_EVT_LOAD_OPTIONS, EFISTUB_EVT_COUNT, @@@ -227,54 -220,95 +228,95 @@@ static const struct }, }; + static_assert(sizeof(efi_tcg2_event_t) == sizeof(efi_cc_event_t)); + + union efistub_event { + efi_tcg2_event_t tcg2_data; + efi_cc_event_t cc_data; + }; + + struct efistub_measured_event { + union efistub_event event_data; + TCG_PCClientTaggedEvent tagged_event __packed; + }; + static efi_status_t efi_measure_tagged_event(unsigned long load_addr, unsigned long load_size, - enum efistub_event event) + enum efistub_event_type event) { + union { + efi_status_t + (__efiapi *hash_log_extend_event)(void *, u64, efi_physical_addr_t, + u64, const union efistub_event *); + struct { u32 hash_log_extend_event; } mixed_mode; + } method; + struct efistub_measured_event *evt; + int size = struct_size(evt, tagged_event.tagged_event_data, + events[event].event_data_len); efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_tcg2_protocol_t *tcg2 = NULL; + union efistub_event ev; efi_status_t status; + void *protocol; efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); if (tcg2) { - struct efi_measured_event { - efi_tcg2_event_t event_data; - efi_tcg2_tagged_event_t tagged_event; - u8 tagged_event_data[]; - } *evt; - int size = sizeof(*evt) + events[event].event_data_len; - - status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, - (void **)&evt); - if (status != EFI_SUCCESS) - goto fail; - - evt->event_data = (struct efi_tcg2_event){ + ev.tcg2_data = (struct efi_tcg2_event){ .event_size = size, - .event_header.header_size = sizeof(evt->event_data.event_header), + .event_header.header_size = sizeof(ev.tcg2_data.event_header), .event_header.header_version = EFI_TCG2_EVENT_HEADER_VERSION, .event_header.pcr_index = events[event].pcr_index, .event_header.event_type = EV_EVENT_TAG, }; - - evt->tagged_event = (struct efi_tcg2_tagged_event){ - .tagged_event_id = events[event].event_id, - .tagged_event_data_size = events[event].event_data_len, + protocol = tcg2; + method.hash_log_extend_event = + (void *)efi_table_attr(tcg2, hash_log_extend_event); + } else { + efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID; + efi_cc_protocol_t *cc = NULL; + + efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc); + if (!cc) + return EFI_UNSUPPORTED; + + ev.cc_data = (struct efi_cc_event){ + .event_size = size, + .event_header.header_size = sizeof(ev.cc_data.event_header), + .event_header.header_version = EFI_CC_EVENT_HEADER_VERSION, + .event_header.event_type = EV_EVENT_TAG, }; - memcpy(evt->tagged_event_data, events[event].event_data, - events[event].event_data_len); - - status = efi_call_proto(tcg2, hash_log_extend_event, 0, - load_addr, load_size, &evt->event_data); - efi_bs_call(free_pool, evt); - + status = efi_call_proto(cc, map_pcr_to_mr_index, + events[event].pcr_index, + &ev.cc_data.event_header.mr_index); if (status != EFI_SUCCESS) goto fail; - return EFI_SUCCESS; + + protocol = cc; + method.hash_log_extend_event = + (void *)efi_table_attr(cc, hash_log_extend_event); } - return EFI_UNSUPPORTED; + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt); + if (status != EFI_SUCCESS) + goto fail; + + *evt = (struct efistub_measured_event) { + .event_data = ev, + .tagged_event.tagged_event_id = events[event].event_id, + .tagged_event.tagged_event_data_size = events[event].event_data_len, + }; + + memcpy(evt->tagged_event.tagged_event_data, events[event].event_data, + events[event].event_data_len); + + status = efi_fn_call(&method, hash_log_extend_event, protocol, 0, + load_addr, load_size, &evt->event_data); + efi_bs_call(free_pool, evt); + + if (status == EFI_SUCCESS) + return EFI_SUCCESS; + fail: efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); return status; diff --combined drivers/firmware/efi/libstub/efistub.h index fc18fd649ed7,df174edfc228..27abb4ce0291 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@@ -37,8 -37,8 +37,8 @@@ extern bool efi_no5lvl extern bool efi_nochunk; extern bool efi_nokaslr; extern int efi_loglevel; +extern int efi_mem_encrypt; extern bool efi_novamap; - extern const efi_system_table_t *efi_system_table; typedef union efi_dxe_services_table efi_dxe_services_table_t; @@@ -843,14 -843,14 +843,14 @@@ struct efi_tcg2_event /* u8[] event follows here */ } __packed; - struct efi_tcg2_tagged_event { - u32 tagged_event_id; - u32 tagged_event_data_size; - /* u8 tagged event data follows here */ - } __packed; + /* from TCG PC Client Platform Firmware Profile Specification */ + typedef struct tdTCG_PCClientTaggedEvent { + u32 tagged_event_id; + u32 tagged_event_data_size; + u8 tagged_event_data[]; + } TCG_PCClientTaggedEvent; typedef struct efi_tcg2_event efi_tcg2_event_t; - typedef struct efi_tcg2_tagged_event efi_tcg2_tagged_event_t; typedef union efi_tcg2_protocol efi_tcg2_protocol_t; union efi_tcg2_protocol { @@@ -882,6 -882,87 +882,87 @@@ } mixed_mode; }; + typedef struct { + u8 major; + u8 minor; + } efi_cc_version_t; + + typedef struct { + u8 type; + u8 sub_type; + } efi_cc_type_t; + + /* EFI CC type/subtype defines */ + #define EFI_CC_TYPE_NONE 0 + #define EFI_CC_TYPE_AMD_SEV 1 + #define EFI_CC_TYPE_INTEL_TDX 2 + + typedef u32 efi_cc_mr_index_t; + + struct efi_cc_event { + u32 event_size; + struct { + u32 header_size; + u16 header_version; + u32 mr_index; + u32 event_type; + } __packed event_header; + /* u8[] event follows here */ + } __packed; + + typedef struct efi_cc_event efi_cc_event_t; + + typedef u32 efi_cc_event_log_bitmap_t; + typedef u32 efi_cc_event_log_format_t; + typedef u32 efi_cc_event_algorithm_bitmap_t; + + typedef struct { + u8 size; + efi_cc_version_t structure_version; + efi_cc_version_t protocol_version; + efi_cc_event_algorithm_bitmap_t hash_algorithm_bitmap; + efi_cc_event_log_bitmap_t supported_event_logs; + efi_cc_type_t cc_type; + } efi_cc_boot_service_cap_t; + + #define EFI_CC_EVENT_HEADER_VERSION 1 + + #define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 + + #define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 + + typedef union efi_cc_protocol efi_cc_protocol_t; + + union efi_cc_protocol { + struct { + efi_status_t + (__efiapi *get_capability)(efi_cc_protocol_t *, + efi_cc_boot_service_cap_t *); + + efi_status_t + (__efiapi *get_event_log)(efi_cc_protocol_t *, + efi_cc_event_log_format_t, + efi_physical_addr_t *, + efi_physical_addr_t *, + efi_bool_t *); + + efi_status_t + (__efiapi *hash_log_extend_event)(efi_cc_protocol_t *, u64, + efi_physical_addr_t, u64, + const efi_cc_event_t *); + + efi_status_t + (__efiapi *map_pcr_to_mr_index)(efi_cc_protocol_t *, u32, + efi_cc_mr_index_t *); + }; + struct { + u32 get_capability; + u32 get_event_log; + u32 hash_log_extend_event; + u32 map_pcr_to_mr_index; + } mixed_mode; + }; + struct riscv_efi_boot_protocol { u64 revision; @@@ -1061,7 -1142,7 +1142,7 @@@ static inline voi efi_enable_reset_attack_mitigation(void) { } #endif - void efi_retrieve_tpm2_eventlog(void); + void efi_retrieve_eventlog(void); struct screen_info *alloc_screen_info(void); struct screen_info *__alloc_screen_info(void); diff --combined drivers/firmware/efi/libstub/x86-stub.c index 0336ed175e67,35413c8dfc25..4f448d4df7b8 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@@ -236,6 -236,15 +236,15 @@@ efi_status_t efi_adjust_memory_range_pr rounded_end = roundup(start + size, EFI_PAGE_SIZE); if (memattr != NULL) { + status = efi_call_proto(memattr, set_memory_attributes, + rounded_start, + rounded_end - rounded_start, + EFI_MEMORY_RO); + if (status != EFI_SUCCESS) { + efi_warn("Failed to set EFI_MEMORY_RO attribute\n"); + return status; + } + status = efi_call_proto(memattr, clear_memory_attributes, rounded_start, rounded_end - rounded_start, @@@ -812,7 -821,7 +821,7 @@@ static efi_status_t efi_decompress_kern *kernel_entry = addr + entry; - return efi_adjust_memory_range_protection(addr, kernel_total_size); + return efi_adjust_memory_range_protection(addr, kernel_text_size); } static void __noreturn enter_kernel(unsigned long kernel_addr, @@@ -884,9 -893,6 +893,9 @@@ void __noreturn efi_stub_entry(efi_hand } } + if (efi_mem_encrypt > 0) + hdr->xloadflags |= XLF_MEM_ENCRYPTION; + status = efi_decompress_kernel(&kernel_entry); if (status != EFI_SUCCESS) { efi_err("Failed to decompress kernel\n"); @@@ -926,7 -932,7 +935,7 @@@ efi_random_get_seed(); - efi_retrieve_tpm2_eventlog(); + efi_retrieve_eventlog(); setup_graphics(boot_params);