From patchwork Tue Jan 21 20:01:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226747 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFs0YGwz9sRW for ; Wed, 22 Jan 2020 07:02:41 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFs03c0zDqSc for ; Wed, 22 Jan 2020 07:02:41 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF445kpzDqPf for ; Wed, 22 Jan 2020 07:02:00 +1100 (AEDT) Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqnS7130365; Tue, 21 Jan 2020 15:01:57 -0500 Received: from ppma01dal.us.ibm.com (83.d6.3fa9.ip4.static.sl-reverse.com [169.63.214.131]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xp0s788fd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:56 -0500 Received: from pps.filterd (ppma01dal.us.ibm.com [127.0.0.1]) by ppma01dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK0nrs023411; Tue, 21 Jan 2020 20:01:55 GMT Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by ppma01dal.us.ibm.com with ESMTP id 2xksn6p43b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:55 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1soU59048304 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:54 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6683D6A051; Tue, 21 Jan 2020 20:01:54 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CFADF6A05A; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:47 -0500 Message-Id: <20200121200147.1002075-9-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 priorityscore=1501 suspectscore=29 mlxlogscore=999 phishscore=0 impostorscore=0 clxscore=1015 bulkscore=0 malwarescore=0 mlxscore=0 lowpriorityscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 8/8] tcgbios: Measure the GPT table X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefan Berger , kevin@koconnor.net Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" From: Stefan Berger Measure and log the GPT table including LBA1 and all GPT table entries with a non-zero Type GUID. We follow the specification "TCG PC Client Platform Firmware Profile Specification" for the format of what needs to be logged and measured. See section "Event Logging" subsection "Measuring UEFI Variables" for the UEFI_GPT_DATA structure. Signed-off-by: Stefan Berger --- board-qemu/slof/vtpm-sml.fs | 8 ++++ lib/libtpm/tcgbios.c | 88 ++++++++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 3 ++ lib/libtpm/tcgbios_int.h | 40 ++++++++++++++++ lib/libtpm/tpm.code | 32 +++++++++++++ lib/libtpm/tpm.in | 3 ++ slof/fs/packages/disk-label.fs | 22 +++++++++ 7 files changed, 196 insertions(+) diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs index a51c907..fd0e6ee 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -42,6 +42,14 @@ s" ibm,vtpm" 2dup device-name device-type THEN ; +: measure-gpt ( ) + 0 7 separator-event + tpm-measure-gpt + ?dup IF + ." VTPM: Error code from tpm-measure-gpt: " . cr + THEN +; + : leave-firmware ( -- ) tpm-leave-firmware ( errcode ) ?dup IF diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c index c5f8ccf..be6c3d1 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -69,6 +69,11 @@ static struct { #define TPM2_ALG_SHA512_FLAG (1 << 3) #define TPM2_ALG_SM3_256_FLAG (1 << 4) +static const uint8_t ZeroGuid[16] = { 0 }; + +static UEFI_GPT_DATA *uefi_gpt_data; +static size_t uefi_gpt_data_size; + /* * TPM 2 logs are written in little endian format. */ @@ -925,6 +930,89 @@ uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr, addr + 0x1b8, 0x48); } +/* + * This is the first function to call when measuring a GPT table. + * It allocates memory for the data to log which are 'measured' later on. + */ +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length) +{ + if (!tpm_is_working()) + return; + + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + + uefi_gpt_data_size = sizeof(UEFI_GPT_DATA); + uefi_gpt_data = SLOF_alloc_mem(uefi_gpt_data_size); + if (!uefi_gpt_data) + return; + + memcpy(&uefi_gpt_data->EfiPartitionHeader, + addr, sizeof(uefi_gpt_data->EfiPartitionHeader)); + uefi_gpt_data->NumberOfPartitions = 0; +} + +/* + * This function adds a GPT entry to the data to measure. It must + * be called after tpm_gpt_set_lba1. + */ +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length) +{ + size_t sz; + UEFI_PARTITION_ENTRY *upe = (void *)addr; + void *tmp; + + if (!tpm_is_working() || + !uefi_gpt_data || + length < sizeof(*upe) || + !memcmp(upe->partTypeGuid, ZeroGuid, sizeof(ZeroGuid))) + return; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + (uefi_gpt_data->NumberOfPartitions + 1) + * sizeof(UEFI_PARTITION_ENTRY); + if (sz > uefi_gpt_data_size) { + tmp = SLOF_alloc_mem(sz); + if (!tmp) + goto err_no_mem; + + memcpy(tmp, uefi_gpt_data, uefi_gpt_data_size); + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data = tmp; + uefi_gpt_data_size = sz; + } + + memcpy(&uefi_gpt_data->Partitions[uefi_gpt_data->NumberOfPartitions], + addr, + sizeof(UEFI_PARTITION_ENTRY)); + uefi_gpt_data->NumberOfPartitions++; + + return; + +err_no_mem: + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data_size = 0; + uefi_gpt_data = NULL; +} + +/* + * tpm_measure_gpt finally measures the GPT table and adds an entry + * to the log. + */ +uint32_t tpm_measure_gpt(void) +{ + size_t sz; + + if (!tpm_is_working()) + return TCGBIOS_GENERAL_ERROR; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + uefi_gpt_data->NumberOfPartitions * sizeof(UEFI_PARTITION_ENTRY); + + return tpm_add_measurement_to_log(5, EV_EFI_GPT_EVENT, + (const char *)uefi_gpt_data, sz, + (const uint8_t *)uefi_gpt_data, sz); +} + uint32_t tpm_measure_scrtm(void) { uint32_t rc; diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h index c4a2e71..8174d86 100644 --- a/lib/libtpm/tcgbios.h +++ b/lib/libtpm/tcgbios.h @@ -29,5 +29,8 @@ uint32_t tpm_driver_get_failure_reason(void); void tpm_driver_set_failure_reason(uint32_t errcode); bool tpm_is_working(void); void tpm20_menu(void); +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length); +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length); +uint32_t tpm_measure_gpt(void); #endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h index 6892e6f..1a88402 100644 --- a/lib/libtpm/tcgbios_int.h +++ b/lib/libtpm/tcgbios_int.h @@ -39,6 +39,8 @@ #define EV_S_CRTM_VERSION 8 #define EV_IPL 13 #define EV_IPL_PARTITION_DATA 14 +#define EV_EFI_EVENT_BASE 0x80000000 +#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 0x6) #define BCV_DEVICE_HDD 0x80 @@ -91,6 +93,44 @@ struct TCG_EfiSpecIdEventStruct { */ } __attribute__((packed)); +/* EFI related data structures for logging */ +typedef struct { + uint64_t signature; + uint32_t revision; + uint32_t size; + uint32_t crc32; + uint8_t reserved[4]; +} __attribute__((packed)) UEFI_TABLE_HEADER; + +typedef struct { + UEFI_TABLE_HEADER header; + uint64_t currentLba; + uint64_t backupLba; + uint64_t firstLba; + uint64_t lastLba; + uint8_t diskGuid[16]; + uint64_t partEntryLba; + uint32_t numPartEntry; + uint32_t partEntrySize; + uint32_t partArrayCrc32; + uint8_t reserved[420]; +} __attribute__((packed)) UEFI_PARTITION_TABLE_HEADER; + +typedef struct { + uint8_t partTypeGuid[16]; + uint8_t partGuid[16]; + uint64_t firstLba; + uint64_t lastLba; + uint64_t attribute; + uint8_t partName[72]; +} __attribute__((packed)) UEFI_PARTITION_ENTRY; + +typedef struct { + UEFI_PARTITION_TABLE_HEADER EfiPartitionHeader; + uint64_t NumberOfPartitions; + UEFI_PARTITION_ENTRY Partitions[0]; +} __attribute__((packed)) UEFI_GPT_DATA; + /* Input and Output headers for all TPM commands */ struct tpm_req_header { uint16_t tag; diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code index b8f5669..205c608 100644 --- a/lib/libtpm/tpm.code +++ b/lib/libtpm/tpm.code @@ -137,3 +137,35 @@ MIRP PRIM(tpm20_X2d_menu) tpm20_menu(); MIRP + +/*************************************************************************/ +/* Set the LBA1 of the GPT */ +/* SLOF: tpm-gpt-set-lba1 ( addr length -- ) */ +/* LIBTPM: tpm_gpt_set_lba1(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_set_X2d_lba1) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_set_lba1(addr, length); +MIRP + +/*************************************************************************/ +/* Add a GPT table entry */ +/* SLOF: tpm-gpt-add-entry ( addr length -- ) */ +/* LIBTPM: tpm_gpt_add_entry(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_add_X2d_entry) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_add_entry(addr, length); +MIRP + +/*************************************************************************/ +/* Measure and log GPT EVENT */ +/* SLOF: tpm-measure-gpt ( -- errcode ) */ +/* LIBTPM: errcode = tpm_measure_gpt() */ +/*************************************************************************/ +PRIM(tpm_X2d_measure_X2d_gpt) + PUSH; + TOS.n = tpm_measure_gpt(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in index 590fee1..bdbc47d 100644 --- a/lib/libtpm/tpm.in +++ b/lib/libtpm/tpm.in @@ -25,3 +25,6 @@ cod(tpm-measure-scrtm) cod(tpm-driver-get-failure-reason) cod(tpm-driver-set-failure-reason) cod(tpm20-menu) +cod(tpm-gpt-set-lba1) +cod(tpm-gpt-add-entry) +cod(tpm-measure-gpt) diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs index 252a44e..1ea3dfa 100644 --- a/slof/fs/packages/disk-label.fs +++ b/slof/fs/packages/disk-label.fs @@ -433,6 +433,27 @@ B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 block gpt>signature x@ GPT-SIGNATURE = ; +\ Measure the GPT partition table by collecting its LBA1 +\ and GPT Entries and then measuring them. +\ This function modifies 'block' and 'seek-pos' + +: measure-gpt-partition ( -- ) + s" /ibm,vtpm" find-node ?dup IF + get-gpt-partition 0= if drop EXIT THEN + + block block-size tpm-gpt-set-lba1 + + block gpt>num-part-entry l@-le + 1+ 1 ?DO + seek-pos 0 seek drop + block gpt-part-size read drop + block gpt-part-size tpm-gpt-add-entry + seek-pos gpt-part-size + to seek-pos + LOOP + s" measure-gpt" rot $call-static + THEN +; + : load-from-gpt-prep-partition ( addr -- size ) get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false exit THEN @@ -455,6 +476,7 @@ B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 ; : try-gpt-dos-partition ( -- true|false ) + measure-gpt-partition get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false EXIT THEN 1+ 1 ?DO