From patchwork Fri Feb 22 20:26:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10826951 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 06B791805 for ; Fri, 22 Feb 2019 20:26:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EDAC03293A for ; Fri, 22 Feb 2019 20:26:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EBE0E328CC; Fri, 22 Feb 2019 20:26:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5FC513294E for ; Fri, 22 Feb 2019 20:26:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726975AbfBVU0R (ORCPT ); Fri, 22 Feb 2019 15:26:17 -0500 Received: from mail-pg1-f201.google.com ([209.85.215.201]:57342 "EHLO mail-pg1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726955AbfBVU0Q (ORCPT ); Fri, 22 Feb 2019 15:26:16 -0500 Received: by mail-pg1-f201.google.com with SMTP id d3so2458702pgv.23 for ; Fri, 22 Feb 2019 12:26:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=PIskTotTS30my00PpyuDNjp7J1bfei86ZvMSyGFT+Tk=; b=rB/3gxjtk7QInhP1fGU8s+7yNH6+fpF0d5AA0bKpDTTw8lDg0EsawLZWApduXgPYNg 8Pp6j6FKF6wRBUiPMKzRMczZu9t5SRqDs0T1Z5bo3/ARbTqLGK0waiVl8xMr+1pT+4GK ahvQH0BMa6XLYz+5fmSqFHxEGyDIZ8sgviV3I68okHCOSlkUAJxihw6Ce9WsNogzu5Kd 1NTw+nHvBqWbsHu0YN2DhmC0lU5ReT4DLgrsQpyfYXQKQ49jxjyYhybtMlfQ2wqE20n1 eQ0VE1cdXUmhXRuJE8i73SWMG+RuWeScAXSDX6CK9xbiZAGY6qVC1B5hoX7pcov4F6n4 nRWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=PIskTotTS30my00PpyuDNjp7J1bfei86ZvMSyGFT+Tk=; b=Zf3TTVWIjHZhrt5LJbH3sGAwqUx+9GUTPNu8ZTbCbjUZHfzup1LIOpXR70cN380mNw cAYSVykPD/gldjdvPThLJkEiaMZw3+pLhUZ8rHYDMGouxmhTi5FAKxAGABxIWBZx0AvN ZUVcq0oIEpK+EYqmCOB0CzLoKA1rnQY7rY4E83O8dTcMLAEQlbIAlSHoO+GZYpE9Wt58 gIpOQT+8QAH/Cxt0xCJAi3NHUScdIMak/L1LBMdG7ujOze4jDaewRUvhGmTslPiep5Pw SzLdN7Q9VwLIK/VVKhLC/sEUJa34+g6aNIfgXGJa2sLX4GScwCNYhjROsqtUN+P/4OCO Tmuw== X-Gm-Message-State: AHQUAubFiJHmv/dJcA1YnsQrCPJlDR3kLEVahadCB7beq1KXm5dCjAeb qKE/nSdTAffQ3ebVP91dRm8Yfe43l7+7rjaXsmE74A== X-Google-Smtp-Source: AHgI3IbrUQQy7H+Rwm147t40V6tiYOdDt8xad6imXP9blhPLdeTT8QyWUi2atbMieXcz40bMPiRoSjJNMxNHsA0Vw4GD9Q== X-Received: by 2002:a17:902:bc49:: with SMTP id t9mr1867783plz.70.1550867174986; Fri, 22 Feb 2019 12:26:14 -0800 (PST) Date: Fri, 22 Feb 2019 12:26:03 -0800 In-Reply-To: <20190222202606.160816-1-matthewgarrett@google.com> Message-Id: <20190222202606.160816-2-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190222202606.160816-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc0.258.g878e2cd30e-goog Subject: [PATCH V4 1/4] tpm: Abstract crypto agile event size calculations From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: peterhuewe@gmx.de, jarkko.sakkinen@linux.intel.com, jgg@ziepe.ca, roberto.sassu@huawei.com, linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, tweek@google.com, Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett We need to calculate the size of crypto agile events in multiple locations, including in the EFI boot stub. The easiest way to do this is to put it in a header file as an inline and leave a wrapper to ensure we don't end up with multiple copies of it embedded in the existing code. Signed-off-by: Matthew Garrett --- drivers/char/tpm/eventlog/tpm2.c | 47 +--------------------- include/linux/tpm_eventlog.h | 68 ++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 46 deletions(-) diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c index d8b77133a83a..dc12e1cbd03a 100644 --- a/drivers/char/tpm/eventlog/tpm2.c +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -40,52 +40,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2_head *event, struct tcg_pcr_event *event_header) { - struct tcg_efi_specid_event_head *efispecid; - struct tcg_event_field *event_field; - void *marker; - void *marker_start; - u32 halg_size; - size_t size; - u16 halg; - int i; - int j; - - marker = event; - marker_start = marker; - marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) - + sizeof(event->count); - - efispecid = (struct tcg_efi_specid_event_head *)event_header->event; - - /* Check if event is malformed. */ - if (event->count > efispecid->num_algs) - return 0; - - for (i = 0; i < event->count; i++) { - halg_size = sizeof(event->digests[i].alg_id); - memcpy(&halg, marker, halg_size); - marker = marker + halg_size; - for (j = 0; j < efispecid->num_algs; j++) { - if (halg == efispecid->digest_sizes[j].alg_id) { - marker += - efispecid->digest_sizes[j].digest_size; - break; - } - } - /* Algorithm without known length. Such event is unparseable. */ - if (j == efispecid->num_algs) - return 0; - } - - event_field = (struct tcg_event_field *)marker; - marker = marker + sizeof(event_field->event_size) - + event_field->event_size; - size = marker - marker_start; - - if ((event->event_type == 0) && (event_field->event_size == 0)) - return 0; - - return size; + return __calc_tpm2_event_size(event, event_header); } static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h index f47342361e87..09c19d506b69 100644 --- a/include/linux/tpm_eventlog.h +++ b/include/linux/tpm_eventlog.h @@ -117,4 +117,72 @@ struct tcg_pcr_event2_head { struct tpm2_digest digests[]; } __packed; +/** + * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry + * @event: Pointer to the event whose size should be calculated + * @event_header: Pointer to the initial event containing the digest lengths + * + * The TPM2 event log format can contain multiple digests corresponding to + * separate PCR banks, and also contains a variable length of the data that + * was measured. This requires knowledge of how long each digest type is, + * and this information is contained within the first event in the log. + * + * We calculate the length by examining the number of events, and then looking + * at each event in turn to determine how much space is used for events in + * total. Once we've done this we know the offset of the data length field, + * and can calculate the total size of the event. + * + * Return: size of the event on success, <0 on failure + */ + +static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event, + struct tcg_pcr_event *event_header) +{ + struct tcg_efi_specid_event_head *efispecid; + struct tcg_event_field *event_field; + void *marker; + void *marker_start; + u32 halg_size; + size_t size; + u16 halg; + int i; + int j; + + marker = event; + marker_start = marker; + marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) + + sizeof(event->count); + + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; + + /* Check if event is malformed. */ + if (event->count > efispecid->num_algs) + return 0; + + for (i = 0; i < event->count; i++) { + halg_size = sizeof(event->digests[i].alg_id); + memcpy(&halg, marker, halg_size); + marker = marker + halg_size; + for (j = 0; j < efispecid->num_algs; j++) { + if (halg == efispecid->digest_sizes[j].alg_id) { + marker += + efispecid->digest_sizes[j].digest_size; + break; + } + } + /* Algorithm without known length. Such event is unparseable. */ + if (j == efispecid->num_algs) + return 0; + } + + event_field = (struct tcg_event_field *)marker; + marker = marker + sizeof(event_field->event_size) + + event_field->event_size; + size = marker - marker_start; + + if ((event->event_type == 0) && (event_field->event_size == 0)) + return 0; + + return size; +} #endif From patchwork Fri Feb 22 20:26:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10826953 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A323B14E1 for ; Fri, 22 Feb 2019 20:26:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8F1AE28515 for ; Fri, 22 Feb 2019 20:26:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 80D983285B; Fri, 22 Feb 2019 20:26:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A89D932839 for ; Fri, 22 Feb 2019 20:26:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727184AbfBVU0T (ORCPT ); Fri, 22 Feb 2019 15:26:19 -0500 Received: from mail-qt1-f202.google.com ([209.85.160.202]:43519 "EHLO mail-qt1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727065AbfBVU0T (ORCPT ); Fri, 22 Feb 2019 15:26:19 -0500 Received: by mail-qt1-f202.google.com with SMTP id m37so3136114qte.10 for ; Fri, 22 Feb 2019 12:26:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=21HOYtxw/AyWaX/u7SeNBmxdIR0I1nG8vfqFGwjLU2g=; b=CJj68MuZLGcIV/kuXVtAeL7fGOmMCt2lwCz7qXmqSWWPcrlC6qRKlHrHPpy/SN7W/p KW2u6LT+sNgkGoHc3nh/L2Sm3DWIo4FDyyYcOqLTGezp167t45zYyfZCVSXCcU49vcVJ pLtz5Muqo1fXr0iAyOClwGM/3uOA4jmUP8IiEQBwv5JrKYrUKtmOsN0CUvA2yksSpMzB J2bcNszK+GKLa89/j18PFsEQ3hlgjvxiTMrFHjokVBDiOFUcqnpL+VSZ6xYyZFx3HuCs vFEZ5bqOJuRsE+QJWGE7ou7wAoyK/O4TgkjtXlf/iipurai3zLjG08Szp6rMOLcYui5I oGEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=21HOYtxw/AyWaX/u7SeNBmxdIR0I1nG8vfqFGwjLU2g=; b=emocw/iv7DV0Fv7CjlfevJpsKocNio/Hduy+oaK5pW3mjmUlmqPu+08v0YMn8Nx0wL tpd1OXGfqXFxFmxZrNqhKpbUi3RpiFo9lFo72REqDgPOt2YylLvzhagqcdOiVDS/KGtk 7z47BCYdna84VkS6UYdQvNlabwu8B3GFAwPbM0Jdqjjx0YIveB2X02H3GsXI6TBS0ue6 ApOZfIWR4PCag1NLAemvwcGDBvdxnC1GJowjkkUdDdUEhNB4JeqUF8CMuSG0kHC5YKVt Wi79er8MQlEKLbGSW0N9JGHyzVFO9ERtEQPHQcnUcxJzgTKlhIjj37Z8MRXCgN47g/+g HQJw== X-Gm-Message-State: AHQUAubpT1drFNnlmv0KxuQ725vxzu4koO4ZntOBGUgMimS5VD8lFI41 bQ27gV7mmAjxAHDmpuMf+9g7Ftjs9w//kF7iKQI/3Q== X-Google-Smtp-Source: AHgI3IbpHc4yesO6blGpRy1zQcXyhP8YMu8gm9SVD/PwuDpyVGnDyuut7Q22gYFP5y0YY6GG27xXS+XCw3xKLbbICSEbWQ== X-Received: by 2002:a0c:98bd:: with SMTP id f58mr3413944qvd.6.1550867177575; Fri, 22 Feb 2019 12:26:17 -0800 (PST) Date: Fri, 22 Feb 2019 12:26:04 -0800 In-Reply-To: <20190222202606.160816-1-matthewgarrett@google.com> Message-Id: <20190222202606.160816-3-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190222202606.160816-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc0.258.g878e2cd30e-goog Subject: [PATCH V4 2/4] tpm: Reserve the TPM final events table From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: peterhuewe@gmx.de, jarkko.sakkinen@linux.intel.com, jgg@ziepe.ca, roberto.sassu@huawei.com, linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, tweek@google.com, Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett UEFI systems provide a boot services protocol for obtaining the TPM event log, but this is unusable after ExitBootServices() is called. Unfortunately ExitBootServices() itself triggers additional TPM events that then can't be obtained using this protocol. The platform provides a mechanism for the OS to obtain these events by recording them to a separate UEFI configuration table which the OS can then map. Unfortunately this table isn't self describing in terms of providing its length, so we need to parse the events inside it to figure out how long it is. Since the table isn't mapped at this point, we need to extend the length calculation function to be able to map the event as it goes along. Signed-off-by: Matthew Garrett --- drivers/char/tpm/eventlog/tpm2.c | 2 +- drivers/firmware/efi/efi.c | 2 + drivers/firmware/efi/tpm.c | 51 ++++++++++++++++- include/linux/efi.h | 9 +++ include/linux/tpm_eventlog.h | 94 +++++++++++++++++++++++++++++--- 5 files changed, 148 insertions(+), 10 deletions(-) diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c index dc12e1cbd03a..2cfdf1db4363 100644 --- a/drivers/char/tpm/eventlog/tpm2.c +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -40,7 +40,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2_head *event, struct tcg_pcr_event *event_header) { - return __calc_tpm2_event_size(event, event_header); + return __calc_tpm2_event_size(event, event_header, false); } static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 55b77c576c42..6b11c41e0575 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -53,6 +53,7 @@ struct efi __read_mostly efi = { .mem_attr_table = EFI_INVALID_TABLE_ADDR, .rng_seed = EFI_INVALID_TABLE_ADDR, .tpm_log = EFI_INVALID_TABLE_ADDR, + .tpm_final_log = EFI_INVALID_TABLE_ADDR, .mem_reserve = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -485,6 +486,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, + {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log}, {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, {NULL_GUID, NULL, NULL}, }; diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c index 0cbeb3d46b18..2ccaa6661aaf 100644 --- a/drivers/firmware/efi/tpm.c +++ b/drivers/firmware/efi/tpm.c @@ -10,24 +10,50 @@ #include #include #include +#include #include +int efi_tpm_final_log_size; +EXPORT_SYMBOL(efi_tpm_final_log_size); + +static int tpm2_calc_event_log_size(void *data, int count, void *size_info) +{ + struct tcg_pcr_event2_head *header; + int event_size, size = 0; + + while (count > 0) { + header = data + size; + event_size = __calc_tpm2_event_size(header, size_info, true); + if (event_size == 0) + return -1; + size += event_size; + } + + return size; +} + /* * Reserve the memory associated with the TPM Event Log configuration table. */ int __init efi_tpm_eventlog_init(void) { struct linux_efi_tpm_eventlog *log_tbl; + struct efi_tcg2_final_events_table *final_tbl; unsigned int tbl_size; - if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) { + /* + * We can't calculate the size of the final events without the + * first entry in the TPM log, so bail here. + */ return 0; + } log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); if (!log_tbl) { pr_err("Failed to map TPM Event Log table @ 0x%lx\n", - efi.tpm_log); + efi.tpm_log); efi.tpm_log = EFI_INVALID_TABLE_ADDR; return -ENOMEM; } @@ -35,6 +61,27 @@ int __init efi_tpm_eventlog_init(void) tbl_size = sizeof(*log_tbl) + log_tbl->size; memblock_reserve(efi.tpm_log, tbl_size); early_memunmap(log_tbl, sizeof(*log_tbl)); + + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) + return 0; + + final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); + + if (!final_tbl) { + pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n", + efi.tpm_final_log); + efi.tpm_final_log = EFI_INVALID_TABLE_ADDR; + return -ENOMEM; + } + + tbl_size = tpm2_calc_event_log_size(final_tbl->events, + final_tbl->nr_events, + (void *)efi.tpm_log); + memblock_reserve((unsigned long)final_tbl, + tbl_size + sizeof(*final_tbl)); + early_memunmap(final_tbl, sizeof(*final_tbl)); + efi_tpm_final_log_size = tbl_size; + return 0; } diff --git a/include/linux/efi.h b/include/linux/efi.h index 28604a8d0aa9..ee8d820a4943 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -676,6 +676,7 @@ void efi_native_runtime_setup(void); #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) #define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa) +#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25) #define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2) typedef struct { @@ -983,6 +984,7 @@ extern struct efi { unsigned long mem_attr_table; /* memory attributes table */ unsigned long rng_seed; /* UEFI firmware random seed */ unsigned long tpm_log; /* TPM2 Event Log table */ + unsigned long tpm_final_log; /* TPM2 Final Events Log table */ unsigned long mem_reserve; /* Linux EFI memreserve table */ efi_get_time_t *get_time; efi_set_time_t *set_time; @@ -1693,6 +1695,13 @@ struct linux_efi_tpm_eventlog { extern int efi_tpm_eventlog_init(void); +struct efi_tcg2_final_events_table { + u64 version; + u64 nr_events; + u8 events[]; +}; +extern int efi_tpm_final_log_size; + /* * efi_runtime_service() function identifiers. * "NONE" is used by efi_recover_from_page_fault() to check if the page diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h index 09c19d506b69..dccc97e6135c 100644 --- a/include/linux/tpm_eventlog.h +++ b/include/linux/tpm_eventlog.h @@ -117,10 +117,27 @@ struct tcg_pcr_event2_head { struct tpm2_digest digests[]; } __packed; +struct tcg_algorithm_size { + u16 algorithm_id; + u16 algorithm_size; +}; + +struct tcg_algorithm_info { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintn_size; + u32 number_of_algorithms; + struct tcg_algorithm_size digest_sizes[]; +}; + /** * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry * @event: Pointer to the event whose size should be calculated * @event_header: Pointer to the initial event containing the digest lengths + * @do_mapping: Whether or not the event needs to be mapped * * The TPM2 event log format can contain multiple digests corresponding to * separate PCR banks, and also contains a variable length of the data that @@ -136,10 +153,13 @@ struct tcg_pcr_event2_head { */ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event, - struct tcg_pcr_event *event_header) + struct tcg_pcr_event *event_header, + bool do_mapping) { struct tcg_efi_specid_event_head *efispecid; struct tcg_event_field *event_field; + void *mapping = NULL; + int mapping_size; void *marker; void *marker_start; u32 halg_size; @@ -153,36 +173,96 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event, marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) + sizeof(event->count); + /* Map the event header */ + if (do_mapping) { + mapping_size = marker - marker_start; + mapping = early_memremap((unsigned long)marker_start, + mapping_size); + if (!mapping) { + size = 0; + goto out; + } + } + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; /* Check if event is malformed. */ - if (event->count > efispecid->num_algs) - return 0; + if (event->count > efispecid->num_algs) { + size = 0; + goto out; + } for (i = 0; i < event->count; i++) { halg_size = sizeof(event->digests[i].alg_id); + + /* Map the digest's algorithm identifier */ + if (do_mapping) { + early_memunmap(mapping, mapping_size); + mapping_size = marker - marker_start + halg_size; + mapping = early_memremap((unsigned long)marker_start, + mapping_size); + if (!mapping) { + size = 0; + goto out; + } + } + memcpy(&halg, marker, halg_size); marker = marker + halg_size; + for (j = 0; j < efispecid->num_algs; j++) { if (halg == efispecid->digest_sizes[j].alg_id) { marker += efispecid->digest_sizes[j].digest_size; + + /* Map the digest content itself */ + if (do_mapping) { + early_memunmap(mapping, mapping_size); + mapping_size = marker - marker_start; + mapping = early_memremap((unsigned long)marker_start, + mapping_size); + if (!mapping) { + size = 0; + goto out; + } + } break; } } /* Algorithm without known length. Such event is unparseable. */ - if (j == efispecid->num_algs) - return 0; + if (j == efispecid->num_algs) { + size = 0; + goto out; + } } event_field = (struct tcg_event_field *)marker; + + /* + * Map the event size - we don't read from the event itself, so + * we don't need to map it + */ + if (do_mapping) { + early_memunmap(marker_start, mapping_size); + mapping_size += sizeof(event_field->event_size); + mapping = early_memremap((unsigned long)marker_start, + mapping_size); + if (!mapping) { + size = 0; + goto out; + } + } + marker = marker + sizeof(event_field->event_size) + event_field->event_size; size = marker - marker_start; if ((event->event_type == 0) && (event_field->event_size == 0)) - return 0; - + size = 0; +out: + if (do_mapping) + early_memunmap(mapping, mapping_size); return size; } + #endif From patchwork Fri Feb 22 20:26:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10826963 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 677B71575 for ; Fri, 22 Feb 2019 20:26:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5AF2632841 for ; Fri, 22 Feb 2019 20:26:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4FC0A328B7; Fri, 22 Feb 2019 20:26:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E57FC32869 for ; Fri, 22 Feb 2019 20:26:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727310AbfBVU0e (ORCPT ); Fri, 22 Feb 2019 15:26:34 -0500 Received: from mail-ua1-f73.google.com ([209.85.222.73]:52114 "EHLO mail-ua1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727219AbfBVU0V (ORCPT ); Fri, 22 Feb 2019 15:26:21 -0500 Received: by mail-ua1-f73.google.com with SMTP id j2so648152uap.18 for ; Fri, 22 Feb 2019 12:26:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=8ZLu9apGJq8gMxM5fACckAPsW9cvH79FQBy+6X2uyc4=; b=jjk9Y0DSJr31PAijE1VAhzeYGJwQBiuw4R13Y+cM2jKBQWe7RFRRzTRWqyb0AQhqd8 tOalXyt8ulNJgbQBaV915incR5EvtBoFKTx2KRjMcK40a4Swexf1RR+lyDZwcPR0xZHZ pk3B9oAx/m1niI99/67S94VbZIdEdcxWCiLKwOZ0TDFjtnV5CJ8YUe29uUmgloHE7ZWh c/Q2SMU77B+TWlewVizz6l3TTnmfjnsQlTydvywAtTjmaikZmhz9zZFM+KB5Rcw0N+GU zjYUsgXdUWZzur4GTYlCNlu19siCy8VDEjmFzBAjj/T1HPWc9GVEkYCCwHldooZfQuxj GG0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=8ZLu9apGJq8gMxM5fACckAPsW9cvH79FQBy+6X2uyc4=; b=boE4rybeFYid1L7ETfODG44ILFxsVt/BuixSc3Tj0LhULJwmP30x1Lg2RxQaU2GLMI io0GG/1HuaLbvaze9LyJ71DD4Xo0dFo0q76RIUG7qOpQg5HvHNM7EMjq8PcuYuRAxiwV 0tq91PcIjkIHBZJxRNntRziGDzwuTqusOK5It9KZ/Td4HKRRY8awQDX/hWL26Pbz/s1P D/H2OtmZZ+s5ZUxO5YXQvHKINlnUtcDkSAdciGqZ78MKfJzkdwJmPi9QdnLpZCEbmvWL o7HmTOta2ik08jLVIMCw0Z/qYfm2b+rk8iTxnYEeo3CnTHKCSkptoT4Kd2lYzWdM8yMj LK6w== X-Gm-Message-State: AHQUAuZ9f7wND5fmW70cudT79L1YASZbP/d1xrnC69WjlJ+rH9bll/rf lFFWThFr26Vni4egWeq7KtA7GQu1ZAqb+F0R8eqzAA== X-Google-Smtp-Source: AHgI3IbxQ+WnEa1/boPr02rjPJvsi/TF2O3WIyWJ2V88tbL2ZfaXand/Xu/BuwpCrTw/FKj2l4P2xXsSmArD5SMITXRi0w== X-Received: by 2002:a1f:9750:: with SMTP id z77mr196035vkd.5.1550867180288; Fri, 22 Feb 2019 12:26:20 -0800 (PST) Date: Fri, 22 Feb 2019 12:26:05 -0800 In-Reply-To: <20190222202606.160816-1-matthewgarrett@google.com> Message-Id: <20190222202606.160816-4-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190222202606.160816-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc0.258.g878e2cd30e-goog Subject: [PATCH V4 3/4] tpm: Append the final event log to the TPM event log From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: peterhuewe@gmx.de, jarkko.sakkinen@linux.intel.com, jgg@ziepe.ca, roberto.sassu@huawei.com, linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, tweek@google.com, Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett Any events that are logged after GetEventsLog() is called are logged to the EFI Final Events table. These events are defined as being in the crypto agile log format, so we can just append them directly to the existing log if it's in the same format. In theory we can also construct old-style SHA1 log entries for devices that only return logs in that format, but EDK2 doesn't generate the final event log in that case so it doesn't seem worth it at the moment. Signed-off-by: Matthew Garrett --- drivers/char/tpm/eventlog/efi.c | 50 ++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c index 3e673ab22cb4..9179cf6bdee9 100644 --- a/drivers/char/tpm/eventlog/efi.c +++ b/drivers/char/tpm/eventlog/efi.c @@ -21,10 +21,13 @@ int tpm_read_log_efi(struct tpm_chip *chip) { + struct efi_tcg2_final_events_table *final_tbl = NULL; struct linux_efi_tpm_eventlog *log_tbl; struct tpm_bios_log *log; u32 log_size; u8 tpm_log_version; + void *tmp; + int ret; if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; @@ -52,15 +55,48 @@ int tpm_read_log_efi(struct tpm_chip *chip) /* malloc EventLog space */ log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL); - if (!log->bios_event_log) - goto err_memunmap; - log->bios_event_log_end = log->bios_event_log + log_size; + if (!log->bios_event_log) { + ret = -ENOMEM; + goto out; + } + log->bios_event_log_end = log->bios_event_log + log_size; tpm_log_version = log_tbl->version; - memunmap(log_tbl); - return tpm_log_version; -err_memunmap: + ret = tpm_log_version; + + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || + efi_tpm_final_log_size == 0 || + tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + goto out; + + final_tbl = memremap(efi.tpm_final_log, + sizeof(*final_tbl) + efi_tpm_final_log_size, + MEMREMAP_WB); + if (!final_tbl) { + pr_err("Could not map UEFI TPM final log\n"); + kfree(log->bios_event_log); + ret = -ENOMEM; + goto out; + } + + tmp = krealloc(log->bios_event_log, + log_size + efi_tpm_final_log_size, + GFP_KERNEL); + if (!tmp) { + kfree(log->bios_event_log); + ret = -ENOMEM; + goto out; + } + + log->bios_event_log = tmp; + memcpy((void *)log->bios_event_log + log_size, + final_tbl->events, efi_tpm_final_log_size); + log->bios_event_log_end = log->bios_event_log + + log_size + efi_tpm_final_log_size; + +out: + memunmap(final_tbl); memunmap(log_tbl); - return -ENOMEM; + return ret; } From patchwork Fri Feb 22 20:26:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10826955 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8427C14E1 for ; Fri, 22 Feb 2019 20:26:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C91232841 for ; Fri, 22 Feb 2019 20:26:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6113B3294F; Fri, 22 Feb 2019 20:26:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D9E3B32841 for ; Fri, 22 Feb 2019 20:26:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727269AbfBVU0Y (ORCPT ); Fri, 22 Feb 2019 15:26:24 -0500 Received: from mail-qk1-f202.google.com ([209.85.222.202]:44585 "EHLO mail-qk1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727287AbfBVU0Y (ORCPT ); Fri, 22 Feb 2019 15:26:24 -0500 Received: by mail-qk1-f202.google.com with SMTP id e9so2423684qka.11 for ; Fri, 22 Feb 2019 12:26:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=QdqoL0K3zxFFGbmlyhBJxqAUmz+voVFPYJ0GB3SWvlY=; b=s1mHfRL+EDTU5WJMCV1wxupbcwVVB2OrrhGchRt5aCjj1ppa4myp4g5/p3mFBP/WCD rHK13sQYsXjNwu7nI+WX9gPhgpsfRreXtmCTw0dSyjYENcU6RFZI61hu0RFGVVDln9pt HOy26IrEpNsZeBRzUK2IJVRtdtTwvEKH3CHMLotGuKpPfZCSMMeXLIRlbG6vuU8BAKpq ui4n6yntzHt5j8jf0ulu04Hz0/KJ2rcBG/0t5PZ9rxU8hbMXHjUKwV7W/HP7fY1hqSxS DehwscNHkKhngiPM9A2H/57/h6oYyeQ+6BsfHHTVVFoiYzoK4EoP2XbXjFHTL1iLysmR u6ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=QdqoL0K3zxFFGbmlyhBJxqAUmz+voVFPYJ0GB3SWvlY=; b=ouIKhZNge6Jnv0SdM/LdtL1sSyTuIaTmUjrRimxAwxXmnBIlYydxl7QFK1W8CdWQdX eSH8y7upzr2lpC1ZQpuJvO5CzeX/Lm8HLc1mfbR746Tb6NUY2+VW6T/INiOdpTMZr8tX j6av6yrxoFshAE00FVnG65Uyh7moT+S9Zo6sQQwgOOMOuUKGY7rqAX8rp6ItoAzk0B9E o6n381tbvzY6ZvvWIzRytJT+p/u7a9juWl87Qaxmv1LYyFZlKpqzXEGX4tvxXegObCSW xTVh1B9xnOOan/AuK/PH5wiAMVaouJ/whobitmvdL+KUbh4eEnruFWxq3YDDRjJ96IpE Cpyg== X-Gm-Message-State: AHQUAuZum4QCWbwQjqo6kH9GtTmic99GnJnnL9DFeNgeGyuj9FevGkh6 s/lfS/TAEi6FzKrq5GSl6vMnAjxv7Xhtw1YlR0QouQ== X-Google-Smtp-Source: AHgI3IZ6hRQOpgvZQ7RZTDBrH6MpRsUnwB5Cm2xa4JwoZXOgxyM0uZaoo6PmI7/4HwRZladXWq0OXWEQpbpV0NseTkt1eg== X-Received: by 2002:a37:d654:: with SMTP id t81mr3541286qki.4.1550867182796; Fri, 22 Feb 2019 12:26:22 -0800 (PST) Date: Fri, 22 Feb 2019 12:26:06 -0800 In-Reply-To: <20190222202606.160816-1-matthewgarrett@google.com> Message-Id: <20190222202606.160816-5-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190222202606.160816-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc0.258.g878e2cd30e-goog Subject: [PATCH V4 4/4] efi: Attempt to get the TCG2 event log in the boot stub From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: peterhuewe@gmx.de, jarkko.sakkinen@linux.intel.com, jgg@ziepe.ca, roberto.sassu@huawei.com, linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, tweek@google.com, Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett Right now we only attempt to obtain the SHA1-only event log. The protocol also supports a crypto agile log format, which contains digests for all algorithms in use. Attempt to obtain this first, and fall back to obtaining the older format if the system doesn't support it. This is lightly complicated by the event sizes being variable (as we don't know in advance which algorithms are in use), and the interface giving us back a pointer to the start of the final entry rather than a pointer to the end of the log - as a result, we need to parse the final entry to figure out its length in order to know how much data to copy up to the OS. Signed-off-by: Matthew Garrett --- drivers/firmware/efi/libstub/tpm.c | 50 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index a90b0b8fc69a..523cd07c551c 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -59,7 +59,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) #endif -static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) { efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; @@ -69,6 +69,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) 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; void *tcg2_protocol = NULL; status = efi_call_early(locate_protocol, &tcg2_guid, NULL, @@ -76,14 +77,20 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) if (status != EFI_SUCCESS) return; - status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, - EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, - &log_location, &log_last_entry, &truncated); - if (status != EFI_SUCCESS) - return; + status = efi_call_proto(efi_tcg2_protocol, get_event_log, + tcg2_protocol, 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(efi_tcg2_protocol, get_event_log, + tcg2_protocol, version, &log_location, + &log_last_entry, &truncated); + if (status != EFI_SUCCESS || !log_location) + return; + + } - if (!log_location) - return; first_entry_addr = (unsigned long) log_location; /* @@ -98,8 +105,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) * We need to calculate its size to deduce the full size of * the logs. */ - last_entry_size = sizeof(struct tcpa_event) + - ((struct tcpa_event *) last_entry_addr)->event_size; + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { + /* + * The TCG2 log format has variable length entries, + * and the information to decode the hash algorithms + * back into a size is contained in the first entry - + * pass a pointer to the final entry (to calculate its + * size) and the first entry (so we know how long each + * digest is) + */ + last_entry_size = + __calc_tpm2_event_size((void *)last_entry_addr, + (void *)log_location, + false); + } else { + last_entry_size = sizeof(struct tcpa_event) + + ((struct tcpa_event *) last_entry_addr)->event_size; + } log_size = log_last_entry - log_location + last_entry_size; } @@ -116,7 +138,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) memset(log_tbl, 0, sizeof(*log_tbl) + log_size); log_tbl->size = log_size; - log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + log_tbl->version = version; memcpy(log_tbl->log, (void *) first_entry_addr, log_size); status = efi_call_early(install_configuration_table, @@ -128,9 +150,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) err_free: efi_call_early(free_pool, log_tbl); } - -void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) -{ - /* Only try to retrieve the logs in 1.2 format. */ - efi_retrieve_tpm2_eventlog_1_2(sys_table_arg); -}