This patch queue goes on top of Matthew Fioravante''s [VTPM v5 0/7] series. While some of the patches have been posted before, all have been cleaned up a bit. [PATCH 1/9] stubdom: Change vTPM shared page ABI * Removed unneeded reconfiguration pieces * Removed feature-protocol-v2 xenstore key references [PATCH 2/9] stubdom/vtpm: Support locality field * Add distinct patch file instead of patching a patch * Comment on future use of the locality field [PATCH 3/9] stubdom/vtpm: correct the buffer size returned by * New patch [PATCH 4/9] stubdom/vtpm: Add locality-5 PCRs * New patch [PATCH 5/9] stubdom/vtpm: Allow repoen of closed devices * This used to use Reconfigure, but has been changed to use the Closed states similar to blkback [PATCH 6/9] stubdom/vtpm: make state save operation atomic * Avoid hardcoded maximum saved state size * Better debug/error messages [PATCH 7/9] stubdom/grub: send kernel measurements to vTPM * Use PolarSSL SHA1 function * Use byteswap.h functions [PATCH 8/9] stubdom/vtpm: support multiple backends * Split into its own patch so it can be excluded if automatic vTPM shutdown is required [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM * New patch, RFC; an alternative to hwinitpcrs
This changes the vTPM shared page ABI from a copy of the Xen network interface to a single-page interface that better reflects the expected behavior of a TPM: only a single request packet can be sent at any given time, and every packet sent generates a single response packet. This protocol change should also increase efficiency as it avoids mapping and unmapping grants when possible. While the contents of the shared page have been defined to allow packets larger than a single page (actually 4088 bytes) by allowing the client to add extra grant references, the mapping of these extra references has not been implemented; a feature node in xenstore may be used in the future to indicate full support for the multi-page protocol. Most uses of the TPM should not require this feature. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/include/tpmback.h | 1 + extras/mini-os/include/tpmfront.h | 7 ++- extras/mini-os/tpmback.c | 115 +++++++++++++------------------------ extras/mini-os/tpmfront.c | 117 +++++++++++++++----------------------- xen/include/public/io/tpmif.h | 45 ++++----------- 5 files changed, 99 insertions(+), 186 deletions(-) diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h index ff86732..ec9eda4 100644 --- a/extras/mini-os/include/tpmback.h +++ b/extras/mini-os/include/tpmback.h @@ -43,6 +43,7 @@ struct tpmcmd { domid_t domid; /* Domid of the frontend */ + uint8_t locality; /* Locality requested by the frontend */ unsigned int handle; /* Handle of the frontend */ unsigned char uuid[16]; /* uuid of the tpm interface */ diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h index fd2cb17..a0c7c4d 100644 --- a/extras/mini-os/include/tpmfront.h +++ b/extras/mini-os/include/tpmfront.h @@ -37,9 +37,7 @@ struct tpmfront_dev { grant_ref_t ring_ref; evtchn_port_t evtchn; - tpmif_tx_interface_t* tx; - - void** pages; + vtpm_shared_page_t *page; domid_t bedomid; char* nodename; @@ -77,6 +75,9 @@ void shutdown_tpmfront(struct tpmfront_dev* dev); * */ int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t** resp, size_t* resplen); +/* Set the locality used for communicating with a vTPM */ +int tpmfront_set_locality(struct tpmfront_dev* dev, int locality); + #ifdef HAVE_LIBC #include <sys/stat.h> /* POSIX IO functions: diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 658fed1..01c2851 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -86,10 +86,7 @@ struct tpmif { evtchn_port_t evtchn; /* Shared page */ - tpmif_tx_interface_t* tx; - - /* pointer to TPMIF_RX_RING_SIZE pages */ - void** pages; + vtpm_shared_page_t *page; enum xenbus_state state; enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; @@ -312,7 +309,6 @@ int insert_tpmif(tpmif_t* tpmif) remove_tpmif(tpmif); goto error_post_irq; } - return 0; error: local_irq_restore(flags); @@ -386,8 +382,7 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) tpmif->fe_state_path = NULL; tpmif->state = XenbusStateInitialising; tpmif->status = DISCONNECTED; - tpmif->tx = NULL; - tpmif->pages = NULL; + tpmif->page = NULL; tpmif->flags = 0; memset(tpmif->uuid, 0, sizeof(tpmif->uuid)); return tpmif; @@ -395,9 +390,6 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) void __free_tpmif(tpmif_t* tpmif) { - if(tpmif->pages) { - free(tpmif->pages); - } if(tpmif->fe_path) { free(tpmif->fe_path); } @@ -430,12 +422,6 @@ tpmif_t* new_tpmif(domid_t domid, unsigned int handle) goto error; } - /* allocate pages to be used for shared mapping */ - if((tpmif->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE)) == NULL) { - goto error; - } - memset(tpmif->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); - if(tpmif_change_state(tpmif, XenbusStateInitWait)) { goto error; } @@ -486,7 +472,7 @@ void free_tpmif(tpmif_t* tpmif) tpmif->status = DISCONNECTING; mask_evtchn(tpmif->evtchn); - if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1)) { + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1)) { TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); } @@ -529,9 +515,10 @@ void free_tpmif(tpmif_t* tpmif) void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *data) { tpmif_t* tpmif = (tpmif_t*) data; - tpmif_tx_request_t* tx = &tpmif->tx->ring[0].req; - /* Throw away 0 size events, these can trigger from event channel unmasking */ - if(tx->size == 0) + vtpm_shared_page_t* pg = tpmif->page; + + /* Only pay attention if the request is ready */ + if (pg->state == 0) return; TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); @@ -585,11 +572,10 @@ int connect_fe(tpmif_t* tpmif) free(value); domid = tpmif->domid; - if((tpmif->tx = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { + if((tpmif->page = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); return -1; } - memset(tpmif->tx, 0, PAGE_SIZE); /*Bind the event channel */ if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tpmif, &tpmif->evtchn))) @@ -618,7 +604,7 @@ error_post_evtchn: mask_evtchn(tpmif->evtchn); unbind_evtchn(tpmif->evtchn); error_post_map: - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1); + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1); return -1; } @@ -874,6 +860,7 @@ void shutdown_tpmback(void) inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, unsigned char uuid[16]) { tpmcmd->domid = domid; + tpmcmd->locality = -1; tpmcmd->handle = handle; memcpy(tpmcmd->uuid, uuid, sizeof(tpmcmd->uuid)); tpmcmd->req = NULL; @@ -884,12 +871,12 @@ inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, un tpmcmd_t* get_request(tpmif_t* tpmif) { tpmcmd_t* cmd; - tpmif_tx_request_t* tx; - int offset; - int tocopy; - int i; - uint32_t domid; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG + int i; +#endif local_irq_save(flags); @@ -899,35 +886,22 @@ tpmcmd_t* get_request(tpmif_t* tpmif) { } init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); - tx = &tpmif->tx->ring[0].req; - cmd->req_len = tx->size; + shr = tpmif->page; + cmd->req_len = shr->length; + cmd->locality = shr->locality; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->req_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } /* Allocate the buffer */ if(cmd->req_len) { if((cmd->req = malloc(cmd->req_len)) == NULL) { goto error; } } - /* Copy the bits from the shared pages */ - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_READ)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->req_len - offset, PAGE_SIZE); - memcpy(&cmd->req[offset], tpmif->pages[i], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); - - } + /* Copy the bits from the shared page(s) */ + memcpy(cmd->req, offset + (uint8_t*)shr, cmd->req_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len); @@ -958,38 +932,24 @@ error: void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) { - tpmif_tx_request_t* tx; - int offset; - int i; - uint32_t domid; - int tocopy; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG +int i; +#endif local_irq_save(flags); - tx = &tpmif->tx->ring[0].req; - tx->size = cmd->resp_len; - - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_WRITE)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->resp_len - offset, PAGE_SIZE); - memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); + shr = tpmif->page; + shr->length = cmd->resp_len; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->resp_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; } + memcpy(offset + (uint8_t*)shr, cmd->resp, cmd->resp_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->resp_len); @@ -1003,6 +963,7 @@ void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) #endif /* clear the ready flag and send the event channel notice to the frontend */ tpmif_req_finished(tpmif); + shr->state = 0; notify_remote_via_evtchn(tpmif->evtchn); error: local_irq_restore(flags); diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index 0218d7f..e66ce3c 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -176,7 +176,7 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState ret = wait_for_backend_closed(&events, path); break; default: - break; + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +190,13 @@ static int tpmfront_connect(struct tpmfront_dev* dev) { char* err; /* Create shared page */ - dev->tx = (tpmif_tx_interface_t*) alloc_page(); - if(dev->tx == NULL) { + dev->page = (vtpm_shared_page_t*) alloc_page(); + if(dev->page == NULL) { TPMFRONT_ERR("Unable to allocate page for shared memory\n"); goto error; } - memset(dev->tx, 0, PAGE_SIZE); - dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->tx), 0); + memset(dev->page, 0, PAGE_SIZE); + dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->page), 0); TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref); /*Create event channel */ @@ -228,7 +228,7 @@ error_postevtchn: unbind_evtchn(dev->evtchn); error_postmap: gnttab_end_access(dev->ring_ref); - free_page(dev->tx); + free_page(dev->page); error: return -1; } @@ -240,7 +240,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) char path[512]; char* value, *err; unsigned long long ival; - int i; printk("============= Init TPM Front ================\n"); @@ -289,19 +288,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) goto error; } - /* Allocate pages that will contain the messages */ - dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE); - if(dev->pages == NULL) { - goto error; - } - memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - dev->pages[i] = (void*)alloc_page(); - if(dev->pages[i] == NULL) { - goto error; - } - } - TPMFRONT_LOG("Initialization Completed successfully\n"); return dev; @@ -314,8 +300,6 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } @@ -349,27 +333,12 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) /* Wait for the backend to close and unmap shared pages, ignore any errors */ wait_for_backend_state_changed(dev, XenbusStateClosed); - /* Cleanup any shared pages */ - if(dev->pages) { - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - if(dev->pages[i]) { - tx = &dev->tx->ring[i].req; - if(tx->ref != 0) { - gnttab_end_access(tx->ref); - } - free_page(dev->pages[i]); - } - } - free(dev->pages); - } - /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); unbind_evtchn(dev->evtchn); gnttab_end_access(dev->ring_ref); - free_page(dev->tx); - + free_page(dev->page); } /* Cleanup memory usage */ @@ -387,13 +356,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) { + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG int i; - tpmif_tx_request_t* tx = NULL; +#endif /* Error Checking */ if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to send message through disconnected frontend\n"); return -1; } + shr = dev->page; #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length); @@ -407,19 +380,16 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) #endif /* Copy to shared pages now */ - for(i = 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) { - /* Share the page */ - tx = &dev->tx->ring[i].req; - tx->unused = 0; - tx->addr = virt_to_mach(dev->pages[i]); - tx->ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->pages[i]), 0); - /* Copy the bits to the page */ - tx->size = length > PAGE_SIZE ? PAGE_SIZE : length; - memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size); - - /* Update counters */ - length -= tx->size; + offset = sizeof(*shr); + if (length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Message too long for shared page\n"); + return -1; } + memcpy(offset + (uint8_t*)shr, msg, length); + shr->length = length; + barrier(); + shr->state = 1; + dev->waiting = 1; dev->resplen = 0; #ifdef HAVE_LIBC @@ -434,44 +404,41 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) } int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *length) { - tpmif_tx_request_t* tx; - int i; + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG +int i; +#endif if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to receive message from disconnected frontend\n"); return -1; } /*Wait for the response */ wait_event(dev->waitq, (!dev->waiting)); + shr = dev->page; + if (shr->state != 0) + goto quit; /* Initialize */ *msg = NULL; - *length = 0; + *length = shr->length; + offset = sizeof(*shr); - /* special case, just quit */ - tx = &dev->tx->ring[0].req; - if(tx->size == 0 ) { - goto quit; - } - /* Get the total size */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - *length += tx->size; + if (*length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Reply too long for shared page\n"); + return -1; } + /* Alloc the buffer */ if(dev->respbuf) { free(dev->respbuf); } *msg = dev->respbuf = malloc(*length); dev->resplen = *length; + /* Copy the bits */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size); - gnttab_end_access(tx->ref); - tx->ref = 0; - } + memcpy(*msg, offset + (uint8_t*)shr, *length); + #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned int) *length); for(i = 0; i < *length; ++i) { @@ -504,6 +471,14 @@ int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t* return 0; } +int tpmfront_set_locality(struct tpmfront_dev* dev, int locality) +{ + if (!dev || !dev->page) + return -1; + dev->page->locality = locality; + return 0; +} + #ifdef HAVE_LIBC #include <errno.h> int tpmfront_open(struct tpmfront_dev* dev) diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h index 02ccdab..afc9181 100644 --- a/xen/include/public/io/tpmif.h +++ b/xen/include/public/io/tpmif.h @@ -1,7 +1,7 @@ /****************************************************************************** * tpmif.h * - * TPM I/O interface for Xen guest OSes. + * TPM I/O interface for Xen guest OSes, v2 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -21,48 +21,23 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * Copyright (c) 2005, IBM Corporation - * - * Author: Stefan Berger, stefanb@us.ibm.com - * Grant table support: Mahadevan Gomathisankaran - * - * This code has been derived from tools/libxc/xen/io/netif.h - * - * Copyright (c) 2003-2004, Keir Fraser */ #ifndef __XEN_PUBLIC_IO_TPMIF_H__ #define __XEN_PUBLIC_IO_TPMIF_H__ -#include "../grant_table.h" +struct vtpm_shared_page { + uint16_t length; /* request/response length in bytes */ -struct tpmif_tx_request { - unsigned long addr; /* Machine address of packet. */ - grant_ref_t ref; /* grant table access reference */ - uint16_t unused; - uint16_t size; /* Packet size in bytes. */ -}; -typedef struct tpmif_tx_request tpmif_tx_request_t; - -/* - * The TPMIF_TX_RING_SIZE defines the number of pages the - * front-end and backend can exchange (= size of array). - */ -typedef uint32_t TPMIF_RING_IDX; - -#define TPMIF_TX_RING_SIZE 1 - -/* This structure must fit in a memory page. */ - -struct tpmif_ring { - struct tpmif_tx_request req; -}; -typedef struct tpmif_ring tpmif_ring_t; + uint8_t state; /* 0 - response ready / idle + * 1 - request ready / working */ + uint8_t locality; /* for the current request */ + uint8_t padding[3]; -struct tpmif_tx_interface { - struct tpmif_ring ring[TPMIF_TX_RING_SIZE]; + uint8_t nr_extra_pages; /* extra pages for long packets; may be zero */ + uint32_t extra_pages[0]; /* grant IDs; length is actually nr_extra_pages */ }; -typedef struct tpmif_tx_interface tpmif_tx_interface_t; +typedef struct vtpm_shared_page vtpm_shared_page_t; #endif -- 1.7.11.7
The vTPM protocol now contains a field allowing the locality of a command to be specified; pass this to the TPM when processing a packet. While the locality is not currently checked for validity, a binding between locality and some distinguishing feature of the client domain (such as the XSM label) will need to be defined in order to properly support a multi-client vTPM. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-locality.patch | 50 +++++++++++++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm.c | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 stubdom/vtpm-locality.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index fcc608e..683bc51 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -207,6 +207,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz tar xzf $< mv tpm_emulator-$(TPMEMU_VERSION) $@ patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; + patch -d $@ -p1 < vtpm-locality.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-locality.patch b/stubdom/vtpm-locality.patch new file mode 100644 index 0000000..8ab7dea --- /dev/null +++ b/stubdom/vtpm-locality.patch @@ -0,0 +1,50 @@ +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c +index 60bbb90..f8f7f0f 100644 +--- a/tpm/tpm_capability.c ++++ b/tpm/tpm_capability.c +@@ -949,6 +949,8 @@ static TPM_RESULT set_vendor(UINT32 subCap, BYTE *setValue, + UINT32 setValueSize, BOOL ownerAuth, + BOOL deactivated, BOOL disabled) + { ++ if (tpmData.stany.flags.localityModifier != 8) ++ return TPM_BAD_PARAMETER; + /* set the capability area with the specified data, on failure + deactivate the TPM */ + switch (subCap) { +diff --git a/tpm/tpm_cmd_handler.c b/tpm/tpm_cmd_handler.c +index 288d1ce..9e1cfb4 100644 +--- a/tpm/tpm_cmd_handler.c ++++ b/tpm/tpm_cmd_handler.c +@@ -4132,7 +4132,7 @@ void tpm_emulator_shutdown() + tpm_extern_release(); + } + +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size) ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality) + { + TPM_REQUEST req; + TPM_RESPONSE rsp; +@@ -4140,7 +4140,9 @@ int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint3 + UINT32 len; + BOOL free_out; + +- debug("tpm_handle_command()"); ++ debug("tpm_handle_command(%d)", locality); ++ if (locality != -1) ++ tpmData.stany.flags.localityModifier = locality; + + /* we need the whole packet at once, otherwise unmarshalling will fail */ + if (tpm_unmarshal_TPM_REQUEST((uint8_t**)&in, &in_size, &req) != 0) { +diff --git a/tpm/tpm_emulator.h b/tpm/tpm_emulator.h +index eed749e..4c228bd 100644 +--- a/tpm/tpm_emulator.h ++++ b/tpm/tpm_emulator.h +@@ -59,7 +59,7 @@ void tpm_emulator_shutdown(void); + * its usage. In case of an error, all internally allocated memory + * is released and the the state of out and out_size is unspecified. + */ +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size); ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality); + + #endif /* _TPM_EMULATOR_H_ */ + diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index 71aef78..eb7912f 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -183,7 +183,7 @@ static void main_loop(void) { } /* If not disabled, do the command */ else { - if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len)) != 0) { + if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len, tpmcmd->locality)) != 0) { error("tpm_handle_command() failed"); create_error_response(tpmcmd, TPM_FAIL); } -- 1.7.11.7
Daniel De Graaf
2012-Nov-30 14:49 UTC
[PATCH 3/9] stubdom/vtpm: correct the buffer size returned by TPM_CAP_PROP_INPUT_BUFFER
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-bufsize.patch | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 stubdom/vtpm-bufsize.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index 683bc51..c01f1a5 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -208,6 +208,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz mv tpm_emulator-$(TPMEMU_VERSION) $@ patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; patch -d $@ -p1 < vtpm-locality.patch + patch -d $@ -p1 < vtpm-bufsize.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-bufsize.patch b/stubdom/vtpm-bufsize.patch new file mode 100644 index 0000000..9c9304c --- /dev/null +++ b/stubdom/vtpm-bufsize.patch @@ -0,0 +1,13 @@ +diff --git a/config.h.in b/config.h.in +index d16a997..8088a2a 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -27,7 +27,7 @@ + #define TPM_STORAGE_NAME "${TPM_STORAGE_NAME}" + #define TPM_DEVICE_NAME "${TPM_DEVICE_NAME}" + #define TPM_LOG_FILE "${TPM_LOG_FILE}" +-#define TPM_CMD_BUF_SIZE 4096 ++#define TPM_CMD_BUF_SIZE 4088 + + #endif /* _CONFIG_H_ */ + -- 1.7.11.7
This defines new PCRs (24-31) that are restricted to locality 5, which can be used by an agent outside a domain to record information about its measurements and activity. These PCRs cannot be initialized from the hardware TPM (since most hardware TPMs do not define PCR 24+). This definition may need to be changed in the future, as the TCG''s VTPM working group is working to define the meaning of PCRs above 23 on a vTPM; the existing PC-client specification allows these PCRs to be implementation-defined. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-locality5-pcrs.patch | 33 +++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm.c | 8 ++++---- stubdom/vtpm/vtpm_pcrs.h | 6 +++--- 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 stubdom/vtpm-locality5-pcrs.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index c01f1a5..4744b79 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -209,6 +209,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; patch -d $@ -p1 < vtpm-locality.patch patch -d $@ -p1 < vtpm-bufsize.patch + patch -d $@ -p1 < vtpm-locality5-pcrs.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-locality5-pcrs.patch b/stubdom/vtpm-locality5-pcrs.patch new file mode 100644 index 0000000..f697035 --- /dev/null +++ b/stubdom/vtpm-locality5-pcrs.patch @@ -0,0 +1,33 @@ +diff --git a/tpm/tpm_data.c b/tpm/tpm_data.c +index 50c9697..d8cac09 100644 +--- a/tpm/tpm_data.c ++++ b/tpm/tpm_data.c +@@ -151,9 +151,12 @@ void tpm_init_data(void) + init_pcr_attr(22, TRUE, 0x04, 0x04); + init_pcr_attr(23, TRUE, 0x1f, 0x1f); + } +- for (i = 24; i < TPM_NUM_PCR; i++) { +- init_pcr_attr(i, TRUE, 0x00, 0x00); +- } ++ for (i = 24; i < 28 && i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, FALSE, 0x00, 0x20); ++ for (i = 28; i < 32 && i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, TRUE, 0x20, 0x20); ++ for (i = 32; i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, FALSE, 0x00, 0xC0); + if (tpmConf & TPM_CONF_GENERATE_EK) { + /* generate a new endorsement key */ + tpm_rsa_generate_key(&tpmData.permanent.data.endorsementKey, 2048); +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h +index f746c05..08cef1e 100644 +--- a/tpm/tpm_structures.h ++++ b/tpm/tpm_structures.h +@@ -676,7 +676,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { + /* + * Number of PCRs of the TPM (must be a multiple of eight) + */ +-#define TPM_NUM_PCR 24 ++#define TPM_NUM_PCR 32 + + /* + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index eb7912f..aaf1a24 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -253,18 +253,18 @@ int parse_cmd_line(int argc, char** argv) opt_args.hwinitpcrs = VTPM_PCRNONE; } else if(sscanf(pch, "%u", &v1) == 1) { //Set one - if(v1 >= TPM_NUM_PCR) { + if(v1 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } opt_args.hwinitpcrs |= (1 << v1); } else if(sscanf(pch, "%u-%u", &v1, &v2) == 2) { //Set range - if(v1 >= TPM_NUM_PCR) { + if(v1 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } - if(v2 >= TPM_NUM_PCR) { + if(v2 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } @@ -312,7 +312,7 @@ int parse_cmd_line(int argc, char** argv) pcrstr[0] = ''\0''; info("The following PCRs will be initialized with values from the hardware TPM:"); - for(unsigned int i = 0; i < TPM_NUM_PCR; ++i) { + for(unsigned int i = 0; i < VTPM_NUMPCRS; ++i) { if(opt_args.hwinitpcrs & (1 << i)) { ptr += sprintf(ptr, "%u, ", i); } diff --git a/stubdom/vtpm/vtpm_pcrs.h b/stubdom/vtpm/vtpm_pcrs.h index 11835f9..bd9068c 100644 --- a/stubdom/vtpm/vtpm_pcrs.h +++ b/stubdom/vtpm/vtpm_pcrs.h @@ -40,11 +40,11 @@ #define VTPM_PCR22 1 << 22 #define VTPM_PCR23 1 << 23 -#define VTPM_PCRALL (1 << TPM_NUM_PCR) - 1 -#define VTPM_PCRNONE 0 - #define VTPM_NUMPCRS 24 +#define VTPM_PCRALL (1 << VTPM_NUMPCRS) - 1 +#define VTPM_PCRNONE 0 + struct tpmfront_dev; TPM_RESULT vtpm_initialize_hw_pcrs(struct tpmfront_dev* tpmfront_dev, unsigned long pcrs); -- 1.7.11.7
Daniel De Graaf
2012-Nov-30 14:49 UTC
[PATCH 5/9] stubdom/vtpm: Allow repoen of closed devices
Allow the vtpm device to be disconnected and reconnected so that a bootloader (like pv-grub) can submit measurements and return the vtpm device to its initial state before booting the target kernel. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/tpmback.c | 23 ++++++++++++++++++++++- extras/mini-os/tpmfront.c | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 01c2851..9309d26 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -608,6 +608,24 @@ error_post_map: return -1; } +static void disconnect_fe(tpmif_t* tpmif) +{ + if (tpmif->status == CONNECTED) { + tpmif->status = DISCONNECTING; + mask_evtchn(tpmif->evtchn); + + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1)) { + TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); + } + + unbind_evtchn(tpmif->evtchn); + } + tpmif->status = DISCONNECTED; + tpmif_change_state(tpmif, XenbusStateInitWait); + + TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int) tpmif->domid, tpmif->handle); +} + static int frontend_changed(tpmif_t* tpmif) { int state = xenbus_read_integer(tpmif->fe_state_path); @@ -634,8 +652,11 @@ static int frontend_changed(tpmif_t* tpmif) tpmif_change_state(tpmif, XenbusStateClosing); break; - case XenbusStateUnknown: /* keep it here */ case XenbusStateClosed: + disconnect_fe(tpmif); + break; + + case XenbusStateUnknown: /* keep it here */ free_tpmif(tpmif); break; diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index e66ce3c..181da30 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -146,6 +146,9 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) case XenbusStateClosed: TPMFRONT_LOG("Backend Closed\n"); return 0; + case XenbusStateInitWait: + TPMFRONT_LOG("Backend Closed (waiting for reconnect)\n"); + return 0; default: xenbus_wait_for_watch(events); } @@ -306,10 +309,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) TPMFRONT_LOG("Shutting down tpmfront\n"); /* disconnect */ if(dev->state == XenbusStateConnected) { - dev->state = XenbusStateClosing; - //FIXME: Transaction for this? /* Tell backend we are closing */ + dev->state = XenbusStateClosing; if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename, err); free(err); } @@ -333,6 +336,13 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) /* Wait for the backend to close and unmap shared pages, ignore any errors */ wait_for_backend_state_changed(dev, XenbusStateClosed); + /* Prepare for a later reopen (possibly by a kexec''d kernel) */ + dev->state = XenbusStateInitialising; + if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename, err); + free(err); + } + /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); unbind_evtchn(dev->evtchn); -- 1.7.11.7
Daniel De Graaf
2012-Nov-30 14:49 UTC
[PATCH 6/9] stubdom/vtpm: make state save operation atomic
This changes the save format of the vtpm stubdom to include two copies of the saved data: one active, and one inactive. When saving the state, data is written to the inactive slot before updating the key and hash saved with the TPM Manager, which determines the active slot when the vTPM starts up. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/vtpm/vtpmblk.c | 74 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c index b343bd8..fe529ab 100644 --- a/stubdom/vtpm/vtpmblk.c +++ b/stubdom/vtpm/vtpmblk.c @@ -26,6 +26,7 @@ static struct blkfront_dev* blkdev = NULL; static int blkfront_fd = -1; +static uint64_t slot_size = 0; int init_vtpmblk(struct tpmfront_dev* tpmfront_dev) { @@ -45,6 +46,8 @@ int init_vtpmblk(struct tpmfront_dev* tpmfront_dev) goto error; } + slot_size = blkinfo.sectors * blkinfo.sector_size / 2; + return 0; error: shutdown_blkfront(blkdev); @@ -59,15 +62,20 @@ void shutdown_vtpmblk(void) blkdev = NULL; } -int write_vtpmblk_raw(uint8_t *data, size_t data_length) +static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot) { int rc; uint32_t lenbuf; - debug("Begin Write data=%p len=%u", data, data_length); + debug("Begin Write data=%p len=%u slot=%u ssize=%u", data, data_length, slot, slot_size); + + if (data_length > slot_size - 4) { + error("vtpm data cannot fit in data slot (%d/%d).", data_length, slot_size - 4); + return -1; + } lenbuf = cpu_to_be32((uint32_t)data_length); - lseek(blkfront_fd, 0, SEEK_SET); + lseek(blkfront_fd, slot * slot_size, SEEK_SET); if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { error("write(length) failed! error was %s", strerror(errno)); return -1; @@ -82,12 +90,12 @@ int write_vtpmblk_raw(uint8_t *data, size_t data_length) return 0; } -int read_vtpmblk_raw(uint8_t **data, size_t *data_length) +static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot) { int rc; uint32_t lenbuf; - lseek(blkfront_fd, 0, SEEK_SET); + lseek(blkfront_fd, slot * slot_size, SEEK_SET); if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { error("read(length) failed! error was %s", strerror(errno)); return -1; @@ -97,6 +105,10 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length) error("read 0 data_length for NVM"); return -1; } + if(*data_length > slot_size - 4) { + error("read invalid data_length for NVM"); + return -1; + } *data = tpm_malloc(*data_length); if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) { @@ -104,7 +116,7 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length) return -1; } - info("Read %u bytes from NVM persistent storage", *data_length); + info("Read %u bytes from NVM persistent storage (slot %d)", *data_length, slot); return 0; } @@ -221,6 +233,9 @@ egress: return rc; } +/* Current active state slot, or -1 if no valid saved state exists */ +static int active_slot = -1; + int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { int rc; uint8_t* cipher = NULL; @@ -228,12 +243,17 @@ int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_ uint8_t hashkey[HASHKEYSZ]; uint8_t* symkey = hashkey + HASHSZ; + /* Switch to the other slot. Note that in a new vTPM, the read will not + * succeed, so active_slot will be -1 and we will write to slot 0. + */ + active_slot = !active_slot; + /* Encrypt the data */ if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) { goto abort_egress; } /* Write to disk */ - if((rc = write_vtpmblk_raw(cipher, cipher_len))) { + if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) { goto abort_egress; } /* Get sha1 hash of data */ @@ -256,7 +276,8 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data size_t cipher_len = 0; size_t keysize; uint8_t* hashkey = NULL; - uint8_t hash[HASHSZ]; + uint8_t hash0[HASHSZ]; + uint8_t hash1[HASHSZ]; uint8_t* symkey; /* Retreive the hash and the key from the manager */ @@ -270,14 +291,32 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data } symkey = hashkey + HASHSZ; - /* Read from disk now */ - if((rc = read_vtpmblk_raw(&cipher, &cipher_len))) { + active_slot = 0; + debug("Reading slot 0 from disk\n"); + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) { goto abort_egress; } /* Compute the hash of the cipher text and compare */ - sha1(cipher, cipher_len, hash); - if(memcmp(hash, hashkey, HASHSZ)) { + sha1(cipher, cipher_len, hash0); + if(!memcmp(hash0, hashkey, HASHSZ)) + goto valid; + + free(cipher); + cipher = NULL; + + active_slot = 1; + debug("Reading slot 1 from disk (offset=%u)\n", slot_size); + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) { + goto abort_egress; + } + + /* Compute the hash of the cipher text and compare */ + sha1(cipher, cipher_len, hash1); + if(!memcmp(hash1, hashkey, HASHSZ)) + goto valid; + + { int i; error("NVM Storage Checksum failed!"); printf("Expected: "); @@ -285,14 +324,20 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data printf("%02hhX ", hashkey[i]); } printf("\n"); - printf("Actual: "); + printf("Slot 0: "); + for(i = 0; i < HASHSZ; ++i) { + printf("%02hhX ", hash0[i]); + } + printf("\n"); + printf("Slot 1: "); for(i = 0; i < HASHSZ; ++i) { - printf("%02hhX ", hash[i]); + printf("%02hhX ", hash1[i]); } printf("\n"); rc = -1; goto abort_egress; } +valid: /* Decrypt the blob */ if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) { @@ -300,6 +345,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data } goto egress; abort_egress: + active_slot = -1; egress: free(cipher); free(hashkey); -- 1.7.11.7
Daniel De Graaf
2012-Nov-30 14:49 UTC
[PATCH 7/9] stubdom/grub: send kernel measurements to vTPM
This allows a domU with an arbitrary kernel and initrd to take advantage of the static root of trust provided by a vTPM. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 2 +- stubdom/grub/Makefile | 1 + stubdom/grub/kexec.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ stubdom/grub/minios.cfg | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/stubdom/Makefile b/stubdom/Makefile index 4744b79..790b547 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -399,7 +399,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar.gz done .PHONY: grub -grub: grub-upstream $(CROSS_ROOT) +grub: cross-polarssl grub-upstream $(CROSS_ROOT) mkdir -p grub-$(XEN_TARGET_ARCH) CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) DESTDIR= -C $@ OBJ_DIR=$(CURDIR)/grub-$(XEN_TARGET_ARCH) diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile index d6e3a1e..6bd2c4c 100644 --- a/stubdom/grub/Makefile +++ b/stubdom/grub/Makefile @@ -60,6 +60,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) $(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__ PV_GRUB_SOURCES = kexec.c mini-os.c +PV_GRUB_SOURCES += ../polarssl-$(XEN_TARGET_ARCH)/library/sha1.o SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES) diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c index b21c91a..cef357e 100644 --- a/stubdom/grub/kexec.c +++ b/stubdom/grub/kexec.c @@ -28,7 +28,9 @@ #include <blkfront.h> #include <netfront.h> #include <fbfront.h> +#include <tpmfront.h> #include <shared.h> +#include <byteswap.h> #include "mini-os.h" @@ -54,6 +56,22 @@ static unsigned long allocated; int pin_table(xc_interface *xc_handle, unsigned int type, unsigned long mfn, domid_t dom); +#define TPM_TAG_RQU_COMMAND 0xC1 +#define TPM_ORD_Extend 20 + +struct pcr_extend_cmd { + uint16_t tag; + uint32_t size; + uint32_t ord; + + uint32_t pcr; + unsigned char hash[20]; +} __attribute__((packed)); + +/* Not imported from polarssl''s header since the prototype unhelpfully defines + * the input as unsigned char, which causes pointer type mismatches */ +void sha1(const void *input, size_t ilen, unsigned char output[20]); + /* We need mfn to appear as target_pfn, so exchange with the MFN there */ static void do_exchange(struct xc_dom_image *dom, xen_pfn_t target_pfn, xen_pfn_t source_mfn) { @@ -117,6 +135,40 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) return 0; } +static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline) +{ + struct tpmfront_dev* tpm = init_tpmfront(NULL); + uint8_t *resp; + size_t resplen = 0; + struct pcr_extend_cmd cmd; + + /* If all guests have access to a vTPM, it may be useful to replace this + * with ASSERT(tpm) to prevent configuration errors from allowing a guest + * to boot without a TPM (or with a TPM that has not been sent any + * measurements, which could allow forging the measurements). + */ + if (!tpm) + return; + + cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND); + cmd.size = bswap_32(sizeof(cmd)); + cmd.ord = bswap_32(TPM_ORD_Extend); + cmd.pcr = bswap_32(4); // PCR #4 for kernel + sha1(dom->kernel_blob, dom->kernel_size, cmd.hash); + + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = bswap_32(5); // PCR #5 for cmdline + sha1(cmdline, strlen(cmdline), cmd.hash); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = bswap_32(5); // PCR #5 for initrd + sha1(dom->ramdisk_blob, dom->ramdisk_size, cmd.hash); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + shutdown_tpmfront(tpm); +} + void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) { struct xc_dom_image *dom; @@ -151,6 +203,8 @@ void kexec(void *kernel, long kernel_size, void *module, long module_size, char dom->console_evtchn = start_info.console.domU.evtchn; dom->xenstore_evtchn = start_info.store_evtchn; + tpm_hash2pcr(dom, cmdline); + if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) { grub_printf("xc_dom_boot_xen_init returned %d\n", rc); errnum = ERR_BOOT_FAILURE; diff --git a/stubdom/grub/minios.cfg b/stubdom/grub/minios.cfg index 40cfa68..8df4909 100644 --- a/stubdom/grub/minios.cfg +++ b/stubdom/grub/minios.cfg @@ -1,2 +1,3 @@ CONFIG_START_NETWORK=n CONFIG_SPARSE_BSS=n +CONFIG_TPMFRONT=y -- 1.7.11.7
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/vtpm/vtpm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index aaf1a24..d576c8f 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -141,8 +141,6 @@ int check_ordinal(tpmcmd_t* tpmcmd) { static void main_loop(void) { tpmcmd_t* tpmcmd = NULL; - domid_t domid; /* Domid of frontend */ - unsigned int handle; /* handle of frontend */ int res = -1; info("VTPM Initializing\n"); @@ -162,15 +160,7 @@ static void main_loop(void) { goto abort_postpcrs; } - /* Wait for the frontend domain to connect */ - info("Waiting for frontend domain to connect.."); - if(tpmback_wait_for_frontend_connect(&domid, &handle) == 0) { - info("VTPM attached to Frontend %u/%u", (unsigned int) domid, handle); - } else { - error("Unable to attach to a frontend"); - } - - tpmcmd = tpmback_req(domid, handle); + tpmcmd = tpmback_req_any(); while(tpmcmd) { /* Handle the request */ if(tpmcmd->req_len) { @@ -194,7 +184,7 @@ static void main_loop(void) { tpmback_resp(tpmcmd); /* Wait for the next request */ - tpmcmd = tpmback_req(domid, handle); + tpmcmd = tpmback_req_any(); } -- 1.7.11.7
Daniel De Graaf
2012-Nov-30 14:49 UTC
[PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM
This allows the hardware TPM''s PCRs to be accessed from a vTPM for debugging and as a simple alternative to a deep quote in situations where the integrity of the vTPM''s own TCB is not in question. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 stubdom/vtpm-pcr-passthrough.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index 790b547..03ec07e 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -210,6 +210,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz patch -d $@ -p1 < vtpm-locality.patch patch -d $@ -p1 < vtpm-bufsize.patch patch -d $@ -p1 < vtpm-locality5-pcrs.patch + patch -d $@ -p1 < vtpm-pcr-passthrough.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-pcr-passthrough.patch b/stubdom/vtpm-pcr-passthrough.patch new file mode 100644 index 0000000..4e898a5 --- /dev/null +++ b/stubdom/vtpm-pcr-passthrough.patch @@ -0,0 +1,73 @@ +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c +index f8f7f0f..885af52 100644 +--- a/tpm/tpm_capability.c ++++ b/tpm/tpm_capability.c +@@ -72,7 +72,7 @@ static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, + switch (property) { + case TPM_CAP_PROP_PCR: + debug("[TPM_CAP_PROP_PCR]"); +- return return_UINT32(respSize, resp, TPM_NUM_PCR); ++ return return_UINT32(respSize, resp, TPM_NUM_PCR_V); + + case TPM_CAP_PROP_DIR: + debug("[TPM_CAP_PROP_DIR]"); +diff --git a/tpm/tpm_emulator_extern.h b/tpm/tpm_emulator_extern.h +index 36a32dd..77ed595 100644 +--- a/tpm/tpm_emulator_extern.h ++++ b/tpm/tpm_emulator_extern.h +@@ -56,6 +56,7 @@ void (*tpm_free)(/*const*/ void *ptr); + /* random numbers */ + + void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); ++void tpm_get_extern_pcr(int index, void *buf); + + /* usec since last call */ + +diff --git a/tpm/tpm_integrity.c b/tpm/tpm_integrity.c +index 66ece83..f3c4196 100644 +--- a/tpm/tpm_integrity.c ++++ b/tpm/tpm_integrity.c +@@ -56,8 +56,11 @@ TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, + TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) + { + info("TPM_PCRRead()"); +- if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; +- memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); ++ if (pcrIndex >= TPM_NUM_PCR_V) return TPM_BADINDEX; ++ if (pcrIndex >= TPM_NUM_PCR) ++ tpm_get_extern_pcr(pcrIndex - TPM_NUM_PCR, outDigest); ++ else ++ memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); + return TPM_SUCCESS; + } + +@@ -138,12 +141,15 @@ TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, + BYTE *buf, *ptr; + info("tpm_compute_pcr_digest()"); + /* create PCR composite */ +- if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR ++ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR_V + || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; + for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { + /* is PCR number i selected ? */ + if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { +- memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); ++ if (i >= TPM_NUM_PCR) ++ tpm_get_extern_pcr(i - TPM_NUM_PCR, &comp.pcrValue[j++]); ++ else ++ memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); + } + } + memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h +index 08cef1e..8c97fc5 100644 +--- a/tpm/tpm_structures.h ++++ b/tpm/tpm_structures.h +@@ -677,6 +677,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { + * Number of PCRs of the TPM (must be a multiple of eight) + */ + #define TPM_NUM_PCR 32 ++#define TPM_NUM_PCR_V (TPM_NUM_PCR + 24) + + /* + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c index 7eae98b..ed058fb 100644 --- a/stubdom/vtpm/vtpm_cmd.c +++ b/stubdom/vtpm/vtpm_cmd.c @@ -134,6 +134,44 @@ egress: } +extern struct tpmfront_dev* tpmfront_dev; +void tpm_get_extern_pcr(int index, void *buf) { + TPM_RESULT status = TPM_SUCCESS; + uint8_t* cmdbuf, *resp, *bptr; + size_t resplen = 0; + UINT32 len; + + /*Ask the real tpm for the PCR value */ + TPM_TAG tag = TPM_TAG_RQU_COMMAND; + UINT32 size; + TPM_COMMAND_CODE ord = TPM_ORD_PCRRead; + len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32); + + /*Create the raw tpm command */ + bptr = cmdbuf = malloc(size); + TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord)); + TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, index)); + + /* Send cmd, wait for response */ + TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), + ERR_TPMFRONT); + + bptr = resp; len = resplen; + TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED); + + //Check return status of command + CHECKSTATUSGOTO(ord, "TPM_PCRRead()"); + + //Get the PCR value out + TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, buf, 20), ERR_MALFORMED); + + goto egress; +abort_egress: + memset(buf, 0x20, 20); +egress: + free(cmdbuf); +} + TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length) { TPM_RESULT status = TPM_SUCCESS; -- 1.7.11.7
Samuel Thibault
2012-Dec-04 00:17 UTC
Re: [PATCH 7/9] stubdom/grub: send kernel measurements to vTPM
Daniel De Graaf, le Fri 30 Nov 2012 09:49:13 -0500, a écrit :> This allows a domU with an arbitrary kernel and initrd to take advantage > of the static root of trust provided by a vTPM. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Samuel
I let Matthew review the other patches. Samuel
Matthew Fioravante
2012-Dec-04 17:43 UTC
Re: [PATCH 2/9] stubdom/vtpm: Support locality field
Looks good, will need to test. Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> On 11/30/2012 09:49 AM, Daniel De Graaf wrote:> The vTPM protocol now contains a field allowing the locality of a > command to be specified; pass this to the TPM when processing a packet. > While the locality is not currently checked for validity, a binding > between locality and some distinguishing feature of the client domain > (such as the XSM label) will need to be defined in order to properly > support a multi-client vTPM. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/Makefile | 1 + > stubdom/vtpm-locality.patch | 50 +++++++++++++++++++++++++++++++++++++++++++++ > stubdom/vtpm/vtpm.c | 2 +- > 3 files changed, 52 insertions(+), 1 deletion(-) > create mode 100644 stubdom/vtpm-locality.patch > > diff --git a/stubdom/Makefile b/stubdom/Makefile > index fcc608e..683bc51 100644 > --- a/stubdom/Makefile > +++ b/stubdom/Makefile > @@ -207,6 +207,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz > tar xzf $< > mv tpm_emulator-$(TPMEMU_VERSION) $@ > patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; > + patch -d $@ -p1 < vtpm-locality.patch > mkdir $@/build > cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" > touch $@ > diff --git a/stubdom/vtpm-locality.patch b/stubdom/vtpm-locality.patch > new file mode 100644 > index 0000000..8ab7dea > --- /dev/null > +++ b/stubdom/vtpm-locality.patch > @@ -0,0 +1,50 @@ > +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c > +index 60bbb90..f8f7f0f 100644 > +--- a/tpm/tpm_capability.c > ++++ b/tpm/tpm_capability.c > +@@ -949,6 +949,8 @@ static TPM_RESULT set_vendor(UINT32 subCap, BYTE *setValue, > + UINT32 setValueSize, BOOL ownerAuth, > + BOOL deactivated, BOOL disabled) > + { > ++ if (tpmData.stany.flags.localityModifier != 8) > ++ return TPM_BAD_PARAMETER; > + /* set the capability area with the specified data, on failure > + deactivate the TPM */ > + switch (subCap) { > +diff --git a/tpm/tpm_cmd_handler.c b/tpm/tpm_cmd_handler.c > +index 288d1ce..9e1cfb4 100644 > +--- a/tpm/tpm_cmd_handler.c > ++++ b/tpm/tpm_cmd_handler.c > +@@ -4132,7 +4132,7 @@ void tpm_emulator_shutdown() > + tpm_extern_release(); > + } > + > +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size) > ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality) > + { > + TPM_REQUEST req; > + TPM_RESPONSE rsp; > +@@ -4140,7 +4140,9 @@ int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint3 > + UINT32 len; > + BOOL free_out; > + > +- debug("tpm_handle_command()"); > ++ debug("tpm_handle_command(%d)", locality); > ++ if (locality != -1) > ++ tpmData.stany.flags.localityModifier = locality; > + > + /* we need the whole packet at once, otherwise unmarshalling will fail */ > + if (tpm_unmarshal_TPM_REQUEST((uint8_t**)&in, &in_size, &req) != 0) { > +diff --git a/tpm/tpm_emulator.h b/tpm/tpm_emulator.h > +index eed749e..4c228bd 100644 > +--- a/tpm/tpm_emulator.h > ++++ b/tpm/tpm_emulator.h > +@@ -59,7 +59,7 @@ void tpm_emulator_shutdown(void); > + * its usage. In case of an error, all internally allocated memory > + * is released and the the state of out and out_size is unspecified. > + */ > +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size); > ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality); > + > + #endif /* _TPM_EMULATOR_H_ */ > + > diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c > index 71aef78..eb7912f 100644 > --- a/stubdom/vtpm/vtpm.c > +++ b/stubdom/vtpm/vtpm.c > @@ -183,7 +183,7 @@ static void main_loop(void) { > } > /* If not disabled, do the command */ > else { > - if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len)) != 0) { > + if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len, tpmcmd->locality)) != 0) { > error("tpm_handle_command() failed"); > create_error_response(tpmcmd, TPM_FAIL); > }_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Dec-04 17:44 UTC
Re: [PATCH 7/9] stubdom/grub: send kernel measurements to vTPM
Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> On 11/30/2012 09:49 AM, Daniel De Graaf wrote:> This allows a domU with an arbitrary kernel and initrd to take advantage > of the static root of trust provided by a vTPM. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/Makefile | 2 +- > stubdom/grub/Makefile | 1 + > stubdom/grub/kexec.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ > stubdom/grub/minios.cfg | 1 + > 4 files changed, 57 insertions(+), 1 deletion(-) > > diff --git a/stubdom/Makefile b/stubdom/Makefile > index 4744b79..790b547 100644 > --- a/stubdom/Makefile > +++ b/stubdom/Makefile > @@ -399,7 +399,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar.gz > done > > .PHONY: grub > -grub: grub-upstream $(CROSS_ROOT) > +grub: cross-polarssl grub-upstream $(CROSS_ROOT) > mkdir -p grub-$(XEN_TARGET_ARCH) > CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) DESTDIR= -C $@ OBJ_DIR=$(CURDIR)/grub-$(XEN_TARGET_ARCH) > > diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile > index d6e3a1e..6bd2c4c 100644 > --- a/stubdom/grub/Makefile > +++ b/stubdom/grub/Makefile > @@ -60,6 +60,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) > $(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__ > > PV_GRUB_SOURCES = kexec.c mini-os.c > +PV_GRUB_SOURCES += ../polarssl-$(XEN_TARGET_ARCH)/library/sha1.o > > SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES) > > diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c > index b21c91a..cef357e 100644 > --- a/stubdom/grub/kexec.c > +++ b/stubdom/grub/kexec.c > @@ -28,7 +28,9 @@ > #include <blkfront.h> > #include <netfront.h> > #include <fbfront.h> > +#include <tpmfront.h> > #include <shared.h> > +#include <byteswap.h> > > #include "mini-os.h" > > @@ -54,6 +56,22 @@ static unsigned long allocated; > int pin_table(xc_interface *xc_handle, unsigned int type, unsigned long mfn, > domid_t dom); > > +#define TPM_TAG_RQU_COMMAND 0xC1 > +#define TPM_ORD_Extend 20 > + > +struct pcr_extend_cmd { > + uint16_t tag; > + uint32_t size; > + uint32_t ord; > + > + uint32_t pcr; > + unsigned char hash[20]; > +} __attribute__((packed)); > + > +/* Not imported from polarssl''s header since the prototype unhelpfully defines > + * the input as unsigned char, which causes pointer type mismatches */ > +void sha1(const void *input, size_t ilen, unsigned char output[20]); > + > /* We need mfn to appear as target_pfn, so exchange with the MFN there */ > static void do_exchange(struct xc_dom_image *dom, xen_pfn_t target_pfn, xen_pfn_t source_mfn) > { > @@ -117,6 +135,40 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) > return 0; > } > > +static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline) > +{ > + struct tpmfront_dev* tpm = init_tpmfront(NULL); > + uint8_t *resp; > + size_t resplen = 0; > + struct pcr_extend_cmd cmd; > + > + /* If all guests have access to a vTPM, it may be useful to replace this > + * with ASSERT(tpm) to prevent configuration errors from allowing a guest > + * to boot without a TPM (or with a TPM that has not been sent any > + * measurements, which could allow forging the measurements). > + */ > + if (!tpm) > + return; > + > + cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND); > + cmd.size = bswap_32(sizeof(cmd)); > + cmd.ord = bswap_32(TPM_ORD_Extend); > + cmd.pcr = bswap_32(4); // PCR #4 for kernel > + sha1(dom->kernel_blob, dom->kernel_size, cmd.hash); > + > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + cmd.pcr = bswap_32(5); // PCR #5 for cmdline > + sha1(cmdline, strlen(cmdline), cmd.hash); > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + cmd.pcr = bswap_32(5); // PCR #5 for initrd > + sha1(dom->ramdisk_blob, dom->ramdisk_size, cmd.hash); > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + shutdown_tpmfront(tpm); > +} > + > void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) > { > struct xc_dom_image *dom; > @@ -151,6 +203,8 @@ void kexec(void *kernel, long kernel_size, void *module, long module_size, char > dom->console_evtchn = start_info.console.domU.evtchn; > dom->xenstore_evtchn = start_info.store_evtchn; > > + tpm_hash2pcr(dom, cmdline); > + > if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) { > grub_printf("xc_dom_boot_xen_init returned %d\n", rc); > errnum = ERR_BOOT_FAILURE; > diff --git a/stubdom/grub/minios.cfg b/stubdom/grub/minios.cfg > index 40cfa68..8df4909 100644 > --- a/stubdom/grub/minios.cfg > +++ b/stubdom/grub/minios.cfg > @@ -1,2 +1,3 @@ > CONFIG_START_NETWORK=n > CONFIG_SPARSE_BSS=n > +CONFIG_TPMFRONT=y_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Dec-04 17:47 UTC
Re: [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM
So this maps a fixed set of PCRs always? Is there any use case where the user might want the PCR mappings to be configurable? Might they want to disable this feature to disallow Hardware PCR access in the vm? Also can you update the docs/misc/vtpm.txt documentation with a note about this and the grub feature? On 11/30/2012 09:49 AM, Daniel De Graaf wrote:> This allows the hardware TPM''s PCRs to be accessed from a vTPM for > debugging and as a simple alternative to a deep quote in situations > where the integrity of the vTPM''s own TCB is not in question. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/Makefile | 1 + > stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ > stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ > 3 files changed, 112 insertions(+) > create mode 100644 stubdom/vtpm-pcr-passthrough.patch > > diff --git a/stubdom/Makefile b/stubdom/Makefile > index 790b547..03ec07e 100644 > --- a/stubdom/Makefile > +++ b/stubdom/Makefile > @@ -210,6 +210,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz > patch -d $@ -p1 < vtpm-locality.patch > patch -d $@ -p1 < vtpm-bufsize.patch > patch -d $@ -p1 < vtpm-locality5-pcrs.patch > + patch -d $@ -p1 < vtpm-pcr-passthrough.patch > mkdir $@/build > cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" > touch $@ > diff --git a/stubdom/vtpm-pcr-passthrough.patch b/stubdom/vtpm-pcr-passthrough.patch > new file mode 100644 > index 0000000..4e898a5 > --- /dev/null > +++ b/stubdom/vtpm-pcr-passthrough.patch > @@ -0,0 +1,73 @@ > +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c > +index f8f7f0f..885af52 100644 > +--- a/tpm/tpm_capability.c > ++++ b/tpm/tpm_capability.c > +@@ -72,7 +72,7 @@ static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, > + switch (property) { > + case TPM_CAP_PROP_PCR: > + debug("[TPM_CAP_PROP_PCR]"); > +- return return_UINT32(respSize, resp, TPM_NUM_PCR); > ++ return return_UINT32(respSize, resp, TPM_NUM_PCR_V); > + > + case TPM_CAP_PROP_DIR: > + debug("[TPM_CAP_PROP_DIR]"); > +diff --git a/tpm/tpm_emulator_extern.h b/tpm/tpm_emulator_extern.h > +index 36a32dd..77ed595 100644 > +--- a/tpm/tpm_emulator_extern.h > ++++ b/tpm/tpm_emulator_extern.h > +@@ -56,6 +56,7 @@ void (*tpm_free)(/*const*/ void *ptr); > + /* random numbers */ > + > + void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); > ++void tpm_get_extern_pcr(int index, void *buf); > + > + /* usec since last call */ > + > +diff --git a/tpm/tpm_integrity.c b/tpm/tpm_integrity.c > +index 66ece83..f3c4196 100644 > +--- a/tpm/tpm_integrity.c > ++++ b/tpm/tpm_integrity.c > +@@ -56,8 +56,11 @@ TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, > + TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) > + { > + info("TPM_PCRRead()"); > +- if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; > +- memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); > ++ if (pcrIndex >= TPM_NUM_PCR_V) return TPM_BADINDEX; > ++ if (pcrIndex >= TPM_NUM_PCR) > ++ tpm_get_extern_pcr(pcrIndex - TPM_NUM_PCR, outDigest); > ++ else > ++ memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); > + return TPM_SUCCESS; > + } > + > +@@ -138,12 +141,15 @@ TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, > + BYTE *buf, *ptr; > + info("tpm_compute_pcr_digest()"); > + /* create PCR composite */ > +- if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR > ++ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR_V > + || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; > + for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { > + /* is PCR number i selected ? */ > + if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { > +- memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); > ++ if (i >= TPM_NUM_PCR) > ++ tpm_get_extern_pcr(i - TPM_NUM_PCR, &comp.pcrValue[j++]); > ++ else > ++ memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); > + } > + } > + memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); > +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h > +index 08cef1e..8c97fc5 100644 > +--- a/tpm/tpm_structures.h > ++++ b/tpm/tpm_structures.h > +@@ -677,6 +677,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { > + * Number of PCRs of the TPM (must be a multiple of eight) > + */ > + #define TPM_NUM_PCR 32 > ++#define TPM_NUM_PCR_V (TPM_NUM_PCR + 24) > + > + /* > + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) > diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c > index 7eae98b..ed058fb 100644 > --- a/stubdom/vtpm/vtpm_cmd.c > +++ b/stubdom/vtpm/vtpm_cmd.c > @@ -134,6 +134,44 @@ egress: > > } > > +extern struct tpmfront_dev* tpmfront_dev; > +void tpm_get_extern_pcr(int index, void *buf) { > + TPM_RESULT status = TPM_SUCCESS; > + uint8_t* cmdbuf, *resp, *bptr; > + size_t resplen = 0; > + UINT32 len; > + > + /*Ask the real tpm for the PCR value */ > + TPM_TAG tag = TPM_TAG_RQU_COMMAND; > + UINT32 size; > + TPM_COMMAND_CODE ord = TPM_ORD_PCRRead; > + len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32); > + > + /*Create the raw tpm command */ > + bptr = cmdbuf = malloc(size); > + TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord)); > + TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, index)); > + > + /* Send cmd, wait for response */ > + TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), > + ERR_TPMFRONT); > + > + bptr = resp; len = resplen; > + TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED); > + > + //Check return status of command > + CHECKSTATUSGOTO(ord, "TPM_PCRRead()"); > + > + //Get the PCR value out > + TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, buf, 20), ERR_MALFORMED); > + > + goto egress; > +abort_egress: > + memset(buf, 0x20, 20); > +egress: > + free(cmdbuf); > +} > + > TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length) > { > TPM_RESULT status = TPM_SUCCESS;_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Dec-04 18:43 UTC
Re: [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM
On 12/04/2012 12:47 PM, Matthew Fioravante wrote:> So this maps a fixed set of PCRs always?Yes; and making them not the last 24 (or last N) PCRs requires a more complex patch, since the PCR-modification code also needs to be changed.> Is there any use case where the user might want the PCR mappings to be configurable? Might they want to disable this feature to disallow Hardware PCR access in the vm?I think all of these configuration options will be needed for this to be truly useful in an upstream vTPM implementation; however, they require more significant changes to the TPM emulator itself, since values that are currently #defines need to be changed to be configurable at TPM creation. Adding more configuration will also eventually run past the limits of what is reasonable to place on the vTPM''s command line, so it may be useful to consider how to define this type of configuration so that it still ends up in the vTPM''s measurement when create by a measuring domain builder (hash of a config struct on the command line). Things that I think could be configurable: * Localities and what domains can use them (I have a command-line based patch for this). * PCRs beyond the defined minimum (currently 24): what localities have extend/clear access to them, or what HW-PCR they are mapped to * Maximum sizes of TPM items: NV area, counters, sessions, etc TPM version 2.0 may address some of these issues in the specification, so it may be reasonable to require compile-time configuration for a 1.2 TPM, and allow the owner to define the rest at runtime in a 2.0 TPM.> Also can you update the docs/misc/vtpm.txt documentation with a note about this and the grub feature?Sure.> On 11/30/2012 09:49 AM, Daniel De Graaf wrote: >> This allows the hardware TPM''s PCRs to be accessed from a vTPM for >> debugging and as a simple alternative to a deep quote in situations >> where the integrity of the vTPM''s own TCB is not in question. >> >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >> --- >> stubdom/Makefile | 1 + >> stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ >> stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ >> 3 files changed, 112 insertions(+) >> create mode 100644 stubdom/vtpm-pcr-passthrough.patch >> >> diff --git a/stubdom/Makefile b/stubdom/Makefile >> index 790b547..03ec07e 100644 >> --- a/stubdom/Makefile >> +++ b/stubdom/Makefile >> @@ -210,6 +210,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz >> patch -d $@ -p1 < vtpm-locality.patch >> patch -d $@ -p1 < vtpm-bufsize.patch >> patch -d $@ -p1 < vtpm-locality5-pcrs.patch >> + patch -d $@ -p1 < vtpm-pcr-passthrough.patch >> mkdir $@/build >> cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" >> touch $@ >> diff --git a/stubdom/vtpm-pcr-passthrough.patch b/stubdom/vtpm-pcr-passthrough.patch >> new file mode 100644 >> index 0000000..4e898a5 >> --- /dev/null >> +++ b/stubdom/vtpm-pcr-passthrough.patch >> @@ -0,0 +1,73 @@ >> +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c >> +index f8f7f0f..885af52 100644 >> +--- a/tpm/tpm_capability.c >> ++++ b/tpm/tpm_capability.c >> +@@ -72,7 +72,7 @@ static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, >> + switch (property) { >> + case TPM_CAP_PROP_PCR: >> + debug("[TPM_CAP_PROP_PCR]"); >> +- return return_UINT32(respSize, resp, TPM_NUM_PCR); >> ++ return return_UINT32(respSize, resp, TPM_NUM_PCR_V); >> + >> + case TPM_CAP_PROP_DIR: >> + debug("[TPM_CAP_PROP_DIR]"); >> +diff --git a/tpm/tpm_emulator_extern.h b/tpm/tpm_emulator_extern.h >> +index 36a32dd..77ed595 100644 >> +--- a/tpm/tpm_emulator_extern.h >> ++++ b/tpm/tpm_emulator_extern.h >> +@@ -56,6 +56,7 @@ void (*tpm_free)(/*const*/ void *ptr); >> + /* random numbers */ >> + >> + void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); >> ++void tpm_get_extern_pcr(int index, void *buf); >> + >> + /* usec since last call */ >> + >> +diff --git a/tpm/tpm_integrity.c b/tpm/tpm_integrity.c >> +index 66ece83..f3c4196 100644 >> +--- a/tpm/tpm_integrity.c >> ++++ b/tpm/tpm_integrity.c >> +@@ -56,8 +56,11 @@ TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, >> + TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) >> + { >> + info("TPM_PCRRead()"); >> +- if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; >> +- memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); >> ++ if (pcrIndex >= TPM_NUM_PCR_V) return TPM_BADINDEX; >> ++ if (pcrIndex >= TPM_NUM_PCR) >> ++ tpm_get_extern_pcr(pcrIndex - TPM_NUM_PCR, outDigest); >> ++ else >> ++ memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); >> + return TPM_SUCCESS; >> + } >> + >> +@@ -138,12 +141,15 @@ TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, >> + BYTE *buf, *ptr; >> + info("tpm_compute_pcr_digest()"); >> + /* create PCR composite */ >> +- if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR >> ++ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR_V >> + || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; >> + for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { >> + /* is PCR number i selected ? */ >> + if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { >> +- memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); >> ++ if (i >= TPM_NUM_PCR) >> ++ tpm_get_extern_pcr(i - TPM_NUM_PCR, &comp.pcrValue[j++]); >> ++ else >> ++ memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); >> + } >> + } >> + memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); >> +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h >> +index 08cef1e..8c97fc5 100644 >> +--- a/tpm/tpm_structures.h >> ++++ b/tpm/tpm_structures.h >> +@@ -677,6 +677,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { >> + * Number of PCRs of the TPM (must be a multiple of eight) >> + */ >> + #define TPM_NUM_PCR 32 >> ++#define TPM_NUM_PCR_V (TPM_NUM_PCR + 24) >> + >> + /* >> + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) >> diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c >> index 7eae98b..ed058fb 100644 >> --- a/stubdom/vtpm/vtpm_cmd.c >> +++ b/stubdom/vtpm/vtpm_cmd.c >> @@ -134,6 +134,44 @@ egress: >> } >> +extern struct tpmfront_dev* tpmfront_dev; >> +void tpm_get_extern_pcr(int index, void *buf) { >> + TPM_RESULT status = TPM_SUCCESS; >> + uint8_t* cmdbuf, *resp, *bptr; >> + size_t resplen = 0; >> + UINT32 len; >> + >> + /*Ask the real tpm for the PCR value */ >> + TPM_TAG tag = TPM_TAG_RQU_COMMAND; >> + UINT32 size; >> + TPM_COMMAND_CODE ord = TPM_ORD_PCRRead; >> + len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32); >> + >> + /*Create the raw tpm command */ >> + bptr = cmdbuf = malloc(size); >> + TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord)); >> + TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, index)); >> + >> + /* Send cmd, wait for response */ >> + TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), >> + ERR_TPMFRONT); >> + >> + bptr = resp; len = resplen; >> + TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED); >> + >> + //Check return status of command >> + CHECKSTATUSGOTO(ord, "TPM_PCRRead()"); >> + >> + //Get the PCR value out >> + TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, buf, 20), ERR_MALFORMED); >> + >> + goto egress; >> +abort_egress: >> + memset(buf, 0x20, 20); >> +egress: >> + free(cmdbuf); >> +} >> + >> TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length) >> { >> TPM_RESULT status = TPM_SUCCESS; > >-- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Dec-04 18:53 UTC
Re: [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM
Sounds good. Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> On 12/04/2012 01:43 PM, Daniel De Graaf wrote:> On 12/04/2012 12:47 PM, Matthew Fioravante wrote: >> So this maps a fixed set of PCRs always? > Yes; and making them not the last 24 (or last N) PCRs requires a more > complex patch, since the PCR-modification code also needs to be changed. > >> Is there any use case where the user might want the PCR mappings to be configurable? Might they want to disable this feature to disallow Hardware PCR access in the vm? > I think all of these configuration options will be needed for this to be > truly useful in an upstream vTPM implementation; however, they require > more significant changes to the TPM emulator itself, since values that > are currently #defines need to be changed to be configurable at TPM > creation. Adding more configuration will also eventually run past the > limits of what is reasonable to place on the vTPM''s command line, so it > may be useful to consider how to define this type of configuration so > that it still ends up in the vTPM''s measurement when create by a > measuring domain builder (hash of a config struct on the command line). > > Things that I think could be configurable: > * Localities and what domains can use them (I have a command-line > based patch for this). > * PCRs beyond the defined minimum (currently 24): what localities have > extend/clear access to them, or what HW-PCR they are mapped to > * Maximum sizes of TPM items: NV area, counters, sessions, etc > > TPM version 2.0 may address some of these issues in the specification, > so it may be reasonable to require compile-time configuration for a 1.2 > TPM, and allow the owner to define the rest at runtime in a 2.0 TPM. > >> Also can you update the docs/misc/vtpm.txt documentation with a note about this and the grub feature? > Sure. > >> On 11/30/2012 09:49 AM, Daniel De Graaf wrote: >>> This allows the hardware TPM''s PCRs to be accessed from a vTPM for >>> debugging and as a simple alternative to a deep quote in situations >>> where the integrity of the vTPM''s own TCB is not in question. >>> >>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>> --- >>> stubdom/Makefile | 1 + >>> stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ >>> stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ >>> 3 files changed, 112 insertions(+) >>> create mode 100644 stubdom/vtpm-pcr-passthrough.patch >>> >>> diff --git a/stubdom/Makefile b/stubdom/Makefile >>> index 790b547..03ec07e 100644 >>> --- a/stubdom/Makefile >>> +++ b/stubdom/Makefile >>> @@ -210,6 +210,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz >>> patch -d $@ -p1 < vtpm-locality.patch >>> patch -d $@ -p1 < vtpm-bufsize.patch >>> patch -d $@ -p1 < vtpm-locality5-pcrs.patch >>> + patch -d $@ -p1 < vtpm-pcr-passthrough.patch >>> mkdir $@/build >>> cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" >>> touch $@ >>> diff --git a/stubdom/vtpm-pcr-passthrough.patch b/stubdom/vtpm-pcr-passthrough.patch >>> new file mode 100644 >>> index 0000000..4e898a5 >>> --- /dev/null >>> +++ b/stubdom/vtpm-pcr-passthrough.patch >>> @@ -0,0 +1,73 @@ >>> +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c >>> +index f8f7f0f..885af52 100644 >>> +--- a/tpm/tpm_capability.c >>> ++++ b/tpm/tpm_capability.c >>> +@@ -72,7 +72,7 @@ static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, >>> + switch (property) { >>> + case TPM_CAP_PROP_PCR: >>> + debug("[TPM_CAP_PROP_PCR]"); >>> +- return return_UINT32(respSize, resp, TPM_NUM_PCR); >>> ++ return return_UINT32(respSize, resp, TPM_NUM_PCR_V); >>> + >>> + case TPM_CAP_PROP_DIR: >>> + debug("[TPM_CAP_PROP_DIR]"); >>> +diff --git a/tpm/tpm_emulator_extern.h b/tpm/tpm_emulator_extern.h >>> +index 36a32dd..77ed595 100644 >>> +--- a/tpm/tpm_emulator_extern.h >>> ++++ b/tpm/tpm_emulator_extern.h >>> +@@ -56,6 +56,7 @@ void (*tpm_free)(/*const*/ void *ptr); >>> + /* random numbers */ >>> + >>> + void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); >>> ++void tpm_get_extern_pcr(int index, void *buf); >>> + >>> + /* usec since last call */ >>> + >>> +diff --git a/tpm/tpm_integrity.c b/tpm/tpm_integrity.c >>> +index 66ece83..f3c4196 100644 >>> +--- a/tpm/tpm_integrity.c >>> ++++ b/tpm/tpm_integrity.c >>> +@@ -56,8 +56,11 @@ TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, >>> + TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) >>> + { >>> + info("TPM_PCRRead()"); >>> +- if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; >>> +- memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); >>> ++ if (pcrIndex >= TPM_NUM_PCR_V) return TPM_BADINDEX; >>> ++ if (pcrIndex >= TPM_NUM_PCR) >>> ++ tpm_get_extern_pcr(pcrIndex - TPM_NUM_PCR, outDigest); >>> ++ else >>> ++ memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); >>> + return TPM_SUCCESS; >>> + } >>> + >>> +@@ -138,12 +141,15 @@ TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, >>> + BYTE *buf, *ptr; >>> + info("tpm_compute_pcr_digest()"); >>> + /* create PCR composite */ >>> +- if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR >>> ++ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR_V >>> + || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; >>> + for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { >>> + /* is PCR number i selected ? */ >>> + if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { >>> +- memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); >>> ++ if (i >= TPM_NUM_PCR) >>> ++ tpm_get_extern_pcr(i - TPM_NUM_PCR, &comp.pcrValue[j++]); >>> ++ else >>> ++ memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); >>> + } >>> + } >>> + memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); >>> +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h >>> +index 08cef1e..8c97fc5 100644 >>> +--- a/tpm/tpm_structures.h >>> ++++ b/tpm/tpm_structures.h >>> +@@ -677,6 +677,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { >>> + * Number of PCRs of the TPM (must be a multiple of eight) >>> + */ >>> + #define TPM_NUM_PCR 32 >>> ++#define TPM_NUM_PCR_V (TPM_NUM_PCR + 24) >>> + >>> + /* >>> + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) >>> diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c >>> index 7eae98b..ed058fb 100644 >>> --- a/stubdom/vtpm/vtpm_cmd.c >>> +++ b/stubdom/vtpm/vtpm_cmd.c >>> @@ -134,6 +134,44 @@ egress: >>> } >>> +extern struct tpmfront_dev* tpmfront_dev; >>> +void tpm_get_extern_pcr(int index, void *buf) { >>> + TPM_RESULT status = TPM_SUCCESS; >>> + uint8_t* cmdbuf, *resp, *bptr; >>> + size_t resplen = 0; >>> + UINT32 len; >>> + >>> + /*Ask the real tpm for the PCR value */ >>> + TPM_TAG tag = TPM_TAG_RQU_COMMAND; >>> + UINT32 size; >>> + TPM_COMMAND_CODE ord = TPM_ORD_PCRRead; >>> + len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32); >>> + >>> + /*Create the raw tpm command */ >>> + bptr = cmdbuf = malloc(size); >>> + TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord)); >>> + TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, index)); >>> + >>> + /* Send cmd, wait for response */ >>> + TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), >>> + ERR_TPMFRONT); >>> + >>> + bptr = resp; len = resplen; >>> + TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED); >>> + >>> + //Check return status of command >>> + CHECKSTATUSGOTO(ord, "TPM_PCRRead()"); >>> + >>> + //Get the PCR value out >>> + TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, buf, 20), ERR_MALFORMED); >>> + >>> + goto egress; >>> +abort_egress: >>> + memset(buf, 0x20, 20); >>> +egress: >>> + free(cmdbuf); >>> +} >>> + >>> TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length) >>> { >>> TPM_RESULT status = TPM_SUCCESS; >> >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Have you given any thought to the vtpm auto-shutdown semantics? I''d like to preserve that if at all possible. Is the only conflicting patch there patch 8? On 11/30/2012 09:49 AM, Daniel De Graaf wrote:> This patch queue goes on top of Matthew Fioravante''s [VTPM v5 0/7] > series. While some of the patches have been posted before, all have > been cleaned up a bit. > > [PATCH 1/9] stubdom: Change vTPM shared page ABI > * Removed unneeded reconfiguration pieces > * Removed feature-protocol-v2 xenstore key references > > [PATCH 2/9] stubdom/vtpm: Support locality field > * Add distinct patch file instead of patching a patch > * Comment on future use of the locality field > > [PATCH 3/9] stubdom/vtpm: correct the buffer size returned by > * New patch > > [PATCH 4/9] stubdom/vtpm: Add locality-5 PCRs > * New patch > > [PATCH 5/9] stubdom/vtpm: Allow repoen of closed devices > * This used to use Reconfigure, but has been changed to use > the Closed states similar to blkback > > [PATCH 6/9] stubdom/vtpm: make state save operation atomic > * Avoid hardcoded maximum saved state size > * Better debug/error messages > > [PATCH 7/9] stubdom/grub: send kernel measurements to vTPM > * Use PolarSSL SHA1 function > * Use byteswap.h functions > > [PATCH 8/9] stubdom/vtpm: support multiple backends > * Split into its own patch so it can be excluded if > automatic vTPM shutdown is required > > [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM > * New patch, RFC; an alternative to hwinitpcrs_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
On 12/04/2012 01:55 PM, Matthew Fioravante wrote:> Have you given any thought to the vtpm auto-shutdown semantics? I''d like to preserve that if at all possible. Is the only conflicting patch there patch 8? >#8 should be the only patch that conflicts, although I have not tested that the shutdown works as expected after #5. I think the shutdown key in Xenstore is the best solution for this issue (and don''t really have a strong preference for weak function vs a waitqueue).> On 11/30/2012 09:49 AM, Daniel De Graaf wrote: >> This patch queue goes on top of Matthew Fioravante''s [VTPM v5 0/7] >> series. While some of the patches have been posted before, all have >> been cleaned up a bit. >> >> [PATCH 1/9] stubdom: Change vTPM shared page ABI >> * Removed unneeded reconfiguration pieces >> * Removed feature-protocol-v2 xenstore key references >> >> [PATCH 2/9] stubdom/vtpm: Support locality field >> * Add distinct patch file instead of patching a patch >> * Comment on future use of the locality field >> >> [PATCH 3/9] stubdom/vtpm: correct the buffer size returned by >> * New patch >> >> [PATCH 4/9] stubdom/vtpm: Add locality-5 PCRs >> * New patch >> >> [PATCH 5/9] stubdom/vtpm: Allow repoen of closed devices >> * This used to use Reconfigure, but has been changed to use >> the Closed states similar to blkback >> >> [PATCH 6/9] stubdom/vtpm: make state save operation atomic >> * Avoid hardcoded maximum saved state size >> * Better debug/error messages >> >> [PATCH 7/9] stubdom/grub: send kernel measurements to vTPM >> * Use PolarSSL SHA1 function >> * Use byteswap.h functions >> >> [PATCH 8/9] stubdom/vtpm: support multiple backends >> * Split into its own patch so it can be excluded if >> automatic vTPM shutdown is required >> >> [PATCH 9/9] stubdom/vtpm: Add PCR pass-through to hardware TPM >> * New patch, RFC; an alternative to hwinitpcrs > >-- Daniel De Graaf National Security Agency