diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 15:36:30 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 15:36:30 -0800 |
commit | f12fc75ef7db44d71d5a509e2f1bec6966b73776 (patch) | |
tree | 5afdcbdeacae408fb546a60253510d3ea25a0b6c | |
parent | f69212114220edf8372867088b97b47760b6839d (diff) | |
parent | 42f4046bc4ba56c6e4d2af7a9d7f70eaa563daec (diff) | |
download | linux-f12fc75ef7db44d71d5a509e2f1bec6966b73776.tar.bz2 |
Merge tag 'efi-next-for-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
Pull EFI updates from Ard Biesheuvel:
- support taking the measurement of the initrd when loaded via the
LoadFile2 protocol
- kobject API cleanup from Greg
- some header file whitespace fixes
* tag 'efi-next-for-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
efi: use default_groups in kobj_type
efi/libstub: measure loaded initrd info into the TPM
efi/libstub: consolidate initrd handling across architectures
efi/libstub: x86/mixed: increase supported argument count
efi/libstub: add prototype of efi_tcg2_protocol::hash_log_extend_event()
include/linux/efi.h: Remove unneeded whitespaces before tabs
-rw-r--r-- | arch/x86/boot/compressed/efi_thunk_64.S | 14 | ||||
-rw-r--r-- | arch/x86/include/asm/efi.h | 14 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_thunk_64.S | 14 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/esrt.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 73 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub.c | 10 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 30 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/x86-stub.c | 26 | ||||
-rw-r--r-- | drivers/firmware/efi/runtime-map.c | 3 | ||||
-rw-r--r-- | include/linux/efi.h | 6 |
11 files changed, 144 insertions, 53 deletions
diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S index 8bb92e9f4e97..d05f781d54f2 100644 --- a/arch/x86/boot/compressed/efi_thunk_64.S +++ b/arch/x86/boot/compressed/efi_thunk_64.S @@ -26,8 +26,6 @@ SYM_FUNC_START(__efi64_thunk) push %rbp push %rbx - leaq 1f(%rip), %rbp - movl %ds, %eax push %rax movl %es, %eax @@ -35,6 +33,11 @@ SYM_FUNC_START(__efi64_thunk) movl %ss, %eax push %rax + /* Copy args passed on stack */ + movq 0x30(%rsp), %rbp + movq 0x38(%rsp), %rbx + movq 0x40(%rsp), %rax + /* * Convert x86-64 ABI params to i386 ABI */ @@ -44,13 +47,18 @@ SYM_FUNC_START(__efi64_thunk) movl %ecx, 0x8(%rsp) movl %r8d, 0xc(%rsp) movl %r9d, 0x10(%rsp) + movl %ebp, 0x14(%rsp) + movl %ebx, 0x18(%rsp) + movl %eax, 0x1c(%rsp) - leaq 0x14(%rsp), %rbx + leaq 0x20(%rsp), %rbx sgdt (%rbx) addq $16, %rbx sidt (%rbx) + leaq 1f(%rip), %rbp + /* * Switch to IDT and GDT with 32-bit segments. This is the firmware GDT * and IDT that was installed when the kernel started executing. The diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 63158fd55856..03cb12775043 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -46,13 +46,14 @@ extern unsigned long efi_mixed_mode_stack_pa; #define __efi_nargs(...) __efi_nargs_(__VA_ARGS__) #define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__, \ + __efi_arg_sentinel(9), __efi_arg_sentinel(8), \ __efi_arg_sentinel(7), __efi_arg_sentinel(6), \ __efi_arg_sentinel(5), __efi_arg_sentinel(4), \ __efi_arg_sentinel(3), __efi_arg_sentinel(2), \ __efi_arg_sentinel(1), __efi_arg_sentinel(0)) -#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...) \ +#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, n, ...) \ __take_second_arg(n, \ - ({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; })) + ({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 10; })) #define __efi_arg_sentinel(n) , n /* @@ -176,8 +177,9 @@ extern u64 efi_setup; extern efi_status_t __efi64_thunk(u32, ...); #define efi64_thunk(...) ({ \ - __efi_nargs_check(efi64_thunk, 6, __VA_ARGS__); \ - __efi64_thunk(__VA_ARGS__); \ + u64 __pad[3]; /* must have space for 3 args on the stack */ \ + __efi_nargs_check(efi64_thunk, 9, __VA_ARGS__); \ + __efi64_thunk(__VA_ARGS__, __pad); \ }) static inline bool efi_is_mixed(void) @@ -306,6 +308,10 @@ static inline u32 efi64_convert_status(efi_status_t status) #define __efi64_argmap_query_mode(gop, mode, size, info) \ ((gop), (mode), efi64_zero_upper(size), efi64_zero_upper(info)) +/* TCG2 protocol */ +#define __efi64_argmap_hash_log_extend_event(prot, fl, addr, size, ev) \ + ((prot), (fl), 0ULL, (u64)(addr), 0ULL, (u64)(size), 0ULL, ev) + /* * The macros below handle the plumbing for the argument mapping. To add a * mapping for a specific EFI method, simply define a macro diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S index fd3dd1708eba..5b7c6e09954e 100644 --- a/arch/x86/platform/efi/efi_thunk_64.S +++ b/arch/x86/platform/efi/efi_thunk_64.S @@ -37,6 +37,17 @@ SYM_CODE_START(__efi64_thunk) push %rax /* + * Copy args passed via the stack + */ + subq $0x24, %rsp + movq 0x18(%rax), %rbp + movq 0x20(%rax), %rbx + movq 0x28(%rax), %rax + movl %ebp, 0x18(%rsp) + movl %ebx, 0x1c(%rsp) + movl %eax, 0x20(%rsp) + + /* * Calculate the physical address of the kernel text. */ movq $__START_KERNEL_map, %rax @@ -47,7 +58,6 @@ SYM_CODE_START(__efi64_thunk) subq %rax, %rbp subq %rax, %rbx - subq $28, %rsp movl %ebx, 0x0(%rsp) /* return address */ movl %esi, 0x4(%rsp) movl %edx, 0x8(%rsp) @@ -60,7 +70,7 @@ SYM_CODE_START(__efi64_thunk) pushq %rdi /* EFI runtime service address */ lretq -1: movq 24(%rsp), %rsp +1: movq 0x20(%rsp), %rsp pop %rbx pop %rbp retq diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index e6b16b3a17a8..ea0bc39dc965 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -352,11 +352,12 @@ static struct attribute *def_attrs[] = { &efivar_attr_raw_var.attr, NULL, }; +ATTRIBUTE_GROUPS(def); static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, - .default_attrs = def_attrs, + .default_groups = def_groups, }; static ssize_t efivar_create(struct file *filp, struct kobject *kobj, diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index d5915272141f..2a2f52b017e7 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -146,6 +146,8 @@ static struct attribute *esre1_attrs[] = { &esre_last_attempt_status.attr, NULL }; +ATTRIBUTE_GROUPS(esre1); + static void esre_release(struct kobject *kobj) { struct esre_entry *entry = to_entry(kobj); @@ -157,7 +159,7 @@ static void esre_release(struct kobject *kobj) static struct kobj_type esre1_ktype = { .release = esre_release, .sysfs_ops = &esre_attr_ops, - .default_attrs = esre1_attrs, + .default_groups = esre1_groups, }; diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index d489bdc645fe..3d972061c1b0 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -20,10 +20,10 @@ bool efi_nochunk; bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); -bool efi_noinitrd; int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; bool efi_novamap; +static bool efi_noinitrd; static bool efi_nosoftreserve; static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); @@ -625,6 +625,47 @@ efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image, load_addr, load_size); } +static const struct { + efi_tcg2_event_t event_data; + efi_tcg2_tagged_event_t tagged_event; + u8 tagged_event_data[]; +} initrd_tcg2_event = { + { + sizeof(initrd_tcg2_event) + sizeof("Linux initrd"), + { + sizeof(initrd_tcg2_event.event_data.event_header), + EFI_TCG2_EVENT_HEADER_VERSION, + 9, + EV_EVENT_TAG, + }, + }, + { + INITRD_EVENT_TAG_ID, + sizeof("Linux initrd"), + }, + { "Linux initrd" }, +}; + +static void efi_measure_initrd(unsigned long load_addr, unsigned long load_size) +{ + efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; + efi_tcg2_protocol_t *tcg2 = NULL; + efi_status_t status; + + efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); + if (tcg2) { + status = efi_call_proto(tcg2, hash_log_extend_event, + 0, load_addr, load_size, + &initrd_tcg2_event.event_data); + if (status != EFI_SUCCESS) + efi_warn("Failed to measure initrd data: 0x%lx\n", + status); + else + efi_info("Measured initrd data into PCR %d\n", + initrd_tcg2_event.event_data.event_header.pcr_index); + } +} + /** * efi_load_initrd() - Load initial RAM disk * @image: EFI loaded image protocol @@ -643,17 +684,25 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, { efi_status_t status; - if (!load_addr || !load_size) - return EFI_INVALID_PARAMETER; - - status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit); - if (status == EFI_SUCCESS) { - efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); - } else if (status == EFI_NOT_FOUND) { - status = efi_load_initrd_cmdline(image, load_addr, load_size, - soft_limit, hard_limit); - if (status == EFI_SUCCESS && *load_size > 0) - efi_info("Loaded initrd from command line option\n"); + if (efi_noinitrd) { + *load_addr = *load_size = 0; + status = EFI_SUCCESS; + } else { + status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit); + if (status == EFI_SUCCESS) { + efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); + if (*load_size > 0) + efi_measure_initrd(*load_addr, *load_size); + } else if (status == EFI_NOT_FOUND) { + status = efi_load_initrd_cmdline(image, load_addr, load_size, + soft_limit, hard_limit); + if (status == EFI_SUCCESS && *load_size > 0) + efi_info("Loaded initrd from command line option\n"); + } + if (status != EFI_SUCCESS) { + efi_err("Failed to load initrd: 0x%lx\n", status); + *load_addr = *load_size = 0; + } } return status; diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 26e69788f27a..e87e7f1b1a33 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -134,7 +134,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, enum efi_secureboot_mode secure_boot; struct screen_info *si; efi_properties_table_t *prop_tbl; - unsigned long max_addr; efi_system_table = sys_table_arg; @@ -240,13 +239,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, if (!fdt_addr) efi_info("Generating empty DTB\n"); - if (!efi_noinitrd) { - max_addr = efi_get_max_initrd_addr(image_addr); - status = efi_load_initrd(image, &initrd_addr, &initrd_size, - ULONG_MAX, max_addr); - if (status != EFI_SUCCESS) - efi_err("Failed to load initrd!\n"); - } + efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX, + efi_get_max_initrd_addr(image_addr)); efi_random_get_seed(); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index cde0a2ef507d..edb77b0621ea 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -31,7 +31,6 @@ extern bool efi_nochunk; extern bool efi_nokaslr; -extern bool efi_noinitrd; extern int efi_loglevel; extern bool efi_novamap; @@ -667,6 +666,29 @@ union apple_properties_protocol { typedef u32 efi_tcg2_event_log_format; +#define INITRD_EVENT_TAG_ID 0x8F3B22ECU +#define EV_EVENT_TAG 0x00000006U +#define EFI_TCG2_EVENT_HEADER_VERSION 0x1 + +struct efi_tcg2_event { + u32 event_size; + struct { + u32 header_size; + u16 header_version; + u32 pcr_index; + u32 event_type; + } __packed event_header; + /* 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; + +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 { @@ -677,7 +699,11 @@ union efi_tcg2_protocol { efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *); - void *hash_log_extend_event; + efi_status_t (__efiapi *hash_log_extend_event)(efi_tcg2_protocol_t *, + u64, + efi_physical_addr_t, + u64, + const efi_tcg2_event_t *); void *submit_command; void *get_active_pcr_banks; void *set_active_pcr_banks; diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index f14c4ff5839f..01ddd4502e28 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -673,6 +673,7 @@ unsigned long efi_main(efi_handle_t handle, unsigned long bzimage_addr = (unsigned long)startup_32; unsigned long buffer_start, buffer_end; struct setup_header *hdr = &boot_params->hdr; + unsigned long addr, size; efi_status_t status; efi_system_table = sys_table_arg; @@ -761,22 +762,15 @@ unsigned long efi_main(efi_handle_t handle, * arguments will be processed only if image is not NULL, which will be * the case only if we were loaded via the PE entry point. */ - if (!efi_noinitrd) { - unsigned long addr, size; - - status = efi_load_initrd(image, &addr, &size, - hdr->initrd_addr_max, ULONG_MAX); - - if (status != EFI_SUCCESS) { - efi_err("Failed to load initrd!\n"); - goto fail; - } - if (size > 0) { - efi_set_u64_split(addr, &hdr->ramdisk_image, - &boot_params->ext_ramdisk_image); - efi_set_u64_split(size, &hdr->ramdisk_size, - &boot_params->ext_ramdisk_size); - } + status = efi_load_initrd(image, &addr, &size, hdr->initrd_addr_max, + ULONG_MAX); + if (status != EFI_SUCCESS) + goto fail; + if (size > 0) { + efi_set_u64_split(addr, &hdr->ramdisk_image, + &boot_params->ext_ramdisk_image); + efi_set_u64_split(size, &hdr->ramdisk_size, + &boot_params->ext_ramdisk_size); } /* diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index ad9ddefc9dcb..92a3d45a795c 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -79,6 +79,7 @@ static struct attribute *def_attrs[] = { &map_attribute_attr.attr, NULL }; +ATTRIBUTE_GROUPS(def); static const struct sysfs_ops map_attr_ops = { .show = map_attr_show, @@ -94,7 +95,7 @@ static void map_release(struct kobject *kobj) static struct kobj_type __refdata map_ktype = { .sysfs_ops = &map_attr_ops, - .default_attrs = def_attrs, + .default_groups = def_groups, .release = map_release, }; diff --git a/include/linux/efi.h b/include/linux/efi.h index ef8dbc0a1522..0de9fb1fdc5a 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -570,8 +570,8 @@ extern struct efi { unsigned long flags; } efi; -#define EFI_RT_SUPPORTED_GET_TIME 0x0001 -#define EFI_RT_SUPPORTED_SET_TIME 0x0002 +#define EFI_RT_SUPPORTED_GET_TIME 0x0001 +#define EFI_RT_SUPPORTED_SET_TIME 0x0002 #define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004 #define EFI_RT_SUPPORTED_SET_WAKEUP_TIME 0x0008 #define EFI_RT_SUPPORTED_GET_VARIABLE 0x0010 @@ -838,7 +838,7 @@ extern int efi_status_to_err(efi_status_t status); #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 #define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 -#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ +#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ EFI_VARIABLE_BOOTSERVICE_ACCESS | \ EFI_VARIABLE_RUNTIME_ACCESS | \ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ |