[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH V7 12/13] Support for taking measurements when kerne
From: |
Stefan Berger |
Subject: |
[Qemu-devel] [PATCH V7 12/13] Support for taking measurements when kernel etc. are passed to Qemu |
Date: |
Wed, 10 Aug 2011 15:29:31 -0400 |
User-agent: |
quilt/0.48-1 |
This patch adds support for hashing the kernel and initrd as well as the
command line parameters in the case that Qemu was provided the -kernel, -initrd
and -apppend command line parameters. The hashes are then passed to SeaBIOS
for logging. Typically SeaBIOS would take those measurements (hashing) but in
the case Qemu gets these command line parameters, Qemu does not see the kernel
file in its unmodified form anymore (it is modified before it is passed
to the firmware interface). Support for measuring multiboot kernel entries is
also added.
This patch relies on the existing firmware mechanism to pass byte arrays
from Qemu to a BIOS, i.e., SeaBIOS. It introduces structures describing the
header and the following content consisting of an array of structures that
hold the measurements and descriptions of the above mentioned items.
Since hashing requires a sha1 algorithm to be available to Qemu, this patch
introduces a dependency on the freebl library for the sha1 algorithm. The
code for accessing the freebl library's sha1 function has been isolated into
its own file and wrapped with the function call qemu_sha1. Attempts to use the
freebl library's SHA1 function directly didn't work due to clashes of
datatypes with matching names defined by freebl and Qemu.
-v7:
- Support for multiboot kernels
Signed-off-by: Stefan Berger <address@hidden>
---
Makefile.target | 2 -
configure | 23 +++++++++++
hw/fw_cfg.h | 2 +
hw/multiboot.c | 8 ++++
hw/pc.c | 10 +++++
sha1.c | 19 +++++++++
sha1.h | 9 ++++
tpm.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tpm.h | 33 +++++++++++++++++
9 files changed, 213 insertions(+), 1 deletion(-)
Index: qemu-git/hw/pc.c
===================================================================
--- qemu-git.orig/hw/pc.c
+++ qemu-git/hw/pc.c
@@ -678,6 +678,9 @@ static void load_linux(void *fw_cfg,
exit(1);
}
+ tpm_measure_start();
+ tpm_measure_file(kernel_filename, TPM_MSR_TYPE_KERNEL, 8);
+
/* kernel protocol version */
#if 0
fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
@@ -735,6 +738,9 @@ static void load_linux(void *fw_cfg,
(uint8_t*)strdup(kernel_cmdline),
strlen(kernel_cmdline)+1);
+ tpm_measure_buffer(kernel_cmdline, strlen(kernel_cmdline),
+ TPM_MSR_TYPE_KERNEL_CMDLINE, 8, NULL, 0);
+
if (protocol >= 0x202) {
stl_p(header+0x228, cmdline_addr);
} else {
@@ -796,9 +802,13 @@ static void load_linux(void *fw_cfg,
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
+ tpm_measure_buffer(initrd_data, initrd_size, TPM_MSR_TYPE_INITRD, 8,
+ initrd_filename, strlen(initrd_filename) + 1);
+
stl_p(header+0x218, initrd_addr);
stl_p(header+0x21c, initrd_size);
}
+ tpm_measure_end(fw_cfg);
/* load kernel and setup */
setup_size = header[0x1f1];
Index: qemu-git/tpm.h
===================================================================
--- qemu-git.orig/tpm.h
+++ qemu-git/tpm.h
@@ -1,6 +1,9 @@
#ifndef _HW_TPM_CONFIG_H
#define _HW_TPM_CONFIG_H
+#include "sysemu.h"
+#include "hw/fw_cfg.h"
+
struct TPMState;
typedef struct TPMState TPMState;
@@ -108,6 +111,36 @@ void do_info_tpm(Monitor *mon);
void tpm_display_backend_drivers(FILE *out);
const TPMDriverOps *tpm_get_backend_driver(const char *id);
+typedef enum TPMMeasureType {
+ TPM_MSR_TYPE_KERNEL_CMDLINE = 0x1105,
+ TPM_MSR_TYPE_KERNEL = 0x1205,
+ TPM_MSR_TYPE_INITRD = 0x1305,
+ TPM_MSR_TYPE_MODULE_CMDLINE = 0x1405,
+ TPM_MSR_TYPE_MODULE = 0x1505,
+} TPMMeasureType;
+
+typedef struct TPMMsrHdr {
+ uint16_t rev;
+ uint32_t totlen;
+ uint16_t numTPMMsrEntries;
+} __attribute__((packed)) TPMMsrHdr;
+
+typedef struct TPMMsrEntry {
+ uint32_t len;
+ uint32_t pcrindex;
+ uint32_t type;
+ uint8_t digest[20];
+ uint32_t eventdatasize;
+ uint32_t event;
+} __attribute__((packed)) TPMMsrEntry;
+
+void tpm_measure_start(void);
+void tpm_measure_end(FWCfgState *s);
+void tpm_measure_file(const char *, TPMMeasureType type, uint8_t pcrindex);
+void tpm_measure_buffer(const void *buffer, long length,
+ TPMMeasureType type, uint8_t pcrindex,
+ const void *data, uint32_t data_len);
+
extern TPMDriverOps tpm_builtin;
#endif /* _HW_TPM_CONFIG_H */
Index: qemu-git/tpm.c
===================================================================
--- qemu-git.orig/tpm.c
+++ qemu-git/tpm.c
@@ -14,6 +14,9 @@
#include "tpm.h"
#include "monitor.h"
#include "qerror.h"
+#include "sha1.h"
+#include "hw/loader.h"
+#include "bswap.h"
#ifdef CONFIG_TPM
@@ -268,6 +271,88 @@ void tpm_config_parse(QemuOptsList *opts
}
}
+static TPMMsrHdr *tpm_measurements;
+
+void tpm_measure_start(void)
+{
+ if (!tpm_measurements) {
+ tpm_measurements = qemu_mallocz(sizeof(TPMMsrHdr));
+ tpm_measurements->rev = 1;
+ tpm_measurements->totlen = sizeof(TPMMsrHdr);
+ }
+}
+
+void tpm_measure_end(FWCfgState *s)
+{
+ uint32_t totlen = tpm_measurements->totlen;
+ /* fix endianess */
+ tpm_measurements->rev = cpu_to_le16(tpm_measurements->rev);
+ tpm_measurements->totlen = cpu_to_le32(totlen);
+ tpm_measurements->numTPMMsrEntries =
+ cpu_to_le16(tpm_measurements->numTPMMsrEntries);
+
+ fw_cfg_add_i32(s, FW_CFG_TPM_MEASURE_SIZE, totlen);
+ fw_cfg_add_bytes(s, FW_CFG_TPM_MEASURE_DATA,
+ (unsigned char *)tpm_measurements, totlen);
+}
+
+static void tpm_measure_add_hash(unsigned char digest[20], TPMMeasureType type,
+ uint8_t pcrindex,
+ const void *data, uint32_t len)
+{
+ TPMMsrEntry *entry;
+
+ if (tpm_measurements) {
+ uint32_t entry_len = sizeof(TPMMsrEntry) + len;
+ tpm_measurements = qemu_realloc(tpm_measurements,
+ tpm_measurements->totlen +
+ entry_len);
+ if (tpm_measurements) {
+ entry = (void *)tpm_measurements + tpm_measurements->totlen;
+
+ tpm_measurements->totlen += entry_len;
+ tpm_measurements->numTPMMsrEntries++;
+
+ entry->len = cpu_to_le32(entry_len);
+ entry->pcrindex = cpu_to_le32(pcrindex);
+ entry->type = cpu_to_le32(type);
+ memcpy(entry->digest, digest, sizeof(entry->digest));
+ entry->eventdatasize = cpu_to_le32(len);
+ if (len) {
+ memcpy(&entry->event, data, len);
+ }
+ }
+ }
+}
+
+void tpm_measure_buffer(const void *buffer, long len,
+ TPMMeasureType type, uint8_t pcrindex,
+ const void *data, uint32_t data_len)
+{
+ unsigned char hash[20];
+
+ qemu_sha1(hash, buffer, len);
+
+ tpm_measure_add_hash(hash, type, pcrindex, data, data_len);
+}
+
+void tpm_measure_file(const char *filename, TPMMeasureType type,
+ uint8_t pcrindex)
+{
+ int len = get_image_size(filename);
+
+ if (len > 0) {
+ uint8_t *buffer = qemu_malloc(len);
+ if (buffer) {
+ if (load_image(filename, buffer) == len) {
+ tpm_measure_buffer(buffer, len, type, pcrindex,
+ filename, strlen(filename) + 1);
+ }
+ qemu_free(buffer);
+ }
+ }
+}
+
# else /* TARGET_I386 || TARGET_X86_64 */
void tpm_config_parse(QemuOptsList *opts_list, const char *optarg)
@@ -288,5 +373,28 @@ void do_info_tpm(Monitor *mon)
monitor_printf(mon, "TPM support: not compiled\n");
}
+
# endif
+
+#else /* ! CONFIG_TPM */
+
+void tpm_measure_start(void)
+{
+}
+
+void tpm_measure_end(FWCfgState *s)
+{
+}
+
+void tpm_measure_buffer(const void *buffer, long len,
+ TPMMeasureType type, uint8_t pcrindex,
+ const void *data, uint32_t data_len)
+{
+}
+
+void tpm_measure_file(const char *filename, TPMMeasureType type,
+ uint8_t pcrindex)
+{
+}
+
#endif /* CONFIG_TPM */
Index: qemu-git/hw/fw_cfg.h
===================================================================
--- qemu-git.orig/hw/fw_cfg.h
+++ qemu-git/hw/fw_cfg.h
@@ -27,6 +27,8 @@
#define FW_CFG_SETUP_SIZE 0x17
#define FW_CFG_SETUP_DATA 0x18
#define FW_CFG_FILE_DIR 0x19
+#define FW_CFG_TPM_MEASURE_SIZE 0x1a
+#define FW_CFG_TPM_MEASURE_DATA 0x1b
#define FW_CFG_FILE_FIRST 0x20
#define FW_CFG_FILE_SLOTS 0x10
Index: qemu-git/Makefile.target
===================================================================
--- qemu-git.orig/Makefile.target
+++ qemu-git/Makefile.target
@@ -233,7 +233,7 @@ obj-i386-y += debugcon.o multiboot.o
obj-i386-y += pc_piix.o
obj-i386-$(CONFIG_KVM) += kvmclock.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
-obj-i386-$(CONFIG_TPM) += tpm_tis.o
+obj-i386-$(CONFIG_TPM) += tpm_tis.o sha1.o
obj-i386-$(CONFIG_TPM_BUILTIN) += tpm_builtin.o
ifdef CONFIG_TPM_BUILTIN
Index: qemu-git/sha1.c
===================================================================
--- /dev/null
+++ qemu-git/sha1.c
@@ -0,0 +1,19 @@
+/*
+ * SHA1 Freebl wrapper
+ *
+ * Copyright (C) 2011 IBM Corporation
+ * Copyright (C) 2011 Stefan Berger
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sha1.h"
+
+#include <nss3/blapi.h>
+
+int qemu_sha1(unsigned char hash[20], const unsigned char *data, uint32_t len)
+{
+ return SHA1_HashBuf(hash, data, len);
+}
Index: qemu-git/sha1.h
===================================================================
--- /dev/null
+++ qemu-git/sha1.h
@@ -0,0 +1,9 @@
+#ifndef __SHA1_H
+#define __SHA1_H
+
+#include <stdint.h>
+
+int qemu_sha1(unsigned char hash[20], const unsigned char *data,
+ uint32_t length);
+
+#endif /* __SHA1_H */
Index: qemu-git/configure
===================================================================
--- qemu-git.orig/configure
+++ qemu-git/configure
@@ -2578,6 +2578,29 @@ fi
# libtpms probe
if test "$tpm" = "yes" ; then
+ if $pkg_config --atleast-version=3.12.8 nss-softokn >/dev/null 2>&1 ; then
+ tpmsupport_cflags=$($pkg_config --cflags nss-softokn 2>/dev/null)
+ tpmsupport_libs="-lfreebl -lnspr4 -lnssutil3"
+ QEMU_CFLAGS="$QEMU_CFLAGS $tpmsupport_cflags"
+ LIBS="$LIBS $tpmsupport_libs"
+ else
+ feature_not_found "nss-softokn"
+ fi
+
+ # Check for nss-softokn-freebl-devel
+ cat > $TMPC <<EOF
+#include <blapi.h>
+int main(void) {
+ unsigned char hash[20];
+ char src[1];
+ return (int)SHA1_Hash(hash, src);
+}
+EOF
+
+ if ! compile_prog "" "$tpmsupport_libs" ; then
+ feature_not_found "nss-softokn-freebl-devel"
+ fi
+
cat > $TMPC <<EOF
#include <libtpms/tpm_library.h>
int main(void) { return (int)TPMLIB_GetVersion(); }
Index: qemu-git/hw/multiboot.c
===================================================================
--- qemu-git.orig/hw/multiboot.c
+++ qemu-git/hw/multiboot.c
@@ -28,6 +28,7 @@
#include "loader.h"
#include "elf.h"
#include "sysemu.h"
+#include "tpm.h"
/* Show multiboot debug output */
//#define DEBUG_MULTIBOOT
@@ -100,6 +101,8 @@ static uint32_t mb_add_cmdline(Multiboot
target_phys_addr_t p = s->offset_cmdlines;
char *b = (char *)s->mb_buf + p;
+ tpm_measure_buffer(cmdline, strlen(cmdline),
+ TPM_MSR_TYPE_MODULE_CMDLINE, 8, NULL, 0);
get_opt_value(b, strlen(cmdline) + 1, cmdline);
s->offset_cmdlines += strlen(b) + 1;
return s->mb_buf_phys + p;
@@ -283,6 +286,7 @@ int load_multiboot(void *fw_cfg,
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length +
mbs.mb_buf_size);
mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+ tpm_measure_file(initrd_filename, TPM_MSR_TYPE_MODULE, 8);
load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
mbs.mb_buf_phys + offs + mb_mod_length, c);
@@ -299,6 +303,8 @@ int load_multiboot(void *fw_cfg,
snprintf(kcmdline, sizeof(kcmdline), "%s %s",
kernel_filename, kernel_cmdline);
stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+ tpm_measure_buffer(kcmdline, strlen(kcmdline),
+ TPM_MSR_TYPE_KERNEL_CMDLINE, 8, NULL, 0);
stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
@@ -339,5 +345,7 @@ int load_multiboot(void *fw_cfg,
option_rom[nb_option_roms].bootindex = 0;
nb_option_roms++;
+ tpm_measure_end(fw_cfg);
+
return 1; /* yes, we are multiboot */
}
- [Qemu-devel] [PATCH V7 00/13] Qemu Trusted Platform Module (TPM) integration, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 02/13] Add TPM (frontend) hardware interface (TPM TIS) to Qemu, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 01/13] Support for TPM command line options, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 04/13] Add tpm_tis driver to build process, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 10/13] Encrypt state blobs using AES CBC encryption, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 11/13] Experimental support for block migrating TPMs state, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 05/13] Add a debug register, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 06/13] Add a TPM backend skeleton implementation, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 03/13] Add persistent state handling to TPM TIS frontend driver, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 12/13] Support for taking measurements when kernel etc. are passed to Qemu,
Stefan Berger <=
- [Qemu-devel] [PATCH V7 13/13] Add a TPM backend null driver implementation, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 09/13] Add block storage support for libtpms based TPM backend, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 07/13] Implementation of the libtpms-based backend, Stefan Berger, 2011/08/10
- [Qemu-devel] [PATCH V7 08/13] Introduce file lock for the block layer, Stefan Berger, 2011/08/10