]> Git Repo - linux.git/commitdiff
Merge tag 'efi-next-for-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
authorLinus Torvalds <[email protected]>
Wed, 13 Mar 2024 19:37:41 +0000 (12:37 -0700)
committerLinus Torvalds <[email protected]>
Wed, 13 Mar 2024 19:37:41 +0000 (12:37 -0700)
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

1  2 
arch/x86/boot/compressed/misc.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/x86-stub.c

index 4535242cc1b102e78a20be4ff08b7f0479f78848,044e9add713d0f55ea33b7e38d0485bb15362ee7..b70e4a21c15f0e83635051226f5639be9f103910
@@@ -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) {
        /* 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");
  }
index 3dc2f9aaf08db020a74201d2462c2fd2efecef46,dbe43ffcee07cfec9bf1c82e84978a53b602d48b..de659f6a815fd479561b6d2b1939e8f6624d1b02
@@@ -11,6 -11,7 +11,7 @@@
  
  #include <linux/efi.h>
  #include <linux/kernel.h>
+ #include <linux/overflow.h>
  #include <asm/efi.h>
  #include <asm/setup.h>
  
@@@ -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;
index fc18fd649ed771a9edad143b263bd4f887f5f467,df174edfc22855d82da7022ac9c07921c49d4796..27abb4ce029173f52cf204122ddd28093ae3e023
@@@ -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 {
        } 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);
index 0336ed175e671a0ec53b8700a23addaeccddfca5,35413c8dfc251a86c5a417879261d27cb7c7c93b..4f448d4df7b822980c7cb221c281e9ed9bf74deb
@@@ -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");
  
        efi_random_get_seed();
  
-       efi_retrieve_tpm2_eventlog();
+       efi_retrieve_eventlog();
  
        setup_graphics(boot_params);
  
This page took 0.112357 seconds and 4 git commands to generate.