From patchwork Tue Sep 20 12:27:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 607809 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5826BC6FA8B for ; Tue, 20 Sep 2022 12:28:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230300AbiITM2F (ORCPT ); Tue, 20 Sep 2022 08:28:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42736 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230011AbiITM2E (ORCPT ); Tue, 20 Sep 2022 08:28:04 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D9C7E75391 for ; Tue, 20 Sep 2022 05:28:02 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 65D5662055 for ; Tue, 20 Sep 2022 12:28:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46FDBC433D7; Tue, 20 Sep 2022 12:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1663676881; bh=DZRyGE7/rIGWTDjMSq22KgTGDkZuurYQy+zWFRn5e9Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qH8NcIj8Xp+HyOtitIG9c3DdkXhrca/CdPL3SZpIrrqWIQU22PbgeKWgF75X9pItS GyIklWyf8YR829nSoky2qV8N7xcZEiMh4VpVUNV6Z8KtRXS+aLQITEjswJhZTa/LvK vbi6+S/pTKgsUNavUtBfLcRDrluMK6TwY96cQkaaNpwtZh278yZWRQZ1Efr3mcicAN qlZwCyyp2mzJyMrsuJ1h8quvmmwkethIaNPmVfXnFOQr0YQAXUTBk0BXxwmv/NKZxh gQEyzmeBbpu7e42mI29Jaf29CcCTNLMpIWnR9eeZMA73A/udiujjDxpbqqxGkzLEY2 xzvzhaTPH0QVQ== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Peter Jones , Matthew Garrett , Daniel Kiper , Ilias Apalodimas , "Xu, Min M" Subject: [PATCH v2 1/2] efi/libstub: refactor the initrd measuring functions Date: Tue, 20 Sep 2022 14:27:45 +0200 Message-Id: <20220920122746.3553306-2-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220920122746.3553306-1-ardb@kernel.org> References: <20220920122746.3553306-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5459; i=ardb@kernel.org; h=from:subject; bh=srQKs7p3PC5iOf/ljqR6rUVwt+Y767+YpdciVWnF3DM=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjKbG/eAkKO02pkR+1khnWorCaal7avQCWzQVYXACi YjMXmsWJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYymxvwAKCRDDTyI5ktmPJD/PDA CqsKNJIkIuUZbjs5A/Slc6JlfloYTx4TuqxIp4kFWmF3BUrG7J9HbEzOPlk72tV8e72SNM0/fl871/ Zl+V75GPAwHbs3c0ZahoZg4/OVXQqirvG811vBSROT8LmwkFG0wFkdi/xDVIB5eMi3EXMCAGsp+BbY jxr9mtx+GaHrVNvxfuVwyV+OS7CDcfbW8Ea/TXjUiEcV8+MDqkNTPoTTOD7m8bHm03iXYcRsiYsPyx mdxiPLerZ+BQuXRdn2juqT8p6rh+Jk64o3h8LJGSnycwUOWIe7B7kdYMKQuauxHhJg9DsIGK4Xzs6H MGXi8FLoS4HiR3eg3AgABF9zScsFE9SSmEDx3X56cw6VxkaXFBbvehXIpvFls0CjWyBr03Q4WZ3C0Z Qb5LIJ2Q0rISe7m08I/KxE4Uz7F0XYvL3H+cglCSXM+Kf1Ifx6QHaqR6sdBDZwk0ZC74wDzApOIxwX /ZD9BaG382S8az43Nz+Jl9s2pVwIjD0blaDD5d0adzl7U= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org From: Ilias Apalodimas 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 Signed-off-by: Ilias Apalodimas Signed-off-by: Ard Biesheuvel --- 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); From patchwork Tue Sep 20 12:27:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 608422 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 39C4AC6FA8E for ; Tue, 20 Sep 2022 12:28:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230353AbiITM2G (ORCPT ); Tue, 20 Sep 2022 08:28:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230333AbiITM2F (ORCPT ); Tue, 20 Sep 2022 08:28:05 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CE18275389 for ; Tue, 20 Sep 2022 05:28:04 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 63B7A61F2E for ; Tue, 20 Sep 2022 12:28:04 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4663CC433D6; Tue, 20 Sep 2022 12:28:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1663676883; bh=hOm5zcpZJLun8U4GW7Meg2Ojpzde3h4spCZwffF8n5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=URLpsWsQh6B1na7flwFziWsmFgEQhJRKdu8JF20gpkUY7lHCT2/PkA1XC4yNKEJ2M Pk5udmukcuv7wHkSTfgizjemaBHQgTm/LhEZUhFF1sy+MlvciIwh0cOONq8XqjN5CB PCNdNaRplg5l5oMd8jGHNVwNPR1BE/qTlsy7qBxpEWStlX4gPvt5KngVXQPkNB6vUp dK2lu+/O1Q68rgTyVFvEOH9wYRThdldqUXEUwmWOrdVWD8FvwdoHO9C6gBzUsZG8QW LMZwFgqUKBeTGVI0ZZbVIdpoaQG9yszpaYfWPD1eYytGI7HqAraZ2+jublEJjmj5d2 jGPfQt6XoX91A== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Peter Jones , Matthew Garrett , Daniel Kiper , Ilias Apalodimas , "Xu, Min M" Subject: [PATCH v2 2/2] efi/libstub: measure EFI LoadOptions Date: Tue, 20 Sep 2022 14:27:46 +0200 Message-Id: <20220920122746.3553306-3-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220920122746.3553306-1-ardb@kernel.org> References: <20220920122746.3553306-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3346; i=ardb@kernel.org; h=from:subject; bh=L3KrP8TAQav5SOxL416PJKl+GuaHSlN6f4btetHQnEY=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjKbHBkeOlVBWudtBigm+xWOum+xwt1qjppPqCsOHM O6DAyiqJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYymxwQAKCRDDTyI5ktmPJGAgC/ 9NJl2iZNT0cpIJ+KMFShW/t0yc/HhPlOVYUMVUT6gZZ/D45iehvIv73Ir+FKzxU4XoMf/PMzy/NFSr OHgSrBW3YL3IHrjQ+QUTuRxdMXZhKFobRMcV34A/e/TiGd2N4Axy1mUFzRL9OHVRDmuYOCMI6ktEfz aIK4bKxXBU3E6jXl3JSMPCEULtE86fIGGsBfWD4e9vhi1IykAo1m0DltRiaFws+kDHOlPM+kwulYRU Em3rI2ou97nJ1RzXS/im24Z1AeSVr2RaHuuWqkcXk0NSSx2UZUYcpE3OTF0GpFKbzTt2OKGRZkVoR5 PIRMky97Xim58FEETttkW8iy48eT1v+WvJwrExuuiHEM1DybXDRu/94iQaXajE9otAwJTXPNMtP7AW SjLCIuUZ+11TaQ4qhYX0p2cWK+SbPD7tQIV1cZblOQ4C4jnZSxq677iiHi1ITmQn8VKMy8ACgpjG9x yrC/i3oYC1XlHW+dBEKxTi3pmSS14s4XmMsK/KtYf2ebQ= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org From: Ilias Apalodimas 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 Signed-off-by: Ilias Apalodimas Signed-off-by: Ard Biesheuvel --- 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