summaryrefslogtreecommitdiff
path: root/drivers/firmware/efi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-03-13 12:37:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-03-13 12:37:41 -0700
commit70ef654469b371d0a71bcf967fa3dcbca05d4b25 (patch)
treeec0e5a70f90fd52f4745f1a8e3a79ca2b76b8fe1 /drivers/firmware/efi
parent27b984af7a93581e59061e6c4c0c4a62d130d41d (diff)
parent021bc4b9d7ed8dcc90dc288e59f120fa6e3087dc (diff)
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
Diffstat (limited to 'drivers/firmware/efi')
-rw-r--r--drivers/firmware/efi/efi.c3
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c98
-rw-r--r--drivers/firmware/efi/libstub/efi-stub.c2
-rw-r--r--drivers/firmware/efi/libstub/efistub.h95
-rw-r--r--drivers/firmware/efi/libstub/tpm.c82
-rw-r--r--drivers/firmware/efi/libstub/x86-stub.c13
6 files changed, 226 insertions, 67 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 4fcda50acfa4..8859fb0b006d 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -597,7 +597,8 @@ static const efi_config_table_type_t common_tables[] __initconst = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, &efi_mem_attr_table, "MEMATTR" },
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, &efi_rng_seed, "RNG" },
{LINUX_EFI_TPM_EVENT_LOG_GUID, &efi.tpm_log, "TPMEventLog" },
- {LINUX_EFI_TPM_FINAL_LOG_GUID, &efi.tpm_final_log, "TPMFinalLog" },
+ {EFI_TCG2_FINAL_EVENTS_TABLE_GUID, &efi.tpm_final_log, "TPMFinalLog" },
+ {EFI_CC_FINAL_EVENTS_TABLE_GUID, &efi.tpm_final_log, "CCFinalLog" },
{LINUX_EFI_MEMRESERVE_TABLE_GUID, &mem_reserve, "MEMRESERVE" },
{LINUX_EFI_INITRD_MEDIA_GUID, &initrd, "INITRD" },
{EFI_RT_PROPERTIES_TABLE_GUID, &rt_prop, "RTPROP" },
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 3dc2f9aaf08d..de659f6a815f 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -11,6 +11,7 @@
#include <linux/efi.h>
#include <linux/kernel.h>
+#include <linux/overflow.h>
#include <asm/efi.h>
#include <asm/setup.h>
@@ -201,7 +202,7 @@ void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_si
*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 +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,
};
+ 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;
- evt->tagged_event = (struct efi_tcg2_tagged_event){
- .tagged_event_id = events[event].event_id,
- .tagged_event_data_size = events[event].event_data_len,
- };
-
- memcpy(evt->tagged_event_data, events[event].event_data,
- events[event].event_data_len);
+ efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
+ if (!cc)
+ return EFI_UNSUPPORTED;
- status = efi_call_proto(tcg2, hash_log_extend_event, 0,
- load_addr, load_size, &evt->event_data);
- efi_bs_call(free_pool, evt);
+ 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,
+ };
+ 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 --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index f9c1e8a2bd1d..958a680e0660 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -167,7 +167,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
si = setup_graphics();
- efi_retrieve_tpm2_eventlog();
+ efi_retrieve_eventlog();
/* Ask the firmware to clear memory on unclean shutdown */
efi_enable_reset_attack_mitigation();
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index fc18fd649ed7..27abb4ce0291 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -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 @@ 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 @@ static inline void
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 --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c
index 7acbac16eae0..df3182f2e63a 100644
--- a/drivers/firmware/efi/libstub/tpm.c
+++ b/drivers/firmware/efi/libstub/tpm.c
@@ -47,39 +47,18 @@ void efi_enable_reset_attack_mitigation(void)
#endif
-void efi_retrieve_tpm2_eventlog(void)
+static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_location,
+ efi_physical_addr_t log_last_entry,
+ efi_bool_t truncated,
+ struct efi_tcg2_final_events_table *final_events_table)
{
- efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
efi_status_t status;
- efi_physical_addr_t log_location = 0, log_last_entry = 0;
struct linux_efi_tpm_eventlog *log_tbl = NULL;
- struct efi_tcg2_final_events_table *final_events_table = NULL;
unsigned long first_entry_addr, last_entry_addr;
size_t log_size, last_entry_size;
- efi_bool_t truncated;
- int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
- efi_tcg2_protocol_t *tcg2_protocol = NULL;
int final_events_size = 0;
- status = efi_bs_call(locate_protocol, &tcg2_guid, NULL,
- (void **)&tcg2_protocol);
- if (status != EFI_SUCCESS)
- return;
-
- status = efi_call_proto(tcg2_protocol, get_event_log, version,
- &log_location, &log_last_entry, &truncated);
-
- if (status != EFI_SUCCESS || !log_location) {
- version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
- status = efi_call_proto(tcg2_protocol, get_event_log, version,
- &log_location, &log_last_entry,
- &truncated);
- if (status != EFI_SUCCESS || !log_location)
- return;
-
- }
-
first_entry_addr = (unsigned long) log_location;
/*
@@ -93,8 +72,10 @@ void efi_retrieve_tpm2_eventlog(void)
* get_event_log only returns the address of the last entry.
* We need to calculate its size to deduce the full size of
* the logs.
+ *
+ * CC Event log also uses TCG2 format, handle it same as TPM2.
*/
- if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
+ if (version > EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) {
/*
* The TCG2 log format has variable length entries,
* and the information to decode the hash algorithms
@@ -127,8 +108,6 @@ void efi_retrieve_tpm2_eventlog(void)
* Figure out whether any events have already been logged to the
* final events structure, and if so how much space they take up
*/
- if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
- final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID);
if (final_events_table && final_events_table->nr_events) {
struct tcg_pcr_event2_head *header;
int offset;
@@ -165,3 +144,50 @@ void efi_retrieve_tpm2_eventlog(void)
err_free:
efi_bs_call(free_pool, log_tbl);
}
+
+void efi_retrieve_eventlog(void)
+{
+ struct efi_tcg2_final_events_table *final_events_table = NULL;
+ efi_physical_addr_t log_location = 0, log_last_entry = 0;
+ efi_guid_t tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
+ int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
+ efi_tcg2_protocol_t *tpm2 = NULL;
+ efi_bool_t truncated;
+ efi_status_t status;
+
+ status = efi_bs_call(locate_protocol, &tpm2_guid, NULL, (void **)&tpm2);
+ if (status == EFI_SUCCESS) {
+ status = efi_call_proto(tpm2, get_event_log, version, &log_location,
+ &log_last_entry, &truncated);
+
+ if (status != EFI_SUCCESS || !log_location) {
+ version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ status = efi_call_proto(tpm2, get_event_log, version,
+ &log_location, &log_last_entry,
+ &truncated);
+ } else {
+ final_events_table =
+ get_efi_config_table(EFI_TCG2_FINAL_EVENTS_TABLE_GUID);
+ }
+ } else {
+ efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
+ efi_cc_protocol_t *cc = NULL;
+
+ status = efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
+ if (status != EFI_SUCCESS)
+ return;
+
+ version = EFI_CC_EVENT_LOG_FORMAT_TCG_2;
+ status = efi_call_proto(cc, get_event_log, version, &log_location,
+ &log_last_entry, &truncated);
+
+ final_events_table =
+ get_efi_config_table(EFI_CC_FINAL_EVENTS_TABLE_GUID);
+ }
+
+ if (status != EFI_SUCCESS || !log_location)
+ return;
+
+ efi_retrieve_tcg2_eventlog(version, log_location, log_last_entry,
+ truncated, final_events_table);
+}
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index 0336ed175e67..4f448d4df7b8 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -236,6 +236,15 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start,
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 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
*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,
@@ -926,7 +935,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
efi_random_get_seed();
- efi_retrieve_tpm2_eventlog();
+ efi_retrieve_eventlog();
setup_graphics(boot_params);