* [PATCH v2 0/2] efi: measure kernel command line
@ 2022-09-20 12:27 Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 1/2] efi/libstub: refactor the initrd measuring functions Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 2/2] efi/libstub: measure EFI LoadOptions Ard Biesheuvel
0 siblings, 2 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2022-09-20 12:27 UTC (permalink / raw)
To: linux-efi
Cc: Ard Biesheuvel, Peter Jones, Matthew Garrett, Daniel Kiper,
Ilias Apalodimas, Xu, Min M
Measuring the kernel command line (or more generically, image load
options in EFI parlance) is not covered by the TCG spec, which only
reasons about images started as boot options.
Let's work around this oversight by measuring the kernel command line
from the EFI stub itself. Since load options is essentially just a
sequence of bytes, which happens to be interpreted as UTF-16 and
subsequently converted into ASCII before being used as the kernel
command line, let's just measure the whole thing and not the resulting
ASCII string.
Cc: Peter Jones <pjones@redhat.com>
Cc: Matthew Garrett <mjg59@google.com>
Cc: Daniel Kiper <daniel.kiper@oracle.com>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: "Xu, Min M" <min.m.xu@intel.com>
Ilias Apalodimas (2):
efi/libstub: refactor the initrd measuring functions
efi/libstub: measure EFI LoadOptions
drivers/firmware/efi/libstub/efi-stub-helper.c | 130 +++++++++++++-------
drivers/firmware/efi/libstub/efistub.h | 1 +
2 files changed, 88 insertions(+), 43 deletions(-)
--
2.35.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 1/2] efi/libstub: refactor the initrd measuring functions
2022-09-20 12:27 [PATCH v2 0/2] efi: measure kernel command line Ard Biesheuvel
@ 2022-09-20 12:27 ` Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 2/2] efi/libstub: measure EFI LoadOptions Ard Biesheuvel
1 sibling, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2022-09-20 12:27 UTC (permalink / raw)
To: linux-efi
Cc: Ard Biesheuvel, Peter Jones, Matthew Garrett, Daniel Kiper,
Ilias Apalodimas, Xu, Min M
From: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Currently, from the efi-stub, we are only measuring the loaded initrd,
using the TCG2 measured boot protocols. A following patch is
introducing measurements of additional components, such as the kernel
command line. On top of that, we will shortly have to support other
types of measured boot that don't expose the TCG2 protocols.
So let's prepare for that, by rejigging the efi_measure_initrd() routine
into something that we should be able to reuse for measuring other
assets, and which can be extended later to support other measured boot
protocols.
Co-developed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/efi-stub-helper.c | 120 +++++++++++++-------
1 file changed, 77 insertions(+), 43 deletions(-)
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 829f732c5f37..8f9a79bc4e8e 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -334,6 +334,79 @@ 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 {
+ EFISTUB_EVT_INITRD,
+ EFISTUB_EVT_COUNT,
+};
+
+#define STR_WITH_SIZE(s) sizeof(s), s
+
+static const struct {
+ u32 pcr_index;
+ u32 event_id;
+ u32 event_data_len;
+ u8 event_data[52];
+} events[] = {
+ [EFISTUB_EVT_INITRD] = {
+ 9,
+ INITRD_EVENT_TAG_ID,
+ STR_WITH_SIZE("Linux initrd")
+ },
+};
+
+static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
+ unsigned long load_size,
+ enum efistub_event event)
+{
+ 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) {
+ 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){
+ .event_size = size,
+ .event_header.header_size = sizeof(evt->event_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,
+ };
+
+ 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);
+
+ if (status != EFI_SUCCESS)
+ goto fail;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+fail:
+ efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status);
+ return status;
+}
+
/*
* Convert the unicode UEFI command line to ASCII to pass to kernel.
* Size of memory allocated return in *cmd_line_len.
@@ -626,47 +699,6 @@ 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
@@ -692,8 +724,10 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
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);
+ if (*load_size > 0 &&
+ efi_measure_tagged_event(*load_addr, *load_size,
+ EFISTUB_EVT_INITRD) == EFI_SUCCESS)
+ efi_info("Measured initrd data into PCR 9\n");
} else if (status == EFI_NOT_FOUND) {
status = efi_load_initrd_cmdline(image, load_addr, load_size,
soft_limit, hard_limit);
--
2.35.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v2 2/2] efi/libstub: measure EFI LoadOptions
2022-09-20 12:27 [PATCH v2 0/2] efi: measure kernel command line Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 1/2] efi/libstub: refactor the initrd measuring functions Ard Biesheuvel
@ 2022-09-20 12:27 ` Ard Biesheuvel
1 sibling, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2022-09-20 12:27 UTC (permalink / raw)
To: linux-efi
Cc: Ard Biesheuvel, Peter Jones, Matthew Garrett, Daniel Kiper,
Ilias Apalodimas, Xu, Min M
From: Ilias Apalodimas <ilias.apalodimas@linaro.org>
The EFI TCG spec, in §10.2.6 "Measuring UEFI Variables and UEFI GPT
Data", only reasons about the load options passed to a loaded image in
the context of boot options booted directly from the BDS, which are
measured into PCR #5 along with the rest of the Boot#### EFI variable.
However, the UEFI spec mentions the following in the documentation of
the LoadImage() boot service and the EFI_LOADED_IMAGE protocol:
The caller may fill in the image’s "load options" data, or add
additional protocol support to the handle before passing control to
the newly loaded image by calling EFI_BOOT_SERVICES.StartImage().
The typical boot sequence for Linux EFI systems is to load GRUB via a
boot option from the BDS, which [hopefully] calls LoadImage to load the
kernel image, passing the kernel command line via the mechanism
described above. This means that we cannot rely on the firmware
implementing TCG measured boot to ensure that the kernel command line
gets measured before the image is started, so the EFI stub will have to
take care of this itself.
Given that PCR #5 has an official use in the TCG measured boot spec,
let's avoid it in this case. Instead, add a measurement in PCR #9 (which
we already use for our initrd) and extend it with the LoadOptions
measurements
Co-developed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/efi-stub-helper.c | 10 ++++++++++
drivers/firmware/efi/libstub/efistub.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 8f9a79bc4e8e..c26c59a69c76 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -336,6 +336,7 @@ void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_si
enum efistub_event {
EFISTUB_EVT_INITRD,
+ EFISTUB_EVT_LOAD_OPTIONS,
EFISTUB_EVT_COUNT,
};
@@ -352,6 +353,11 @@ static const struct {
INITRD_EVENT_TAG_ID,
STR_WITH_SIZE("Linux initrd")
},
+ [EFISTUB_EVT_LOAD_OPTIONS] = {
+ 9,
+ LOAD_OPTIONS_EVENT_TAG_ID,
+ STR_WITH_SIZE("LOADED_IMAGE::LoadOptions")
+ },
};
static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
@@ -423,6 +429,10 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
efi_status_t status;
u32 options_chars;
+ if (options_size > 0)
+ efi_measure_tagged_event((unsigned long)options, options_size,
+ EFISTUB_EVT_LOAD_OPTIONS);
+
efi_apply_loadoptions_quirk((const void **)&options, &options_size);
options_chars = options_size / sizeof(efi_char16_t);
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 02fb5f7c8eff..8ad6705b555e 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -762,6 +762,7 @@ union apple_properties_protocol {
typedef u32 efi_tcg2_event_log_format;
#define INITRD_EVENT_TAG_ID 0x8F3B22ECU
+#define LOAD_OPTIONS_EVENT_TAG_ID 0x8F3B22EDU
#define EV_EVENT_TAG 0x00000006U
#define EFI_TCG2_EVENT_HEADER_VERSION 0x1
--
2.35.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2022-09-20 12:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-09-20 12:27 [PATCH v2 0/2] efi: measure kernel command line Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 1/2] efi/libstub: refactor the initrd measuring functions Ard Biesheuvel
2022-09-20 12:27 ` [PATCH v2 2/2] efi/libstub: measure EFI LoadOptions Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox