From patchwork Wed Aug 31 19:45:48 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 112663 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1FE5EB6F77 for ; Thu, 1 Sep 2011 05:48:10 +1000 (EST) Received: from localhost ([::1]:51379 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qyqlb-0002wf-6q for incoming@patchwork.ozlabs.org; Wed, 31 Aug 2011 15:48:07 -0400 Received: from eggs.gnu.org ([140.186.70.92]:36436) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QyqlT-0002kS-Q3 for qemu-devel@nongnu.org; Wed, 31 Aug 2011 15:48:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QyqlN-0008G9-J6 for qemu-devel@nongnu.org; Wed, 31 Aug 2011 15:47:59 -0400 Received: from e5.ny.us.ibm.com ([32.97.182.145]:35880) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QyqlN-0008DB-GQ for qemu-devel@nongnu.org; Wed, 31 Aug 2011 15:47:53 -0400 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e5.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p7VJHa5k024572 for ; Wed, 31 Aug 2011 15:17:36 -0400 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p7VJkST5154118 for ; Wed, 31 Aug 2011 15:46:30 -0400 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p7VDjk5w008244 for ; Wed, 31 Aug 2011 07:45:51 -0600 Received: from localhost.localdomain (d941e-10.watson.ibm.com [9.59.241.154]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p7VDjgt8007793 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 31 Aug 2011 07:45:42 -0600 Received: from localhost.localdomain (d941e-10 [127.0.0.1]) by localhost.localdomain (8.14.4/8.14.3) with ESMTP id p7VJk8qi004196; Wed, 31 Aug 2011 15:46:08 -0400 Received: (from root@localhost) by localhost.localdomain (8.14.4/8.14.4/Submit) id p7VJk8Ph004195; Wed, 31 Aug 2011 15:46:08 -0400 Message-Id: <20110831194608.508970977@linux.vnet.ibm.com> User-Agent: quilt/0.48-1 Date: Wed, 31 Aug 2011 15:45:48 -0400 From: Stefan Berger To: stefanb@linux.vnet.ibm.com, seabios@seabios.org References: <20110831194540.700948503@linux.vnet.ibm.com> Content-Disposition: inline; filename=tcgbios_paravirt_measure.diff X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.145 Cc: chrisw@redhat.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH V7 8/9] Support for Qemu-provided measurements X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds support for measurements provided by Qemu via the firmware interface. In the case where Qemu was started with the -kernel, -initrd and -append command lines, Qemu hashes the kernel and initrd files as well as the command line parameters and provides the measurements to SeaBIOS via the firmware interface. SeaBIOS then processes the individual measurements and extends the TPM's PCRs as well as writes logs about those measurements. Signed-off-by: Stefan Berger --- src/boot.c | 1 src/paravirt.c | 14 ++++++++++ src/paravirt.h | 4 +++ src/tcgbios.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 16 ++++++++++++ 5 files changed, 109 insertions(+) Index: seabios/src/tcgbios.c =================================================================== --- seabios.orig/src/tcgbios.c +++ seabios/src/tcgbios.c @@ -17,6 +17,7 @@ #include "acpi.h" // RSDP_SIGNATURE, rsdt_descriptor #include "sha1.h" // sha1 #include "smbios.h" // get_smbios_entry_point +#include "paravirt.h" // QEMU_CFG_KERNEL_*, QEMU_CFG_INITRD_* static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; @@ -1392,6 +1393,79 @@ tcpa_smbios_measure(void) } +u32 tcpa_process_firmware_cfg(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + void *ptr = (void *)0x100000; + u16 ctr = 0; + + u32 len = qemu_cfg_get_u32(QEMU_CFG_TPM_MEASURE_SIZE); + + if (len) { + qemu_cfg_copy(QEMU_CFG_TPM_MEASURE_DATA, ptr, len); + + TPMMsrHdr *hdr = ptr; + u32 idx = sizeof(*hdr); + + if (hdr->rev < 1) + return TCG_GENERAL_ERROR; + + /* since the first revision (1) we have numTPMMsrEntries */ + while (idx < hdr->totlen && ctr < hdr->numTPMMsrEntries) { + TPMMsrEntry *entry = (void *)hdr + idx; + + idx += entry->len; + + struct hleo hleo; + + u8 _pcpes[offsetof(struct pcpes, event) + 400]; + struct pcpes *pcpes = (struct pcpes *)_pcpes; + + pcpes->pcrindex = entry->pcrindex; + pcpes->eventtype = entry->type; + if (entry->eventdatasize < 400) { + pcpes->eventdatasize = entry->eventdatasize; + memcpy(&pcpes->event, &entry->event, entry->eventdatasize); + } else { + pcpes->eventdatasize = 0; + } + memcpy(pcpes->digest, entry->digest, sizeof(pcpes->digest)); + + struct hlei hlei = { + .ipblength = sizeof(hlei), + .hashdataptr = NULL, + .hashdatalen = 0, + .pcrindex = entry->pcrindex, + .logeventtype= entry->type, + .logdataptr = pcpes, + .logdatalen = pcpes->eventdatasize + + offsetof(struct pcpes, event), + }; + + u32 rc = hash_log_event(&hlei, &hleo); + if (rc) + goto err_exit; + + rc = tpm_extend(entry->digest, entry->pcrindex); + if (rc) + goto err_exit; + + ctr++; + } + } + + return 0; + +err_exit: + return 1; +} + + /* * Add a measurement to the log in support of 8.2.5.3 * Creates two log entries Index: seabios/src/boot.c =================================================================== --- seabios.orig/src/boot.c +++ seabios/src/boot.c @@ -610,6 +610,7 @@ static void boot_rom(u32 vector) { printf("Booting from ROM...\n"); + tcpa_process_firmware_cfg(); struct segoff_s so; so.segoff = vector; call_boot_entry(so, 0); Index: seabios/src/paravirt.c =================================================================== --- seabios.orig/src/paravirt.c +++ seabios/src/paravirt.c @@ -61,6 +61,20 @@ void qemu_cfg_port_probe(void) dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present); } +u32 qemu_cfg_get_u32(int e) +{ + u32 i; + + qemu_cfg_read_entry(&i, e, sizeof(i)); + + return i; +} + +void qemu_cfg_copy(int e, void *buf, int len) +{ + qemu_cfg_read_entry(buf, e, len); +} + void qemu_cfg_get_uuid(u8 *uuid) { if (!qemu_cfg_present) Index: seabios/src/paravirt.h =================================================================== --- seabios.orig/src/paravirt.h +++ seabios/src/paravirt.h @@ -33,6 +33,8 @@ static inline int kvm_para_available(voi #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_TPM_MEASURE_SIZE 0x1a +#define QEMU_CFG_TPM_MEASURE_DATA 0x1b #define QEMU_CFG_ARCH_LOCAL 0x8000 #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) @@ -42,6 +44,8 @@ static inline int kvm_para_available(voi extern int qemu_cfg_present; void qemu_cfg_port_probe(void); +u32 qemu_cfg_get_u32(int e); +void qemu_cfg_copy(int e, void *buf, int len); int qemu_cfg_show_boot_menu(void); void qemu_cfg_get_uuid(u8 *uuid); int qemu_cfg_irq0_override(void); Index: seabios/src/tcgbios.h =================================================================== --- seabios.orig/src/tcgbios.h +++ seabios/src/tcgbios.h @@ -390,7 +390,23 @@ u32 tcpa_ipl(enum ipltype bootcd, const u32 tcpa_start_option_rom_scan(void); u32 tcpa_option_rom(const void *addr, u32 len); u32 tcpa_smbios_measure(void); +u32 tcpa_process_firmware_cfg(void); void tcpa_menu(void); +typedef struct TPMMsrHdr { + u16 rev; + u32 totlen; + u16 numTPMMsrEntries; +} __attribute__((packed)) TPMMsrHdr; + +typedef struct TPMMsrEntry { + u32 len; + u32 pcrindex; + u32 type; + u8 digest[SHA1_BUFSIZE]; + u32 eventdatasize; + u32 event; +} __attribute__((packed)) TPMMsrEntry; + #endif /* TCGBIOS_H */