Since the vTPM implementations are being incorproated into Xen and possibly upstream Linux, I would like to see if this protocol change could be added before we have significant legacy implementations. If not, I still think it would be useful as either a v2 or negotiated protocol change. The current vTPM protocol is a copy of the network protocol. This was likely done for ease of implementation, since support for the network backend/frontend existed in Linux and minios. However, this implementation is overly complex when dealing with vTPM packets: for example, a vTPM never needs to deal with having more than one packet in flight at any given time. I will send the corresponding patch for the Linux kernel module once I have adapted it for the file names used in the upstream version. ------------------------------------>8---------------------------------- 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. 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 | 132 ++++++++++++++------------------- extras/mini-os/tpmfront.c | 150 +++++++++++++++++++------------------- xen/include/public/io/tpmif.h | 45 +++--------- 5 files changed, 148 insertions(+), 187 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..29aced9 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; @@ -386,8 +383,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 +391,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 +423,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 +473,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 +516,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 +573,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,10 +605,28 @@ 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; } +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, XenbusStateReconfigured); + + 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); @@ -874,6 +879,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 +890,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 +905,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 +951,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 +982,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..bcee93d 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) } +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* path) +{ + int state; + + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); + while(1) { + state = xenbus_read_integer(path); + if ( state < 0) + state = XenbusStateUnknown; + switch(state) { + case XenbusStateUnknown: + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); + return -1; + case XenbusStateClosed: + TPMFRONT_LOG("Backend Closed\n"); + return 0; + case XenbusStateReconfigured: + TPMFRONT_LOG("Backend Reconfigured\n"); + return 0; + default: + xenbus_wait_for_watch(events); + } + } + +} + static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { char* err; int ret = 0; @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState case XenbusStateClosed: ret = wait_for_backend_closed(&events, path); break; - default: + case XenbusStateReconfigured: + ret = wait_for_backend_reconfig(&events, path); break; + default: + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +219,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 +257,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 +269,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 +317,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,12 +329,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } - TPMFRONT_LOG("Shutting down tpmfront\n"); + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); /* disconnect */ if(dev->state == XenbusStateConnected) { dev->state = XenbusStateClosing; @@ -349,27 +362,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 +385,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) { - int i; - tpmif_tx_request_t* tx = NULL; + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG +int i; +#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 +409,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 +433,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 +500,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
Fioravante, Matthew E.
2012-Nov-20 16:16 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
This was something I''ve been wanting to do for a while so I''m very happy you went ahead and fixed it yourself. Once you submit the linux version I''ll test it on my system. Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> -----Original Message----- From: Daniel De Graaf [mailto:dgdegra@tycho.nsa.gov] Sent: Tuesday, November 20, 2012 11:11 AM To: Fioravante, Matthew E. Cc: xen-devel@lists.xen.org; Ian.Campbell@citrix.com; Daniel De Graaf Subject: [PATCH RFC] stubdom: Change vTPM shared page ABI Since the vTPM implementations are being incorproated into Xen and possibly upstream Linux, I would like to see if this protocol change could be added before we have significant legacy implementations. If not, I still think it would be useful as either a v2 or negotiated protocol change. The current vTPM protocol is a copy of the network protocol. This was likely done for ease of implementation, since support for the network backend/frontend existed in Linux and minios. However, this implementation is overly complex when dealing with vTPM packets: for example, a vTPM never needs to deal with having more than one packet in flight at any given time. I will send the corresponding patch for the Linux kernel module once I have adapted it for the file names used in the upstream version. ------------------------------------>8---------------------------------- 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. 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 | 132 ++++++++++++++------------------- extras/mini-os/tpmfront.c | 150 +++++++++++++++++++------------------- xen/include/public/io/tpmif.h | 45 +++--------- 5 files changed, 148 insertions(+), 187 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..29aced9 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; @@ -386,8 +383,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 +391,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 +423,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 +473,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 +516,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 +573,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,10 +605,28 @@ 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; } +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, XenbusStateReconfigured); + + 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); @@ -874,6 +879,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 +890,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 +905,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 +951,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 +982,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..bcee93d 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) } +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* +path) { + int state; + + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); + while(1) { + state = xenbus_read_integer(path); + if ( state < 0) + state = XenbusStateUnknown; + switch(state) { + case XenbusStateUnknown: + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); + return -1; + case XenbusStateClosed: + TPMFRONT_LOG("Backend Closed\n"); + return 0; + case XenbusStateReconfigured: + TPMFRONT_LOG("Backend Reconfigured\n"); + return 0; + default: + xenbus_wait_for_watch(events); + } + } + +} + static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { char* err; int ret = 0; @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState case XenbusStateClosed: ret = wait_for_backend_closed(&events, path); break; - default: + case XenbusStateReconfigured: + ret = wait_for_backend_reconfig(&events, path); break; + default: + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +219,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 +257,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 +269,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 +317,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,12 +329,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } - TPMFRONT_LOG("Shutting down tpmfront\n"); + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for + reconfigure" : ""); /* disconnect */ if(dev->state == XenbusStateConnected) { dev->state = XenbusStateClosing; @@ -349,27 +362,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 +385,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) { - int i; - tpmif_tx_request_t* tx = NULL; + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG +int i; +#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 +409,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 +433,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 +500,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
Daniel De Graaf
2012-Nov-20 18:24 UTC
[PATCH] drivers/tpm-xen: Change vTPM shared page ABI
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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/char/tpm/xen-tpmfront_if.c | 191 ++++++------------------------------- include/xen/interface/io/tpmif.h | 42 ++------ 2 files changed, 40 insertions(+), 193 deletions(-) diff --git a/drivers/char/tpm/xen-tpmfront_if.c b/drivers/char/tpm/xen-tpmfront_if.c index ba7fad8..02405af 100644 --- a/drivers/char/tpm/xen-tpmfront_if.c +++ b/drivers/char/tpm/xen-tpmfront_if.c @@ -53,7 +53,7 @@ struct tpm_private { struct tpm_chip *chip; - struct tpmif_tx_interface *tx; + struct vtpm_shared_page *page; atomic_t refcnt; unsigned int evtchn; u8 is_connected; @@ -61,8 +61,6 @@ struct tpm_private { spinlock_t tx_lock; - struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE]; - atomic_t tx_busy; void *tx_remember; @@ -73,15 +71,7 @@ struct tpm_private { int ring_ref; }; -struct tx_buffer { - unsigned int size; /* available space in data */ - unsigned int len; /* used space in data */ - unsigned char *data; /* pointer to a page */ -}; - - /* locally visible variables */ -static grant_ref_t gref_head; static struct tpm_private *my_priv; /* local function prototypes */ @@ -92,8 +82,6 @@ static int tpmif_connect(struct xenbus_device *dev, struct tpm_private *tp, domid_t domid); static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0); -static int tpmif_allocate_tx_buffers(struct tpm_private *tp); -static void tpmif_free_tx_buffers(struct tpm_private *tp); static void tpmif_set_connected_state(struct tpm_private *tp, u8 newstate); static int tpm_xmit(struct tpm_private *tp, @@ -101,52 +89,6 @@ static int tpm_xmit(struct tpm_private *tp, void *remember); static void destroy_tpmring(struct tpm_private *tp); -static inline int -tx_buffer_copy(struct tx_buffer *txb, const u8 *src, int len, - int isuserbuffer) -{ - int copied = len; - - if (len > txb->size) - copied = txb->size; - if (isuserbuffer) { - if (copy_from_user(txb->data, src, copied)) - return -EFAULT; - } else { - memcpy(txb->data, src, copied); - } - txb->len = len; - return copied; -} - -static inline struct tx_buffer *tx_buffer_alloc(void) -{ - struct tx_buffer *txb; - - txb = kzalloc(sizeof(struct tx_buffer), GFP_KERNEL); - if (!txb) - return NULL; - - txb->len = 0; - txb->size = PAGE_SIZE; - txb->data = (unsigned char *)__get_free_page(GFP_KERNEL); - if (txb->data == NULL) { - kfree(txb); - txb = NULL; - } - - return txb; -} - - -static inline void tx_buffer_free(struct tx_buffer *txb) -{ - if (txb) { - free_page((long)txb->data); - kfree(txb); - } -} - /************************************************************** Utility function for the tpm_private structure **************************************************************/ @@ -162,15 +104,12 @@ static void tpm_private_put(void) if (!atomic_dec_and_test(&my_priv->refcnt)) return; - tpmif_free_tx_buffers(my_priv); kfree(my_priv); my_priv = NULL; } static struct tpm_private *tpm_private_get(void) { - int err; - if (my_priv) { atomic_inc(&my_priv->refcnt); return my_priv; @@ -181,9 +120,6 @@ static struct tpm_private *tpm_private_get(void) return NULL; tpm_private_init(my_priv); - err = tpmif_allocate_tx_buffers(my_priv); - if (err < 0) - tpm_private_put(); return my_priv; } @@ -218,22 +154,22 @@ int vtpm_vd_send(struct tpm_private *tp, static int setup_tpmring(struct xenbus_device *dev, struct tpm_private *tp) { - struct tpmif_tx_interface *sring; + struct vtpm_shared_page *sring; int err; tp->ring_ref = GRANT_INVALID_REF; - sring = (void *)__get_free_page(GFP_KERNEL); + sring = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); return -ENOMEM; } - tp->tx = sring; + tp->page = sring; - err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx)); + err = xenbus_grant_ring(dev, virt_to_mfn(tp->page)); if (err < 0) { free_page((unsigned long)sring); - tp->tx = NULL; + tp->page = NULL; xenbus_dev_fatal(dev, err, "allocating grant reference"); goto fail; } @@ -256,9 +192,9 @@ static void destroy_tpmring(struct tpm_private *tp) if (tp->ring_ref != GRANT_INVALID_REF) { gnttab_end_foreign_access(tp->ring_ref, - 0, (unsigned long)tp->tx); + 0, (unsigned long)tp->page); tp->ring_ref = GRANT_INVALID_REF; - tp->tx = NULL; + tp->page = NULL; } if (tp->evtchn) @@ -470,62 +406,30 @@ static DEFINE_XENBUS_DRIVER(tpmfront, , .suspend = tpmfront_suspend, ); -static int tpmif_allocate_tx_buffers(struct tpm_private *tp) -{ - unsigned int i; - - for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { - tp->tx_buffers[i] = tx_buffer_alloc(); - if (!tp->tx_buffers[i]) { - tpmif_free_tx_buffers(tp); - return -ENOMEM; - } - } - return 0; -} - -static void tpmif_free_tx_buffers(struct tpm_private *tp) -{ - unsigned int i; - - for (i = 0; i < TPMIF_TX_RING_SIZE; i++) - tx_buffer_free(tp->tx_buffers[i]); -} - static void tpmif_rx_action(unsigned long priv) { struct tpm_private *tp = (struct tpm_private *)priv; - int i = 0; unsigned int received; unsigned int offset = 0; u8 *buffer; - struct tpmif_tx_request *tx = &tp->tx->ring[i].req; + struct vtpm_shared_page *shr = tp->page; atomic_set(&tp->tx_busy, 0); wake_up_interruptible(&tp->wait_q); - received = tx->size; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + received = shr->length; + + if (offset > PAGE_SIZE || offset + received > PAGE_SIZE) { + printk(KERN_WARNING "tpmif_rx_action packet too large\n"); + return; + } buffer = kmalloc(received, GFP_ATOMIC); if (!buffer) return; - for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) { - struct tx_buffer *txb = tp->tx_buffers[i]; - struct tpmif_tx_request *tx; - unsigned int tocopy; - - tx = &tp->tx->ring[i].req; - tocopy = tx->size; - if (tocopy > PAGE_SIZE) - tocopy = PAGE_SIZE; - - memcpy(&buffer[offset], txb->data, tocopy); - - gnttab_release_grant_reference(&gref_head, tx->ref); - - offset += tocopy; - } + memcpy(buffer, offset + (u8*)shr, received); vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember); kfree(buffer); @@ -550,8 +454,7 @@ static int tpm_xmit(struct tpm_private *tp, const u8 *buf, size_t count, int isuserbuffer, void *remember) { - struct tpmif_tx_request *tx; - int i; + struct vtpm_shared_page *shr; unsigned int offset = 0; spin_lock_irq(&tp->tx_lock); @@ -566,48 +469,23 @@ static int tpm_xmit(struct tpm_private *tp, return -EIO; } - for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) { - struct tx_buffer *txb = tp->tx_buffers[i]; - int copied; - - if (!txb) { - spin_unlock_irq(&tp->tx_lock); - return -EFAULT; - } - - copied = tx_buffer_copy(txb, &buf[offset], count, - isuserbuffer); - if (copied < 0) { - /* An error occurred */ - spin_unlock_irq(&tp->tx_lock); - return copied; - } - count -= copied; - offset += copied; - - tx = &tp->tx->ring[i].req; - tx->addr = virt_to_machine(txb->data).maddr; - tx->size = txb->len; - tx->unused = 0; - - /* Get the granttable reference for this page. */ - tx->ref = gnttab_claim_grant_reference(&gref_head); - if (tx->ref == -ENOSPC) { - spin_unlock_irq(&tp->tx_lock); - return -ENOSPC; - } - gnttab_grant_foreign_access_ref(tx->ref, - tp->backend_id, - virt_to_mfn(txb->data), - 0 /*RW*/); - wmb(); - } + shr = tp->page; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + + if (offset > PAGE_SIZE) + return -EIO; + + if (offset + count > PAGE_SIZE) + count = PAGE_SIZE - offset; + + memcpy(offset + (u8*)shr, buf, count); + shr->length = count; + barrier(); + shr->state = 1; atomic_set(&tp->tx_busy, 1); tp->tx_remember = remember; - mb(); - notify_remote_via_evtchn(tp->evtchn); spin_unlock_irq(&tp->tx_lock); @@ -667,12 +545,6 @@ static int __init tpmif_init(void) if (!tp) return -ENOMEM; - if (gnttab_alloc_grant_references(TPMIF_TX_RING_SIZE, - &gref_head) < 0) { - tpm_private_put(); - return -EFAULT; - } - return xenbus_register_frontend(&tpmfront_driver); } module_init(tpmif_init); @@ -680,7 +552,6 @@ module_init(tpmif_init); static void __exit tpmif_exit(void) { xenbus_unregister_driver(&tpmfront_driver); - gnttab_free_grant_references(gref_head); tpm_private_put(); } module_exit(tpmif_exit); diff --git a/include/xen/interface/io/tpmif.h b/include/xen/interface/io/tpmif.h index c9e7294..3d5c743 100644 --- a/include/xen/interface/io/tpmif.h +++ b/include/xen/interface/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,45 +21,21 @@ * 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 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. */ -}; -struct tpmif_tx_request; +struct vtpm_shared_page { + uint16_t length; /* request/response length in bytes */ -/* - * The TPMIF_TX_RING_SIZE defines the number of pages the - * front-end and backend can exchange (= size of array). - */ -#define TPMIF_TX_RING_SIZE 1 - -/* This structure must fit in a memory page. */ - -struct tpmif_ring { - struct tpmif_tx_request req; -}; -struct tpmif_ring; + 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 */ }; -struct tpmif_tx_interface; #endif -- 1.7.11.7
On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote:> This was something I''ve been wanting to do for a while so I''m very > happy you went ahead and fixed it yourself. Once you submit the linux > version I''ll test it on my system. > > Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu>Do we need to synchronise with anything else (Linux drivers?) or I can I just throw this into the tree once it is done? Are we hanging any existing users of the tpm stuff out to dry? Could we get a feature-protocol-v2 flag in xenstore so users at least get an error message from either the front or backend to give a hint why it isn''t working?> 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; > +#endifDodgy indentation? (I saw a bunch of these)> - * Copyright (c) 2005, IBM Corporation > - * > - * Author: Stefan Berger, stefanb@us.ibm.com > - * Grant table support: Mahadevan GomathisankaranDid you really remove everything these guys wrote?> - * This code has been derived from tools/libxc/xen/io/netif.h > - * > - * Copyright (c) 2003-2004, Keir FraserI guess I can buy this bit no longer being true given that you reworked the whole protocol. Ian
Daniel De Graaf
2012-Nov-23 16:15 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
On 11/23/2012 06:04 AM, Ian Campbell wrote:> On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: >> This was something I''ve been wanting to do for a while so I''m very >> happy you went ahead and fixed it yourself. Once you submit the linux >> version I''ll test it on my system. >> >> Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > > Do we need to synchronise with anything else (Linux drivers?) or I can I > just throw this into the tree once it is done?I think the only Linux drivers are the ones that were just posted, and the ones for XenLinux 2.6.18. Assuming the modified Linux module that I posted works as it should, the v2 version will be the only one upstream.> Are we hanging any existing users of the tpm stuff out to dry? Could we > get a feature-protocol-v2 flag in xenstore so users at least get an > error message from either the front or backend to give a hint why it > isn''t working?I suppose we could do that, although I''m not sure the "feature-" prefix is appropriate, since the code doesn''t have the ability to fall back to v1.>> 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 > > Dodgy indentation? (I saw a bunch of these)Whoops, I''ll have to go fix that. The entire mini-os build is sprinkled with tabs and spaces mostly at random, so perhaps a generic fix-indent patch is needed after all the real changes are applied.>> - * Copyright (c) 2005, IBM Corporation >> - * >> - * Author: Stefan Berger, stefanb@us.ibm.com >> - * Grant table support: Mahadevan Gomathisankaran > > Did you really remove everything these guys wrote?From this file, yes - unless the #ifndef and header/footer comments count, but I was under the impression that that is too small to count for copyright, and is duplicated across the other files in that directory anyway.>> - * This code has been derived from tools/libxc/xen/io/netif.h >> - * >> - * Copyright (c) 2003-2004, Keir Fraser > > I guess I can buy this bit no longer being true given that you reworked > the whole protocol. > > IanBasically, the file is a rewrite, although not detected by git/hg as such. I can add an authorship line if that would be helpful (I see that''s normal in other header files). -- Daniel De Graaf National Security Agency
On Fri, 2012-11-23 at 16:15 +0000, Daniel De Graaf wrote:> On 11/23/2012 06:04 AM, Ian Campbell wrote: > > On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: > >> This was something I''ve been wanting to do for a while so I''m very > >> happy you went ahead and fixed it yourself. Once you submit the linux > >> version I''ll test it on my system. > >> > >> Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > > > > Do we need to synchronise with anything else (Linux drivers?) or I can I > > just throw this into the tree once it is done? > > I think the only Linux drivers are the ones that were just posted, and the > ones for XenLinux 2.6.18.Which people might be using?> Assuming the modified Linux module that I posted > works as it should, the v2 version will be the only one upstream. > > > Are we hanging any existing users of the tpm stuff out to dry? Could we > > get a feature-protocol-v2 flag in xenstore so users at least get an > > error message from either the front or backend to give a hint why it > > isn''t working? > > I suppose we could do that, although I''m not sure the "feature-" prefix is > appropriate, since the code doesn''t have the ability to fall back to v1.I think if the "fallback" is printk("Protocol version mismatch") then that would suffice.> > >> 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 > > > > Dodgy indentation? (I saw a bunch of these) > > Whoops, I''ll have to go fix that. The entire mini-os build is sprinkled with > tabs and spaces mostly at random,Yeah it''s a mess AFAICT.> so perhaps a generic fix-indent patch is > needed after all the real changes are applied.It''s either that or just try and make things a bit better with each new patch. Is it supposed to be Xen coding style or something else I wonder. (I think it predates Samuel''s involvement, but lets ask him...) It would probably be useful to add the emacs magic to the various files.> > >> - * Copyright (c) 2005, IBM Corporation > >> - * > >> - * Author: Stefan Berger, stefanb@us.ibm.com > >> - * Grant table support: Mahadevan Gomathisankaran > > > > Did you really remove everything these guys wrote? > > From this file, yes - unless the #ifndef and header/footer comments count, but > I was under the impression that that is too small to count for copyright, and > is duplicated across the other files in that directory anyway.OK, I just get wary when I see copyright stuff changing ;-)> > >> - * This code has been derived from tools/libxc/xen/io/netif.h > >> - * > >> - * Copyright (c) 2003-2004, Keir Fraser > > > > I guess I can buy this bit no longer being true given that you reworked > > the whole protocol. > > > > Ian > > Basically, the file is a rewrite, although not detected by git/hg as such. I can > add an authorship line if that would be helpful (I see that''s normal in other > header files). >
Samuel Thibault
2012-Nov-23 17:37 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
Ian Campbell, le Fri 23 Nov 2012 16:30:17 +0000, a écrit :> > Whoops, I''ll have to go fix that. The entire mini-os build is sprinkled with > > tabs and spaces mostly at random, > > Yeah it''s a mess AFAICT. > > > so perhaps a generic fix-indent patch is > > needed after all the real changes are applied. > > It''s either that or just try and make things a bit better with each new > patch. > > Is it supposed to be Xen coding style or something else I wonder. (I > think it predates Samuel''s involvement, but lets ask him...)It does predate, yes.> It would probably be useful to add the emacs magic to the various files.That could help to keep the files themselves coherent, yes. Samuel
Fioravante, Matthew E.
2012-Nov-26 13:03 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
________________________________________ From: Daniel De Graaf [dgdegra@tycho.nsa.gov] Sent: Friday, November 23, 2012 11:15 AM To: Ian Campbell Cc: Fioravante, Matthew E.; xen-devel@lists.xen.org Subject: Re: [PATCH RFC] stubdom: Change vTPM shared page ABI On 11/23/2012 06:04 AM, Ian Campbell wrote:> On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: >> This was something I''ve been wanting to do for a while so I''m very >> happy you went ahead and fixed it yourself. Once you submit the linux >> version I''ll test it on my system. >> >> Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > > Do we need to synchronise with anything else (Linux drivers?) or I can I > just throw this into the tree once it is done?I think the only Linux drivers are the ones that were just posted, and the ones for XenLinux 2.6.18. Assuming the modified Linux module that I posted works as it should, the v2 version will be the only one upstream.> Are we hanging any existing users of the tpm stuff out to dry? Could we > get a feature-protocol-v2 flag in xenstore so users at least get an > error message from either the front or backend to give a hint why it > isn''t working?I suppose we could do that, although I''m not sure the "feature-" prefix is appropriate, since the code doesn''t have the ability to fall back to v1. I''d rather just let existing users hang out to dry. First off there aren''t really any existing users. Anyone who is or might be a user is probably following these threads closely. Second the xen tpm driver hasn''t even been accepted into linux yet so there really is not any "official" version 1. I can update the documentation to state the requirements on the new tpm driver version so that nobody tries to use the old version in the xen 2.6.18 tree.>> 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 > > Dodgy indentation? (I saw a bunch of these)Whoops, I''ll have to go fix that. The entire mini-os build is sprinkled with tabs and spaces mostly at random, so perhaps a generic fix-indent patch is needed after all the real changes are applied.>> - * Copyright (c) 2005, IBM Corporation >> - * >> - * Author: Stefan Berger, stefanb@us.ibm.com >> - * Grant table support: Mahadevan Gomathisankaran > > Did you really remove everything these guys wrote?From this file, yes - unless the #ifndef and header/footer comments count, but I was under the impression that that is too small to count for copyright, and is duplicated across the other files in that directory anyway.>> - * This code has been derived from tools/libxc/xen/io/netif.h >> - * >> - * Copyright (c) 2003-2004, Keir Fraser > > I guess I can buy this bit no longer being true given that you reworked > the whole protocol. > > IanBasically, the file is a rewrite, although not detected by git/hg as such. I can add an authorship line if that would be helpful (I see that''s normal in other header files). -- Daniel De Graaf National Security Agency
Fioravante, Matthew E.
2012-Nov-26 13:11 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
Ok outlook web email client is horrible. My reply was:>> Are we hanging any existing users of the tpm stuff out to dry? Could we >> get a feature-protocol-v2 flag in xenstore so users at least get an >> error message from either the front or backend to give a hint why it >> isn''t working?>I suppose we could do that, although I''m not sure the "feature-" prefix is >appropriate, since the code doesn''t have the ability to fall back to v1.I''d rather just let existing users hang out to dry. First off there aren''t really any existing users. Anyone who is or might be a user of the new code is probably following these threads closely. Second the xen tpm driver hasn''t even been accepted into linux yet so there really is not any "official" version 1. I can update the documentation to state the requirements on the new tpm driver version in the current linux tree so that nobody tries to use the old version in the xen 2.6.18 tree.
Matthew Fioravante
2012-Nov-27 14:38 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
Daniel I just tried your patch and it didn''t apply cleanly. The tpm drivers have changed slightly from the original versions you are probably working with. The vtpm domains have also changed. Please pull the latest xen unstable and rebase your patches ontop of the tpm drivers there. You can apply my VTPM v4 patches in the mailing list ontop of xen-unstable to test. It looks like everything except the stubdoms and documentation is currently in xen-unstable. On 11/20/2012 11:11 AM, Daniel De Graaf wrote:> Since the vTPM implementations are being incorproated into Xen and > possibly upstream Linux, I would like to see if this protocol change > could be added before we have significant legacy implementations. If > not, I still think it would be useful as either a v2 or negotiated > protocol change. > > The current vTPM protocol is a copy of the network protocol. This was > likely done for ease of implementation, since support for the network > backend/frontend existed in Linux and minios. However, this > implementation is overly complex when dealing with vTPM packets: for > example, a vTPM never needs to deal with having more than one packet in > flight at any given time. > > I will send the corresponding patch for the Linux kernel module once I > have adapted it for the file names used in the upstream version. > > ------------------------------------>8---------------------------------- > > 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. > > 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 | 132 ++++++++++++++------------------- > extras/mini-os/tpmfront.c | 150 +++++++++++++++++++------------------- > xen/include/public/io/tpmif.h | 45 +++--------- > 5 files changed, 148 insertions(+), 187 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..29aced9 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; > @@ -386,8 +383,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 +391,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 +423,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 +473,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 +516,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 +573,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,10 +605,28 @@ 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; > } > > +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, XenbusStateReconfigured); > + > + 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); > @@ -874,6 +879,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 +890,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 +905,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 +951,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 +982,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..bcee93d 100644 > --- a/extras/mini-os/tpmfront.c > +++ b/extras/mini-os/tpmfront.c > @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) > > } > > +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* path) > +{ > + int state; > + > + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); > + while(1) { > + state = xenbus_read_integer(path); > + if ( state < 0) > + state = XenbusStateUnknown; > + switch(state) { > + case XenbusStateUnknown: > + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); > + return -1; > + case XenbusStateClosed: > + TPMFRONT_LOG("Backend Closed\n"); > + return 0; > + case XenbusStateReconfigured: > + TPMFRONT_LOG("Backend Reconfigured\n"); > + return 0; > + default: > + xenbus_wait_for_watch(events); > + } > + } > + > +} > + > static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { > char* err; > int ret = 0; > @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState > case XenbusStateClosed: > ret = wait_for_backend_closed(&events, path); > break; > - default: > + case XenbusStateReconfigured: > + ret = wait_for_backend_reconfig(&events, path); > break; > + default: > + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); > } > > if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { > @@ -190,13 +219,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 +257,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 +269,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 +317,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,12 +329,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > { > char* err; > char path[512]; > - int i; > - tpmif_tx_request_t* tx; > if(dev == NULL) { > return; > } > - TPMFRONT_LOG("Shutting down tpmfront\n"); > + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); > /* disconnect */ > if(dev->state == XenbusStateConnected) { > dev->state = XenbusStateClosing; > @@ -349,27 +362,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 +385,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > > int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) > { > - int i; > - tpmif_tx_request_t* tx = NULL; > + unsigned int offset; > + vtpm_shared_page_t* shr = NULL; > +#ifdef TPMFRONT_PRINT_DEBUG > +int i; > +#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 +409,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 +433,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 +500,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 >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Patch 1/4 is the (updated) version of the patch starting this thread. The series is based off the v4 vTPM series posted to xen-devel. The other 3 patches add support for using the locality field and extending a static root of trust to a user-specified kernel loaded with pv-grub. Since pv-grub is already GPL, there should be no licensing issues created by adding the vTPM code and the Linux SHA1 implementation. Contents: [PATCH 1/4] stubdom: Change vTPM shared page ABI [PATCH 2/4] stubdom/vtpm: Add reconfiguration support [PATCH 3/4] stubdom/grub: send kernel measurements to vTPM [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
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. 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 | 159 +++++++++++++++++++------------------ extras/mini-os/tpmfront.c | 162 ++++++++++++++++++++++---------------- xen/include/public/io/tpmif.h | 45 +++-------- 5 files changed, 191 insertions(+), 183 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..2d31061 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; @@ -266,6 +263,7 @@ int insert_tpmif(tpmif_t* tpmif) unsigned int i, j; tpmif_t* tmp; char* err; + char path[512]; local_irq_save(flags); @@ -303,6 +301,16 @@ int insert_tpmif(tpmif_t* tpmif) local_irq_restore(flags); + snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); + if ((err = xenbus_write(XBT_NIL, path, "1"))) + { + /* if we got an error here we should carefully remove the interface and then return */ + TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); + free(err); + remove_tpmif(tpmif); + goto error_post_irq; + } + /*Listen for state changes on the new interface */ if((err = xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path, tpmif->fe_state_path, >pmdev.events))) { @@ -312,7 +320,6 @@ int insert_tpmif(tpmif_t* tpmif) remove_tpmif(tpmif); goto error_post_irq; } - return 0; error: local_irq_restore(flags); @@ -386,8 +393,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 +401,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 +433,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 +483,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 +526,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); @@ -584,12 +582,26 @@ int connect_fe(tpmif_t* tpmif) } free(value); + /* Check that protocol v2 is being used */ + snprintf(path, 512, "%s/feature-protocol-v2", tpmif->fe_path); + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMBACK_ERR("Unable to read %s during tpmback initialization! error = %s\n", path, err); + free(err); + return -1; + } + if(strcmp(value, "1")) { + TPMBACK_ERR("%s has an invalid value (%s)\n", path, value); + free(value); + return -1; + } + 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,10 +630,28 @@ 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; } +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, XenbusStateReconfigured); + + 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); @@ -874,6 +904,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 +915,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 +930,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 +976,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 +1007,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..c1cbab3 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) } +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* path) +{ + int state; + + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); + while(1) { + state = xenbus_read_integer(path); + if ( state < 0) + state = XenbusStateUnknown; + switch(state) { + case XenbusStateUnknown: + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); + return -1; + case XenbusStateClosed: + TPMFRONT_LOG("Backend Closed\n"); + return 0; + case XenbusStateReconfigured: + TPMFRONT_LOG("Backend Reconfigured\n"); + return 0; + default: + xenbus_wait_for_watch(events); + } + } + +} + static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { char* err; int ret = 0; @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState case XenbusStateClosed: ret = wait_for_backend_closed(&events, path); break; - default: + case XenbusStateReconfigured: + ret = wait_for_backend_reconfig(&events, path); break; + default: + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +219,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 +257,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 +269,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"); @@ -279,6 +307,15 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) goto error; } + /* Publish protocol v2 feature */ + snprintf(path, 512, "%s/feature-protocol-v2", dev->nodename); + if ((err = xenbus_write(XBT_NIL, path, "1"))) + { + TPMFRONT_ERR("Unable to write feature-protocol-v2 node: %s\n", err); + free(err); + goto error; + } + /* Create and publish grant reference and event channel */ if (tpmfront_connect(dev)) { goto error; @@ -289,18 +326,18 @@ 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) { + snprintf(path, 512, "%s/feature-protocol-v2", dev->bepath); + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = %s\n", path, err); + free(err); 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; - } + if(strcmp(value, "1")) { + TPMFRONT_ERR("%s has an invalid value (%s)\n", path, value); + free(value); + goto error; } + free(value); TPMFRONT_LOG("Initialization Completed successfully\n"); @@ -314,12 +351,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } - TPMFRONT_LOG("Shutting down tpmfront\n"); + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); /* disconnect */ if(dev->state == XenbusStateConnected) { dev->state = XenbusStateClosing; @@ -349,27 +384,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 +407,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 +431,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 +455,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 +522,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
Daniel De Graaf
2012-Nov-27 15:14 UTC
[PATCH 2/4] stubdom/vtpm: Add reconfiguration support
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/include/tpmfront.h | 2 +- extras/mini-os/lib/sys.c | 2 +- extras/mini-os/tpmback.c | 5 +++++ extras/mini-os/tpmfront.c | 15 +++++++++------ stubdom/vtpm/vtpm.c | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h index a0c7c4d..913faa4 100644 --- a/extras/mini-os/include/tpmfront.h +++ b/extras/mini-os/include/tpmfront.h @@ -61,7 +61,7 @@ struct tpmfront_dev { /*Initialize frontend */ struct tpmfront_dev* init_tpmfront(const char* nodename); /*Shutdown frontend */ -void shutdown_tpmfront(struct tpmfront_dev* dev); +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig); /* Send a tpm command to the backend and wait for the response * diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c index 3cc3340..03da4f0 100644 --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -459,7 +459,7 @@ int close(int fd) #endif #ifdef CONFIG_TPMFRONT case FTYPE_TPMFRONT: - shutdown_tpmfront(files[fd].tpmfront.dev); + shutdown_tpmfront(files[fd].tpmfront.dev, 0); files[fd].type = FTYPE_NONE; return 0; #endif diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 2d31061..ea42235 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -664,6 +664,7 @@ static int frontend_changed(tpmif_t* tpmif) switch (state) { case XenbusStateInitialising: case XenbusStateInitialised: + case XenbusStateReconfigured: break; case XenbusStateConnected: @@ -678,6 +679,10 @@ static int frontend_changed(tpmif_t* tpmif) tpmif_change_state(tpmif, XenbusStateClosing); break; + case XenbusStateReconfiguring: + disconnect_fe(tpmif); + break; + case XenbusStateUnknown: /* keep it here */ case XenbusStateClosed: free_tpmif(tpmif); diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index c1cbab3..b725ba0 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -344,10 +344,10 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) return dev; error: - shutdown_tpmfront(dev); + shutdown_tpmfront(dev, 0); return NULL; } -void shutdown_tpmfront(struct tpmfront_dev* dev) +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig) { char* err; char path[512]; @@ -357,8 +357,7 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); /* disconnect */ if(dev->state == XenbusStateConnected) { - dev->state = XenbusStateClosing; - //FIXME: Transaction for this? + dev->state = for_reconfig ? XenbusStateReconfiguring : XenbusStateClosing; /* Tell backend we are closing */ if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { free(err); @@ -374,15 +373,19 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) free(err); } + if (for_reconfig) + wait_for_backend_state_changed(dev, XenbusStateReconfigured); + /* Tell backend we are closed */ - dev->state = XenbusStateClosed; + dev->state = for_reconfig ? XenbusStateInitialising : XenbusStateClosed; 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); } /* Wait for the backend to close and unmap shared pages, ignore any errors */ - wait_for_backend_state_changed(dev, XenbusStateClosed); + if (!for_reconfig) + wait_for_backend_state_changed(dev, XenbusStateClosed); /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index 71aef78..c33e078 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -394,7 +394,7 @@ abort_postvtpmblk: abort_postrng: /* Close devices */ - shutdown_tpmfront(tpmfront_dev); + shutdown_tpmfront(tpmfront_dev, 0); abort_posttpmfront: shutdown_tpmback(); -- 1.7.11.7
Daniel De Graaf
2012-Nov-27 15:14 UTC
[PATCH 3/4] 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/grub/Makefile | 2 +- stubdom/grub/kexec.c | 62 ++++++++++++ stubdom/grub/minios.cfg | 1 + stubdom/grub/sha1.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 stubdom/grub/sha1.c diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile index d6e3a1e..f1b5c3e 100644 --- a/stubdom/grub/Makefile +++ b/stubdom/grub/Makefile @@ -59,7 +59,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) $(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__ -PV_GRUB_SOURCES = kexec.c mini-os.c +PV_GRUB_SOURCES = sha1.c kexec.c mini-os.c SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES) diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c index b21c91a..ba48cb7 100644 --- a/stubdom/grub/kexec.c +++ b/stubdom/grub/kexec.c @@ -117,6 +117,66 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) return 0; } +static inline uint16_t be16(uint16_t v) +{ + return (v >> 8) | (v << 8); +} + +static inline uint32_t be32(uint32_t v) +{ + return (be16(v) << 16) | be16(v >> 16); +} + +void sha_compute(uint32_t *buf, void *src, uint32_t len); + +#include <tpmfront.h> + +#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; + uint32_t hash[5]; +} __attribute__((packed)); + +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 = be16(TPM_TAG_RQU_COMMAND); + cmd.size = be32(sizeof(cmd)); + cmd.ord = be32(TPM_ORD_Extend); + cmd.pcr = be32(4); // PCR #4 for kernel + sha_compute(cmd.hash, dom->kernel_blob, dom->kernel_size); + + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = be32(5); // PCR #5 for cmdline + sha_compute(cmd.hash, cmdline, strlen(cmdline)); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = be32(5); // PCR #5 for initrd + sha_compute(cmd.hash, dom->ramdisk_blob, dom->ramdisk_size); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + shutdown_tpmfront(tpm, 1); +} + void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) { struct xc_dom_image *dom; @@ -151,6 +211,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 diff --git a/stubdom/grub/sha1.c b/stubdom/grub/sha1.c new file mode 100644 index 0000000..2ad2e07 --- /dev/null +++ b/stubdom/grub/sha1.c @@ -0,0 +1,260 @@ +/* + * SHA1 routine optimized to do word accesses rather than byte accesses, + * and to avoid unnecessary copies into the context array. + * + * This was based on the git SHA1 implementation. + */ + +#include <stdint.h> +#include <string.h> + +static inline uint16_t be16(uint16_t v) +{ + return (v >> 8) | (v << 8); +} + +static inline uint32_t be32(uint32_t v) +{ + return (be16(v) << 16) | be16(v >> 16); +} + +static inline uint32_t get_unaligned_be32(uint32_t *v) +{ + return be32(*v); +} + +/* + * rol32 - rotate a 32-bit value left + * + * @word: value to rotate + * @shift: bits to roll + */ +static inline uint32_t rol32(uint32_t word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +/* + * ror32 - rotate a 32-bit value right + * + * @word: value to rotate + * @shift: bits to roll + */ +static inline uint32_t ror32(uint32_t word, unsigned int shift) +{ + return (word >> shift) | (word << (32 - shift)); +} + + +/* + * If you have 32 registers or more, the compiler can (and should) + * try to change the array[] accesses into registers. However, on + * machines with less than ~25 registers, that won''t really work, + * and at least gcc will make an unholy mess of it. + * + * So to avoid that mess which just slows things down, we force + * the stores to memory to actually happen (we might be better off + * with a ''W(t)=(val);asm("":"+m" (W(t))'' there instead, as + * suggested by Artur Skawina - that will also make gcc unable to + * try to do the silly "optimize away loads" part because it won''t + * see what the value will be). + * + * Ben Herrenschmidt reports that on PPC, the C version comes close + * to the optimized asm with this (ie on PPC you don''t want that + * ''volatile'', since there are lots of registers). + * + * On ARM we get the best code generation by forcing a full memory barrier + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and + * the stack frame size simply explode and performance goes down the drain. + */ + +#if 1 + #define setW(x, val) (*(volatile uint32_t *)&W(x) = (val)) +#else + #define setW(x, val) (W(x) = (val)) +#endif + +/* This "rolls" over the 512-bit array */ +#define W(x) (array[(x)&15]) + +/* + * Where do we get the source from? The first 16 iterations get it from + * the input data, the next mix it from the 512-bit array. + */ +#define SHA_SRC(t) get_unaligned_be32((uint32_t *)data + t) +#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) + +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ + uint32_t TEMP = input(t); setW(t, TEMP); \ + E += TEMP + rol32(A,5) + (fn) + (constant); \ + B = ror32(B, 2); } while (0) + +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) + +/** + * sha_transform - single block SHA1 transform + * + * @digest: 160 bit digest to update + * @data: 512 bits of data to hash + * @array: 16 words of workspace (see note) + * + * This function generates a SHA1 digest for a single 512-bit block. + * Be warned, it does not handle padding and message digest, do not + * confuse it with the full FIPS 180-1 digest algorithm for variable + * length messages. + * + * Note: If the hash is security sensitive, the caller should be sure + * to clear the workspace. This is left to the caller to avoid + * unnecessary clears between chained hashing operations. + */ +void sha_transform(uint32_t *digest, const char *data, uint32_t *array) +{ + uint32_t A, B, C, D, E; + + A = digest[0]; + B = digest[1]; + C = digest[2]; + D = digest[3]; + E = digest[4]; + + /* Round 1 - iterations 0-16 take their input from ''data'' */ + T_0_15( 0, A, B, C, D, E); + T_0_15( 1, E, A, B, C, D); + T_0_15( 2, D, E, A, B, C); + T_0_15( 3, C, D, E, A, B); + T_0_15( 4, B, C, D, E, A); + T_0_15( 5, A, B, C, D, E); + T_0_15( 6, E, A, B, C, D); + T_0_15( 7, D, E, A, B, C); + T_0_15( 8, C, D, E, A, B); + T_0_15( 9, B, C, D, E, A); + T_0_15(10, A, B, C, D, E); + T_0_15(11, E, A, B, C, D); + T_0_15(12, D, E, A, B, C); + T_0_15(13, C, D, E, A, B); + T_0_15(14, B, C, D, E, A); + T_0_15(15, A, B, C, D, E); + + /* Round 1 - tail. Input from 512-bit mixing array */ + T_16_19(16, E, A, B, C, D); + T_16_19(17, D, E, A, B, C); + T_16_19(18, C, D, E, A, B); + T_16_19(19, B, C, D, E, A); + + /* Round 2 */ + T_20_39(20, A, B, C, D, E); + T_20_39(21, E, A, B, C, D); + T_20_39(22, D, E, A, B, C); + T_20_39(23, C, D, E, A, B); + T_20_39(24, B, C, D, E, A); + T_20_39(25, A, B, C, D, E); + T_20_39(26, E, A, B, C, D); + T_20_39(27, D, E, A, B, C); + T_20_39(28, C, D, E, A, B); + T_20_39(29, B, C, D, E, A); + T_20_39(30, A, B, C, D, E); + T_20_39(31, E, A, B, C, D); + T_20_39(32, D, E, A, B, C); + T_20_39(33, C, D, E, A, B); + T_20_39(34, B, C, D, E, A); + T_20_39(35, A, B, C, D, E); + T_20_39(36, E, A, B, C, D); + T_20_39(37, D, E, A, B, C); + T_20_39(38, C, D, E, A, B); + T_20_39(39, B, C, D, E, A); + + /* Round 3 */ + T_40_59(40, A, B, C, D, E); + T_40_59(41, E, A, B, C, D); + T_40_59(42, D, E, A, B, C); + T_40_59(43, C, D, E, A, B); + T_40_59(44, B, C, D, E, A); + T_40_59(45, A, B, C, D, E); + T_40_59(46, E, A, B, C, D); + T_40_59(47, D, E, A, B, C); + T_40_59(48, C, D, E, A, B); + T_40_59(49, B, C, D, E, A); + T_40_59(50, A, B, C, D, E); + T_40_59(51, E, A, B, C, D); + T_40_59(52, D, E, A, B, C); + T_40_59(53, C, D, E, A, B); + T_40_59(54, B, C, D, E, A); + T_40_59(55, A, B, C, D, E); + T_40_59(56, E, A, B, C, D); + T_40_59(57, D, E, A, B, C); + T_40_59(58, C, D, E, A, B); + T_40_59(59, B, C, D, E, A); + + /* Round 4 */ + T_60_79(60, A, B, C, D, E); + T_60_79(61, E, A, B, C, D); + T_60_79(62, D, E, A, B, C); + T_60_79(63, C, D, E, A, B); + T_60_79(64, B, C, D, E, A); + T_60_79(65, A, B, C, D, E); + T_60_79(66, E, A, B, C, D); + T_60_79(67, D, E, A, B, C); + T_60_79(68, C, D, E, A, B); + T_60_79(69, B, C, D, E, A); + T_60_79(70, A, B, C, D, E); + T_60_79(71, E, A, B, C, D); + T_60_79(72, D, E, A, B, C); + T_60_79(73, C, D, E, A, B); + T_60_79(74, B, C, D, E, A); + T_60_79(75, A, B, C, D, E); + T_60_79(76, E, A, B, C, D); + T_60_79(77, D, E, A, B, C); + T_60_79(78, C, D, E, A, B); + T_60_79(79, B, C, D, E, A); + + digest[0] += A; + digest[1] += B; + digest[2] += C; + digest[3] += D; + digest[4] += E; +} + +/** + * sha_init - initialize the vectors for a SHA1 digest + * @buf: vector to initialize + */ +void sha_init(uint32_t *buf) +{ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + buf[4] = 0xc3d2e1f0; +} + +void sha_compute(uint32_t *buf, void *src, uint32_t len) +{ + uint32_t pos = 0; + uint8_t final[64]; + uint32_t work[16]; + sha_init(buf); + while (len >= pos + 64) { + sha_transform(buf, src + pos, work); + pos += 64; + } + memcpy(final, src + pos, len - pos); + // done with src; pos is now relative to final + pos = len - pos; + final[pos++] = 0x80; + memset(final + pos, 0, sizeof(final) - pos); + if (pos > 56) { + sha_transform(buf, (void*)final, work); + memset(final, 0, sizeof(final)); + } + *(uint32_t*)(final + 60) = be32(len << 3); + sha_transform(buf, (void*)final, work); + buf[0] = be32(buf[0]); + buf[1] = be32(buf[1]); + buf[2] = be32(buf[2]); + buf[3] = be32(buf[3]); + buf[4] = be32(buf[4]); +} -- 1.7.11.7
Daniel De Graaf
2012-Nov-27 15:14 UTC
[PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
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. This also enables a single vTPM to provide multiple tpmback interfaces so that several closely related domains can share a vTPM (for example, a qemu device stubdom and its target domain). Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- stubdom/vtpm/vtpm.c | 16 +++--------- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch index b84eff1..31ace1a 100644 --- a/stubdom/tpmemu-0.7.4.patch +++ b/stubdom/tpmemu-0.7.4.patch @@ -1,9 +1,60 @@ -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 -@@ -249,7 +249,7 @@ +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c +index aabe6c3..440a01b 100644 +--- a/tpm/tpm_emulator_extern.c ++++ b/tpm/tpm_emulator_extern.c +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr #else /* TPM_NO_EXTERN */ - + int (*tpm_extern_init)(void) = NULL; -int (*tpm_extern_release)(void) = NULL; +void (*tpm_extern_release)(void) = NULL; diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index c33e078..dcfc3b9 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) { @@ -183,7 +173,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); } @@ -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
Samuel Thibault
2012-Nov-27 16:41 UTC
Re: [PATCH 3/4] stubdom/grub: send kernel measurements to vTPM
Daniel De Graaf, le Tue 27 Nov 2012 10:14:45 -0500, a écrit :> +static inline uint16_t be16(uint16_t v) > +{ > + return (v >> 8) | (v << 8); > +} > + > +static inline uint32_t be32(uint32_t v) > +{ > + return (be16(v) << 16) | be16(v >> 16); > +}Better use the existing bswap_16 and bswap_32.> +void sha_compute(uint32_t *buf, void *src, uint32_t len); > +++ b/stubdom/grub/sha1.cI guess it could find its way in mini-os/lib? BTW, what is the licence and copyright of this implementation? We need to be sure about that.> @@ -0,0 +1,260 @@ > +/* > + * SHA1 routine optimized to do word accesses rather than byte accesses, > + * and to avoid unnecessary copies into the context array. > + * > + * This was based on the git SHA1 implementation. > + */ > + > +#include <stdint.h> > +#include <string.h> > + > +static inline uint16_t be16(uint16_t v) > +{ > + return (v >> 8) | (v << 8); > +} > + > +static inline uint32_t be32(uint32_t v) > +{ > + return (be16(v) << 16) | be16(v >> 16); > +}Ditto bswap_16/32 Samuel
Samuel Thibault
2012-Nov-27 16:42 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
I let Matthew comment on patches 1 and 4. Samuel
Samuel Thibault
2012-Nov-27 16:44 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
Daniel De Graaf, le Tue 27 Nov 2012 10:14:44 -0500, a écrit :> -void shutdown_tpmfront(struct tpmfront_dev* dev) > +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig)Do we really need to explicit "for_reconfig"? We didn''t need it for fbfront/blkfront/etc. (we just needed to fix some bugs), is tpm anything particular here? Samuel
Daniel De Graaf, le Tue 27 Nov 2012 10:14:42 -0500, a écrit :> Since pv-grub is already GPL, there should be no licensing issues > created by adding the vTPM code and the Linux SHA1 implementation.Ah, I should have read this before :) Yes, the GPL licence shouldn''t pose problem (and thus the sha1 implementation should stay in grub/, and not go to mini-os/lib as I suggested. We still need to know the copyright for the file. Samuel
Matthew Fioravante
2012-Nov-27 18:08 UTC
Re: [PATCH 3/4] stubdom/grub: send kernel measurements to vTPM
On 11/27/2012 10:14 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.Do you have any documentation updates for how to use it? They could be added to the vtpm documentation if thats the most appropriate location. How exactly does this work? Is it intended for HVM domains whos stubdom is connected to a vtpm? I''ve never tried to use vtpm with HVMs yet, so I''d be very surprised if it just works. Does it work for PVM domains? I''m not terribly familiar with how grub in stubdom works.> > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/grub/Makefile | 2 +- > stubdom/grub/kexec.c | 62 ++++++++++++ > stubdom/grub/minios.cfg | 1 + > stubdom/grub/sha1.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 324 insertions(+), 1 deletion(-) > create mode 100644 stubdom/grub/sha1.c > > diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile > index d6e3a1e..f1b5c3e 100644 > --- a/stubdom/grub/Makefile > +++ b/stubdom/grub/Makefile > @@ -59,7 +59,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) > > $(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__ > > -PV_GRUB_SOURCES = kexec.c mini-os.c > +PV_GRUB_SOURCES = sha1.c kexec.c mini-os.c > > SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES) > > diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c > index b21c91a..ba48cb7 100644 > --- a/stubdom/grub/kexec.c > +++ b/stubdom/grub/kexec.c > @@ -117,6 +117,66 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) > return 0; > } > > +static inline uint16_t be16(uint16_t v) > +{ > + return (v >> 8) | (v << 8); > +} > + > +static inline uint32_t be32(uint32_t v) > +{ > + return (be16(v) << 16) | be16(v >> 16); > +} > + > +void sha_compute(uint32_t *buf, void *src, uint32_t len); > + > +#include <tpmfront.h> > + > +#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; > + uint32_t hash[5]; > +} __attribute__((packed)); > + > +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 = be16(TPM_TAG_RQU_COMMAND); > + cmd.size = be32(sizeof(cmd)); > + cmd.ord = be32(TPM_ORD_Extend); > + cmd.pcr = be32(4); // PCR #4 for kernel > + sha_compute(cmd.hash, dom->kernel_blob, dom->kernel_size); > + > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + cmd.pcr = be32(5); // PCR #5 for cmdline > + sha_compute(cmd.hash, cmdline, strlen(cmdline)); > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + cmd.pcr = be32(5); // PCR #5 for initrd > + sha_compute(cmd.hash, dom->ramdisk_blob, dom->ramdisk_size); > + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); > + > + shutdown_tpmfront(tpm, 1); > +}Does this actually work? vtpm-stubdom will shut itself down when the frontend tpm disconnects. Is it really ok to connect and disconnect these devices at will?> + > void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) > { > struct xc_dom_image *dom; > @@ -151,6 +211,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 > diff --git a/stubdom/grub/sha1.c b/stubdom/grub/sha1.c > new file mode 100644 > index 0000000..2ad2e07 > --- /dev/null > +++ b/stubdom/grub/sha1.c > @@ -0,0 +1,260 @@ > +/* > + * SHA1 routine optimized to do word accesses rather than byte accesses, > + * and to avoid unnecessary copies into the context array. > + * > + * This was based on the git SHA1 implementation. > + */ > + > +#include <stdint.h> > +#include <string.h> > + > +static inline uint16_t be16(uint16_t v) > +{ > + return (v >> 8) | (v << 8); > +} > + > +static inline uint32_t be32(uint32_t v) > +{ > + return (be16(v) << 16) | be16(v >> 16); > +} > + > +static inline uint32_t get_unaligned_be32(uint32_t *v) > +{ > + return be32(*v); > +}These exist in mini-os byteorder.h now.> + > +/* > + * rol32 - rotate a 32-bit value left > + * > + * @word: value to rotate > + * @shift: bits to roll > + */ > +static inline uint32_t rol32(uint32_t word, unsigned int shift) > +{ > + return (word << shift) | (word >> (32 - shift)); > +} > + > +/* > + * ror32 - rotate a 32-bit value right > + * > + * @word: value to rotate > + * @shift: bits to roll > + */ > +static inline uint32_t ror32(uint32_t word, unsigned int shift) > +{ > + return (word >> shift) | (word << (32 - shift)); > +} > + > + > +/* > + * If you have 32 registers or more, the compiler can (and should) > + * try to change the array[] accesses into registers. However, on > + * machines with less than ~25 registers, that won''t really work, > + * and at least gcc will make an unholy mess of it. > + * > + * So to avoid that mess which just slows things down, we force > + * the stores to memory to actually happen (we might be better off > + * with a ''W(t)=(val);asm("":"+m" (W(t))'' there instead, as > + * suggested by Artur Skawina - that will also make gcc unable to > + * try to do the silly "optimize away loads" part because it won''t > + * see what the value will be). > + * > + * Ben Herrenschmidt reports that on PPC, the C version comes close > + * to the optimized asm with this (ie on PPC you don''t want that > + * ''volatile'', since there are lots of registers). > + * > + * On ARM we get the best code generation by forcing a full memory barrier > + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and > + * the stack frame size simply explode and performance goes down the drain. > + */ > + > +#if 1 > + #define setW(x, val) (*(volatile uint32_t *)&W(x) = (val)) > +#else > + #define setW(x, val) (W(x) = (val)) > +#endif > + > +/* This "rolls" over the 512-bit array */ > +#define W(x) (array[(x)&15]) > + > +/* > + * Where do we get the source from? The first 16 iterations get it from > + * the input data, the next mix it from the 512-bit array. > + */ > +#define SHA_SRC(t) get_unaligned_be32((uint32_t *)data + t) > +#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) > + > +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ > + uint32_t TEMP = input(t); setW(t, TEMP); \ > + E += TEMP + rol32(A,5) + (fn) + (constant); \ > + B = ror32(B, 2); } while (0) > + > +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) > +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) > +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) > +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) > +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) > + > +/** > + * sha_transform - single block SHA1 transform > + * > + * @digest: 160 bit digest to update > + * @data: 512 bits of data to hash > + * @array: 16 words of workspace (see note) > + * > + * This function generates a SHA1 digest for a single 512-bit block. > + * Be warned, it does not handle padding and message digest, do not > + * confuse it with the full FIPS 180-1 digest algorithm for variable > + * length messages. > + * > + * Note: If the hash is security sensitive, the caller should be sure > + * to clear the workspace. This is left to the caller to avoid > + * unnecessary clears between chained hashing operations. > + */ > +void sha_transform(uint32_t *digest, const char *data, uint32_t *array) > +{ > + uint32_t A, B, C, D, E; > + > + A = digest[0]; > + B = digest[1]; > + C = digest[2]; > + D = digest[3]; > + E = digest[4]; > + > + /* Round 1 - iterations 0-16 take their input from ''data'' */ > + T_0_15( 0, A, B, C, D, E); > + T_0_15( 1, E, A, B, C, D); > + T_0_15( 2, D, E, A, B, C); > + T_0_15( 3, C, D, E, A, B); > + T_0_15( 4, B, C, D, E, A); > + T_0_15( 5, A, B, C, D, E); > + T_0_15( 6, E, A, B, C, D); > + T_0_15( 7, D, E, A, B, C); > + T_0_15( 8, C, D, E, A, B); > + T_0_15( 9, B, C, D, E, A); > + T_0_15(10, A, B, C, D, E); > + T_0_15(11, E, A, B, C, D); > + T_0_15(12, D, E, A, B, C); > + T_0_15(13, C, D, E, A, B); > + T_0_15(14, B, C, D, E, A); > + T_0_15(15, A, B, C, D, E); > + > + /* Round 1 - tail. Input from 512-bit mixing array */ > + T_16_19(16, E, A, B, C, D); > + T_16_19(17, D, E, A, B, C); > + T_16_19(18, C, D, E, A, B); > + T_16_19(19, B, C, D, E, A); > + > + /* Round 2 */ > + T_20_39(20, A, B, C, D, E); > + T_20_39(21, E, A, B, C, D); > + T_20_39(22, D, E, A, B, C); > + T_20_39(23, C, D, E, A, B); > + T_20_39(24, B, C, D, E, A); > + T_20_39(25, A, B, C, D, E); > + T_20_39(26, E, A, B, C, D); > + T_20_39(27, D, E, A, B, C); > + T_20_39(28, C, D, E, A, B); > + T_20_39(29, B, C, D, E, A); > + T_20_39(30, A, B, C, D, E); > + T_20_39(31, E, A, B, C, D); > + T_20_39(32, D, E, A, B, C); > + T_20_39(33, C, D, E, A, B); > + T_20_39(34, B, C, D, E, A); > + T_20_39(35, A, B, C, D, E); > + T_20_39(36, E, A, B, C, D); > + T_20_39(37, D, E, A, B, C); > + T_20_39(38, C, D, E, A, B); > + T_20_39(39, B, C, D, E, A); > + > + /* Round 3 */ > + T_40_59(40, A, B, C, D, E); > + T_40_59(41, E, A, B, C, D); > + T_40_59(42, D, E, A, B, C); > + T_40_59(43, C, D, E, A, B); > + T_40_59(44, B, C, D, E, A); > + T_40_59(45, A, B, C, D, E); > + T_40_59(46, E, A, B, C, D); > + T_40_59(47, D, E, A, B, C); > + T_40_59(48, C, D, E, A, B); > + T_40_59(49, B, C, D, E, A); > + T_40_59(50, A, B, C, D, E); > + T_40_59(51, E, A, B, C, D); > + T_40_59(52, D, E, A, B, C); > + T_40_59(53, C, D, E, A, B); > + T_40_59(54, B, C, D, E, A); > + T_40_59(55, A, B, C, D, E); > + T_40_59(56, E, A, B, C, D); > + T_40_59(57, D, E, A, B, C); > + T_40_59(58, C, D, E, A, B); > + T_40_59(59, B, C, D, E, A); > + > + /* Round 4 */ > + T_60_79(60, A, B, C, D, E); > + T_60_79(61, E, A, B, C, D); > + T_60_79(62, D, E, A, B, C); > + T_60_79(63, C, D, E, A, B); > + T_60_79(64, B, C, D, E, A); > + T_60_79(65, A, B, C, D, E); > + T_60_79(66, E, A, B, C, D); > + T_60_79(67, D, E, A, B, C); > + T_60_79(68, C, D, E, A, B); > + T_60_79(69, B, C, D, E, A); > + T_60_79(70, A, B, C, D, E); > + T_60_79(71, E, A, B, C, D); > + T_60_79(72, D, E, A, B, C); > + T_60_79(73, C, D, E, A, B); > + T_60_79(74, B, C, D, E, A); > + T_60_79(75, A, B, C, D, E); > + T_60_79(76, E, A, B, C, D); > + T_60_79(77, D, E, A, B, C); > + T_60_79(78, C, D, E, A, B); > + T_60_79(79, B, C, D, E, A); > + > + digest[0] += A; > + digest[1] += B; > + digest[2] += C; > + digest[3] += D; > + digest[4] += E; > +} > + > +/** > + * sha_init - initialize the vectors for a SHA1 digest > + * @buf: vector to initialize > + */ > +void sha_init(uint32_t *buf) > +{ > + buf[0] = 0x67452301; > + buf[1] = 0xefcdab89; > + buf[2] = 0x98badcfe; > + buf[3] = 0x10325476; > + buf[4] = 0xc3d2e1f0; > +} > + > +void sha_compute(uint32_t *buf, void *src, uint32_t len) > +{ > + uint32_t pos = 0; > + uint8_t final[64]; > + uint32_t work[16]; > + sha_init(buf); > + while (len >= pos + 64) { > + sha_transform(buf, src + pos, work); > + pos += 64; > + } > + memcpy(final, src + pos, len - pos); > + // done with src; pos is now relative to final > + pos = len - pos; > + final[pos++] = 0x80; > + memset(final + pos, 0, sizeof(final) - pos); > + if (pos > 56) { > + sha_transform(buf, (void*)final, work); > + memset(final, 0, sizeof(final)); > + } > + *(uint32_t*)(final + 60) = be32(len << 3); > + sha_transform(buf, (void*)final, work); > + buf[0] = be32(buf[0]); > + buf[1] = be32(buf[1]); > + buf[2] = be32(buf[2]); > + buf[3] = be32(buf[3]); > + buf[4] = be32(buf[4]); > +}There also exists a sha1 routine in polarssl. You can just link in the polarssl sha1 object file without the entire library. This is what vtpm-stubdom and vtpmmgrdom do to get the crypto pieces they need. Checkout their makefiles for details. Is there any reason using polarssl would be sub-optimal?> -- > 1.7.11.7 >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Nov-27 18:19 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 10:14 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. > This also enables a single vTPM to provide multiple tpmback interfaces > so that several closely related domains can share a vTPM (for example, a > qemu device stubdom and its target domain). > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- > stubdom/vtpm/vtpm.c | 16 +++--------- > 2 files changed, 59 insertions(+), 18 deletions(-) > > diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch > index b84eff1..31ace1a 100644 > --- a/stubdom/tpmemu-0.7.4.patch > +++ b/stubdom/tpmemu-0.7.4.patch > @@ -1,9 +1,60 @@ > -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c > ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 > -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 > -@@ -249,7 +249,7 @@ > +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c > +index aabe6c3..440a01b 100644 > +--- a/tpm/tpm_emulator_extern.c > ++++ b/tpm/tpm_emulator_extern.c > +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr > #else /* TPM_NO_EXTERN */ > - > + > int (*tpm_extern_init)(void) = NULL; > -int (*tpm_extern_release)(void) = NULL; > +void (*tpm_extern_release)(void) = NULL; > diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c > index c33e078..dcfc3b9 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) { > @@ -183,7 +173,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); > } > @@ -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(); > > }Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end?>_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Samuel Thibault
2012-Nov-27 18:36 UTC
Re: [PATCH 3/4] stubdom/grub: send kernel measurements to vTPM
Matthew Fioravante, le Tue 27 Nov 2012 13:08:19 -0500, a écrit :> How exactly does this work? Is it intended for HVM domains whos stubdom is > connected to a vtpm? I''ve never tried to use vtpm with HVMs yet, so I''d be > very surprised if it just works. Does it work for PVM domains? > > I''m not terribly familiar with how grub in stubdom works.Grub in stubdom is for bootloading PV guests only, not HVM. It''s simply the PV version of grub. Samuel
Daniel De Graaf
2012-Nov-27 18:53 UTC
Re: [PATCH 3/4] stubdom/grub: send kernel measurements to vTPM
On 11/27/2012 01:08 PM, Matthew Fioravante wrote:> On 11/27/2012 10:14 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. > Do you have any documentation updates for how to use it? They could be added to the vtpm documentation if thats the most appropriate location.Not much documentation is really needed - you just launch a domain with the pv-grub kernel and a vTPM, and this patch will write the measurements of the kernel, initrd, and command line to PCRs 4/5, similar to trusted grub on real hardware.> How exactly does this work? Is it intended for HVM domains whos stubdom is connected to a vtpm? I''ve never tried to use vtpm with HVMs yet, so I''d be very surprised if it just works. Does it work for PVM domains? > > I''m not terribly familiar with how grub in stubdom works.This is PV only. The pv-grub stubdom is constructed similar to any other PV domain, but the pv-grub kernel is specified instead of a normal Linux kernel. The pv-grub kernel then loads a grub.conf from the guest''s disk image and loads the Linux kernel and initrd specified by the guest; this is more secure than pygrub which does the loading in dom0, and more flexible than requiring the user to pick from a list of pre-approved non-malicious kernels. If the pv-grub domain is created on command by a measured domain builder/initrd combination, you can produce a static chain of trust extending down to the hardware TPM without involving every UID 0 process in dom0. [...]>> + cmd.pcr = be32(4); // PCR #4 for kernel >> + sha_compute(cmd.hash, dom->kernel_blob, dom->kernel_size); >> + >> + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); >> + >> + cmd.pcr = be32(5); // PCR #5 for cmdline >> + sha_compute(cmd.hash, cmdline, strlen(cmdline)); >> + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); >> + >> + cmd.pcr = be32(5); // PCR #5 for initrd >> + sha_compute(cmd.hash, dom->ramdisk_blob, dom->ramdisk_size); >> + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); >> + >> + shutdown_tpmfront(tpm, 1); >> +} > Does this actually work? vtpm-stubdom will shut itself down when the frontend tpm disconnects. Is it really ok to connect and disconnect these devices at will?Hmm, apparently this part may depend on the change from tpmback_req to tpmback_req_any to avoid the shutdown on disconnect. That might not be required (shutdown for reconfigure shouldn''t start returning NULL for requests) but I also haven''t tested that it works without #4. [...]>> +++ b/stubdom/grub/sha1.c[...]> There also exists a sha1 routine in polarssl. You can just link in the polarssl sha1 object file without the entire library. This is what vtpm-stubdom and vtpmmgrdom do to get the crypto pieces they need. Checkout their makefiles for details. > Is there any reason using polarssl would be sub-optimal?No, I think rewriting this to use the polarssl functions would be useful; I didn''t notice the polarssl function was available when this patch was created. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Nov-27 19:02 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 01:19 PM, Matthew Fioravante wrote:> On 11/27/2012 10:14 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. >> This also enables a single vTPM to provide multiple tpmback interfaces >> so that several closely related domains can share a vTPM (for example, a >> qemu device stubdom and its target domain). >> >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >> --- >> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >> stubdom/vtpm/vtpm.c | 16 +++--------- >> 2 files changed, 59 insertions(+), 18 deletions(-) >> >> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >> index b84eff1..31ace1a 100644 >> --- a/stubdom/tpmemu-0.7.4.patch >> +++ b/stubdom/tpmemu-0.7.4.patch >> @@ -1,9 +1,60 @@ >> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >> -@@ -249,7 +249,7 @@ >> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >> +index aabe6c3..440a01b 100644 >> +--- a/tpm/tpm_emulator_extern.c >> ++++ b/tpm/tpm_emulator_extern.c >> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >> #else /* TPM_NO_EXTERN */ >> - >> + >> int (*tpm_extern_init)(void) = NULL; >> -int (*tpm_extern_release)(void) = NULL; >> +void (*tpm_extern_release)(void) = NULL; >> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >> index c33e078..dcfc3b9 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) { >> @@ -183,7 +173,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); >> } >> @@ -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(); >> } > Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end?When a domain shuts down, "xl destroy" is called on its paired vTPM (by some scripting that may need to be incorporated into libxl). A graceful shutdown is not really needed at this point, although it might be needed in the short term if the save-state operation is not atomic - but a method of recovering from this type of failure is needed for vTPMs anyway. -- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-27 19:48 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 02:02 PM, Daniel De Graaf wrote:> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >> On 11/27/2012 10:14 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. >>> This also enables a single vTPM to provide multiple tpmback interfaces >>> so that several closely related domains can share a vTPM (for example, a >>> qemu device stubdom and its target domain). >>> >>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>> --- >>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>> stubdom/vtpm/vtpm.c | 16 +++--------- >>> 2 files changed, 59 insertions(+), 18 deletions(-) >>> >>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>> index b84eff1..31ace1a 100644 >>> --- a/stubdom/tpmemu-0.7.4.patch >>> +++ b/stubdom/tpmemu-0.7.4.patch >>> @@ -1,9 +1,60 @@ >>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>> -@@ -249,7 +249,7 @@ >>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>> +index aabe6c3..440a01b 100644 >>> +--- a/tpm/tpm_emulator_extern.c >>> ++++ b/tpm/tpm_emulator_extern.c >>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>> #else /* TPM_NO_EXTERN */ >>> - >>> + >>> int (*tpm_extern_init)(void) = NULL; >>> -int (*tpm_extern_release)(void) = NULL; >>> +void (*tpm_extern_release)(void) = NULL; >>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>> index c33e078..dcfc3b9 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) { >>> @@ -183,7 +173,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); >>> } >>> @@ -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(); >>> } >> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? > When a domain shuts down, "xl destroy" is called on its paired vTPM (by some > scripting that may need to be incorporated into libxl). A graceful shutdown > is not really needed at this point, although it might be needed in the short > term if the save-state operation is not atomic - but a method of recovering > from this type of failure is needed for vTPMs anyway.This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Samuel Thibault
2012-Nov-27 20:04 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
Matthew Fioravante, le Tue 27 Nov 2012 14:48:29 -0500, a écrit :> What is really needed is a way to do an xl shutdown on mini-os domains to > let vtpm-stubdom shutdown correctly. From what I understand there is not yet > any support for this in mini-os. How tricky would it be to add that? Samuel > any ideas?You mean add support to mini-os for clean shutdown? That''s quite trivial, IIRC it''s a matter of reacting to a xenstore write. Samuel
Daniel De Graaf
2012-Nov-27 20:11 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 02:48 PM, Matthew Fioravante wrote:> On 11/27/2012 02:02 PM, Daniel De Graaf wrote: >> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >>> On 11/27/2012 10:14 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. >>>> This also enables a single vTPM to provide multiple tpmback interfaces >>>> so that several closely related domains can share a vTPM (for example, a >>>> qemu device stubdom and its target domain). >>>> >>>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>>> --- >>>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>>> stubdom/vtpm/vtpm.c | 16 +++--------- >>>> 2 files changed, 59 insertions(+), 18 deletions(-) >>>> >>>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>>> index b84eff1..31ace1a 100644 >>>> --- a/stubdom/tpmemu-0.7.4.patch >>>> +++ b/stubdom/tpmemu-0.7.4.patch >>>> @@ -1,9 +1,60 @@ >>>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>>> -@@ -249,7 +249,7 @@ >>>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>>> +index aabe6c3..440a01b 100644 >>>> +--- a/tpm/tpm_emulator_extern.c >>>> ++++ b/tpm/tpm_emulator_extern.c >>>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>>> #else /* TPM_NO_EXTERN */ >>>> - >>>> + >>>> int (*tpm_extern_init)(void) = NULL; >>>> -int (*tpm_extern_release)(void) = NULL; >>>> +void (*tpm_extern_release)(void) = NULL; >>>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>>> index c33e078..dcfc3b9 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) { >>>> @@ -183,7 +173,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); >>>> } >>>> @@ -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(); >>>> } >>> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? >> When a domain shuts down, "xl destroy" is called on its paired vTPM (by some >> scripting that may need to be incorporated into libxl). A graceful shutdown >> is not really needed at this point, although it might be needed in the short >> term if the save-state operation is not atomic - but a method of recovering >> from this type of failure is needed for vTPMs anyway. > This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. > > What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? > > If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. >I have approached this problem from the opposite direction, while looking at adding protection from vTPM state rollback. The method that I am currently considering is to have two "slots" in the vTPM disk image - one active and and one inactive. The save process would then consist of writing a new save state to the inactive slot, ensuring it has been committed to disk, and then requesting the TPM Manager atomically update the state encryption key to the new value. When loading, the key obtained from the TPM manager will only be able to decrypt one of the two state images; the successful one is the active image. Since the vTPM''s saved state is not expected to be very large, this doesn''t waste a significant amount of disk space. -- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-27 20:21 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 03:11 PM, Daniel De Graaf wrote:> On 11/27/2012 02:48 PM, Matthew Fioravante wrote: >> On 11/27/2012 02:02 PM, Daniel De Graaf wrote: >>> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >>>> On 11/27/2012 10:14 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. >>>>> This also enables a single vTPM to provide multiple tpmback interfaces >>>>> so that several closely related domains can share a vTPM (for example, a >>>>> qemu device stubdom and its target domain). >>>>> >>>>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>>>> --- >>>>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>>>> stubdom/vtpm/vtpm.c | 16 +++--------- >>>>> 2 files changed, 59 insertions(+), 18 deletions(-) >>>>> >>>>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>>>> index b84eff1..31ace1a 100644 >>>>> --- a/stubdom/tpmemu-0.7.4.patch >>>>> +++ b/stubdom/tpmemu-0.7.4.patch >>>>> @@ -1,9 +1,60 @@ >>>>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>>>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>>>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>>>> -@@ -249,7 +249,7 @@ >>>>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>>>> +index aabe6c3..440a01b 100644 >>>>> +--- a/tpm/tpm_emulator_extern.c >>>>> ++++ b/tpm/tpm_emulator_extern.c >>>>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>>>> #else /* TPM_NO_EXTERN */ >>>>> - >>>>> + >>>>> int (*tpm_extern_init)(void) = NULL; >>>>> -int (*tpm_extern_release)(void) = NULL; >>>>> +void (*tpm_extern_release)(void) = NULL; >>>>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>>>> index c33e078..dcfc3b9 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) { >>>>> @@ -183,7 +173,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); >>>>> } >>>>> @@ -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(); >>>>> } >>>> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? >>> When a domain shuts down, "xl destroy" is called on its paired vTPM (by some >>> scripting that may need to be incorporated into libxl). A graceful shutdown >>> is not really needed at this point, although it might be needed in the short >>> term if the save-state operation is not atomic - but a method of recovering >>> from this type of failure is needed for vTPMs anyway. >> This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. >> >> What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? >> >> If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. >> > I have approached this problem from the opposite direction, while looking at > adding protection from vTPM state rollback. The method that I am currently > considering is to have two "slots" in the vTPM disk image - one active and > and one inactive. The save process would then consist of writing a new save > state to the inactive slot, ensuring it has been committed to disk, and then > requesting the TPM Manager atomically update the state encryption key to the > new value. When loading, the key obtained from the TPM manager will only be > able to decrypt one of the two state images; the successful one is the active > image. Since the vTPM''s saved state is not expected to be very large, this > doesn''t waste a significant amount of disk space. >I like that idea in general, but it still doesn''t solve the shutdown race condition. You might not get a corrupted disk but you can still get inadvertently rolled back. Adding a xenstore watch as samuel suggested and doing a clean shutdown would be ideal. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Nov-27 20:30 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 03:21 PM, Matthew Fioravante wrote:> On 11/27/2012 03:11 PM, Daniel De Graaf wrote: >> On 11/27/2012 02:48 PM, Matthew Fioravante wrote: >>> On 11/27/2012 02:02 PM, Daniel De Graaf wrote: >>>> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >>>>> On 11/27/2012 10:14 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. >>>>>> This also enables a single vTPM to provide multiple tpmback interfaces >>>>>> so that several closely related domains can share a vTPM (for example, a >>>>>> qemu device stubdom and its target domain). >>>>>> >>>>>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>>>>> --- >>>>>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>>>>> stubdom/vtpm/vtpm.c | 16 +++--------- >>>>>> 2 files changed, 59 insertions(+), 18 deletions(-) >>>>>> >>>>>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>>>>> index b84eff1..31ace1a 100644 >>>>>> --- a/stubdom/tpmemu-0.7.4.patch >>>>>> +++ b/stubdom/tpmemu-0.7.4.patch >>>>>> @@ -1,9 +1,60 @@ >>>>>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>>>>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>>>>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>>>>> -@@ -249,7 +249,7 @@ >>>>>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>>>>> +index aabe6c3..440a01b 100644 >>>>>> +--- a/tpm/tpm_emulator_extern.c >>>>>> ++++ b/tpm/tpm_emulator_extern.c >>>>>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>>>>> #else /* TPM_NO_EXTERN */ >>>>>> - >>>>>> + >>>>>> int (*tpm_extern_init)(void) = NULL; >>>>>> -int (*tpm_extern_release)(void) = NULL; >>>>>> +void (*tpm_extern_release)(void) = NULL; >>>>>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>>>>> index c33e078..dcfc3b9 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) { >>>>>> @@ -183,7 +173,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); >>>>>> } >>>>>> @@ -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(); >>>>>> } >>>>> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? >>>> When a domain shuts down, "xl destroy" is called on its paired vTPM (by some >>>> scripting that may need to be incorporated into libxl). A graceful shutdown >>>> is not really needed at this point, although it might be needed in the short >>>> term if the save-state operation is not atomic - but a method of recovering >>>> from this type of failure is needed for vTPMs anyway. >>> This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. >>> >>> What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? >>> >>> If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. >>> >> I have approached this problem from the opposite direction, while looking at >> adding protection from vTPM state rollback. The method that I am currently >> considering is to have two "slots" in the vTPM disk image - one active and >> and one inactive. The save process would then consist of writing a new save >> state to the inactive slot, ensuring it has been committed to disk, and then >> requesting the TPM Manager atomically update the state encryption key to the >> new value. When loading, the key obtained from the TPM manager will only be >> able to decrypt one of the two state images; the successful one is the active >> image. Since the vTPM''s saved state is not expected to be very large, this >> doesn''t waste a significant amount of disk space. >> > I like that idea in general, but it still doesn''t solve the shutdown race condition. You might not get a corrupted disk but you can still get inadvertently rolled back. Adding a xenstore watch as samuel suggested and doing a clean shutdown would be ideal.If you run the save before you send back the TPM response, you won''t have any races - if a domain dies without getting a TPM response, the it''s valid for the command to not have completed. The TPM emulator does execute the save prior to returning the result packet, so this race is already avoided. That''s not to say that handling shutdowns properly is useless, of course; other minios domains may need it, and a graceful shutdown is easier to clean up after if not all peers of the vTPM are shutting down at the same time. -- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-27 20:34 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 03:30 PM, Daniel De Graaf wrote:> On 11/27/2012 03:21 PM, Matthew Fioravante wrote: >> On 11/27/2012 03:11 PM, Daniel De Graaf wrote: >>> On 11/27/2012 02:48 PM, Matthew Fioravante wrote: >>>> On 11/27/2012 02:02 PM, Daniel De Graaf wrote: >>>>> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >>>>>> On 11/27/2012 10:14 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. >>>>>>> This also enables a single vTPM to provide multiple tpmback interfaces >>>>>>> so that several closely related domains can share a vTPM (for example, a >>>>>>> qemu device stubdom and its target domain). >>>>>>> >>>>>>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>>>>>> --- >>>>>>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>>>>>> stubdom/vtpm/vtpm.c | 16 +++--------- >>>>>>> 2 files changed, 59 insertions(+), 18 deletions(-) >>>>>>> >>>>>>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>>>>>> index b84eff1..31ace1a 100644 >>>>>>> --- a/stubdom/tpmemu-0.7.4.patch >>>>>>> +++ b/stubdom/tpmemu-0.7.4.patch >>>>>>> @@ -1,9 +1,60 @@ >>>>>>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>>>>>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>>>>>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>>>>>> -@@ -249,7 +249,7 @@ >>>>>>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>>>>>> +index aabe6c3..440a01b 100644 >>>>>>> +--- a/tpm/tpm_emulator_extern.c >>>>>>> ++++ b/tpm/tpm_emulator_extern.c >>>>>>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>>>>>> #else /* TPM_NO_EXTERN */ >>>>>>> - >>>>>>> + >>>>>>> int (*tpm_extern_init)(void) = NULL; >>>>>>> -int (*tpm_extern_release)(void) = NULL; >>>>>>> +void (*tpm_extern_release)(void) = NULL; >>>>>>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>>>>>> index c33e078..dcfc3b9 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) { >>>>>>> @@ -183,7 +173,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); >>>>>>> } >>>>>>> @@ -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(); >>>>>>> } >>>>>> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? >>>>> When a domain shuts down, "xl destroy" is called on its paired vTPM (by some >>>>> scripting that may need to be incorporated into libxl). A graceful shutdown >>>>> is not really needed at this point, although it might be needed in the short >>>>> term if the save-state operation is not atomic - but a method of recovering >>>>> from this type of failure is needed for vTPMs anyway. >>>> This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. >>>> >>>> What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? >>>> >>>> If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. >>>> >>> I have approached this problem from the opposite direction, while looking at >>> adding protection from vTPM state rollback. The method that I am currently >>> considering is to have two "slots" in the vTPM disk image - one active and >>> and one inactive. The save process would then consist of writing a new save >>> state to the inactive slot, ensuring it has been committed to disk, and then >>> requesting the TPM Manager atomically update the state encryption key to the >>> new value. When loading, the key obtained from the TPM manager will only be >>> able to decrypt one of the two state images; the successful one is the active >>> image. Since the vTPM''s saved state is not expected to be very large, this >>> doesn''t waste a significant amount of disk space. >>> >> I like that idea in general, but it still doesn''t solve the shutdown race condition. You might not get a corrupted disk but you can still get inadvertently rolled back. Adding a xenstore watch as samuel suggested and doing a clean shutdown would be ideal. > > If you run the save before you send back the TPM response, you won''t have any > races - if a domain dies without getting a TPM response, the it''s valid for > the command to not have completed. The TPM emulator does execute the save > prior to returning the result packet, so this race is already avoided. > > That''s not to say that handling shutdowns properly is useless, of course; other > minios domains may need it, and a graceful shutdown is easier to clean up after > if not all peers of the vTPM are shutting down at the same time.Ok I follow you now. Do you already have patches to do the disk mirroring and destroy the vtpm from libxl? I think we will want to include this so these new features don''t break the automatic vtpm shutdown model already in place. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Nov-27 20:40 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/27/2012 03:34 PM, Matthew Fioravante wrote:> On 11/27/2012 03:30 PM, Daniel De Graaf wrote: >> On 11/27/2012 03:21 PM, Matthew Fioravante wrote: >>> On 11/27/2012 03:11 PM, Daniel De Graaf wrote: >>>> On 11/27/2012 02:48 PM, Matthew Fioravante wrote: >>>>> On 11/27/2012 02:02 PM, Daniel De Graaf wrote: >>>>>> On 11/27/2012 01:19 PM, Matthew Fioravante wrote: >>>>>>> On 11/27/2012 10:14 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. >>>>>>>> This also enables a single vTPM to provide multiple tpmback interfaces >>>>>>>> so that several closely related domains can share a vTPM (for example, a >>>>>>>> qemu device stubdom and its target domain). >>>>>>>> >>>>>>>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >>>>>>>> --- >>>>>>>> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >>>>>>>> stubdom/vtpm/vtpm.c | 16 +++--------- >>>>>>>> 2 files changed, 59 insertions(+), 18 deletions(-) >>>>>>>> >>>>>>>> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >>>>>>>> index b84eff1..31ace1a 100644 >>>>>>>> --- a/stubdom/tpmemu-0.7.4.patch >>>>>>>> +++ b/stubdom/tpmemu-0.7.4.patch >>>>>>>> @@ -1,9 +1,60 @@ >>>>>>>> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >>>>>>>> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >>>>>>>> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >>>>>>>> -@@ -249,7 +249,7 @@ >>>>>>>> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >>>>>>>> +index aabe6c3..440a01b 100644 >>>>>>>> +--- a/tpm/tpm_emulator_extern.c >>>>>>>> ++++ b/tpm/tpm_emulator_extern.c >>>>>>>> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >>>>>>>> #else /* TPM_NO_EXTERN */ >>>>>>>> - >>>>>>>> + >>>>>>>> int (*tpm_extern_init)(void) = NULL; >>>>>>>> -int (*tpm_extern_release)(void) = NULL; >>>>>>>> +void (*tpm_extern_release)(void) = NULL; >>>>>>>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>>>>>>> index c33e078..dcfc3b9 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) { >>>>>>>> @@ -183,7 +173,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); >>>>>>>> } >>>>>>>> @@ -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(); >>>>>>>> } >>>>>>> Before the vtpm would shut down on its own when the host domain disconnects. This occurs because tpmback_req() returns NULL if the frontend disconnected. Using tpmback_req_any(), this is no longer the case which now means the user has to shut down the vtpm manually. How are you handling vtpm shutdown on your end? >>>>>> When a domain shuts down, "xl destroy" is called on its paired vTPM (by some >>>>>> scripting that may need to be incorporated into libxl). A graceful shutdown >>>>>> is not really needed at this point, although it might be needed in the short >>>>>> term if the save-state operation is not atomic - but a method of recovering >>>>>> from this type of failure is needed for vTPMs anyway. >>>>> This is kind of a difficult problem. The save state operation is not by any means atomic and it is very possible that the guest shuts down and xl destroy is called before the save operation completes. This is especially true if the guest is an embedded or even a mini-os domain using tpmfront that shuts down very quickly. Its the reason why now the vtpm shuts itself down after the guest disconnects. >>>>> >>>>> What is really needed is a way to do an xl shutdown on mini-os domains to let vtpm-stubdom shutdown correctly. From what I understand there is not yet any support for this in mini-os. How tricky would it be to add that? Samuel any ideas? >>>>> >>>>> If thats not possible, another potential hack could be writing a key in xenstore to trigger the shutdown or setting up some other kind of event channel mechanism between the vtpm domain and libxl. >>>>> >>>> I have approached this problem from the opposite direction, while looking at >>>> adding protection from vTPM state rollback. The method that I am currently >>>> considering is to have two "slots" in the vTPM disk image - one active and >>>> and one inactive. The save process would then consist of writing a new save >>>> state to the inactive slot, ensuring it has been committed to disk, and then >>>> requesting the TPM Manager atomically update the state encryption key to the >>>> new value. When loading, the key obtained from the TPM manager will only be >>>> able to decrypt one of the two state images; the successful one is the active >>>> image. Since the vTPM''s saved state is not expected to be very large, this >>>> doesn''t waste a significant amount of disk space. >>>> >>> I like that idea in general, but it still doesn''t solve the shutdown race condition. You might not get a corrupted disk but you can still get inadvertently rolled back. Adding a xenstore watch as samuel suggested and doing a clean shutdown would be ideal. >> If you run the save before you send back the TPM response, you won''t have any >> races - if a domain dies without getting a TPM response, the it''s valid for >> the command to not have completed. The TPM emulator does execute the save >> prior to returning the result packet, so this race is already avoided. >> >> That''s not to say that handling shutdowns properly is useless, of course; other >> minios domains may need it, and a graceful shutdown is easier to clean up after >> if not all peers of the vTPM are shutting down at the same time. > Ok I follow you now. Do you already have patches to do the disk mirroring and destroy the vtpm from libxl? I think we will want to include this so these new features don''t break the automatic vtpm shutdown model already in place. >No, I haven''t implemented either of those yet. The destroy that I''m using is not based on libxl (it assumes both the vtpm and client domain are being created by a dedicated domain-builder domain, and so don''t have a libxl watcher process). -- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-27 21:29 UTC
Re: [PATCH 1/4] stubdom: Change vTPM shared page ABI
I can''t get this patch to apply. It looks like your editor or something else is converting tabs to whitespace. For instance the line in tpmback.h domid_t domid; /* Domid of the frontend */ has tabs between domid; and /*. It looks like this also happened to your linux patch. On 11/27/2012 10:14 AM, Daniel De Graaf wrote:> 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. > > 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 | 159 +++++++++++++++++++------------------ > extras/mini-os/tpmfront.c | 162 ++++++++++++++++++++++---------------- > xen/include/public/io/tpmif.h | 45 +++-------- > 5 files changed, 191 insertions(+), 183 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..2d31061 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; > @@ -266,6 +263,7 @@ int insert_tpmif(tpmif_t* tpmif) > unsigned int i, j; > tpmif_t* tmp; > char* err; > + char path[512]; > > local_irq_save(flags); > > @@ -303,6 +301,16 @@ int insert_tpmif(tpmif_t* tpmif) > > local_irq_restore(flags); > > + snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); > + if ((err = xenbus_write(XBT_NIL, path, "1"))) > + { > + /* if we got an error here we should carefully remove the interface and then return */ > + TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > + free(err); > + remove_tpmif(tpmif); > + goto error_post_irq; > + } > + > /*Listen for state changes on the new interface */ > if((err = xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path, tpmif->fe_state_path, >pmdev.events))) > { > @@ -312,7 +320,6 @@ int insert_tpmif(tpmif_t* tpmif) > remove_tpmif(tpmif); > goto error_post_irq; > } > - > return 0; > error: > local_irq_restore(flags); > @@ -386,8 +393,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 +401,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 +433,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 +483,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 +526,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); > @@ -584,12 +582,26 @@ int connect_fe(tpmif_t* tpmif) > } > free(value); > > + /* Check that protocol v2 is being used */ > + snprintf(path, 512, "%s/feature-protocol-v2", tpmif->fe_path); > + if((err = xenbus_read(XBT_NIL, path, &value))) { > + TPMBACK_ERR("Unable to read %s during tpmback initialization! error = %s\n", path, err); > + free(err); > + return -1; > + } > + if(strcmp(value, "1")) { > + TPMBACK_ERR("%s has an invalid value (%s)\n", path, value); > + free(value); > + return -1; > + } > + 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,10 +630,28 @@ 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; > } > > +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, XenbusStateReconfigured); > + > + 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); > @@ -874,6 +904,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 +915,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 +930,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 +976,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 +1007,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..c1cbab3 100644 > --- a/extras/mini-os/tpmfront.c > +++ b/extras/mini-os/tpmfront.c > @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) > > } > > +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* path) > +{ > + int state; > + > + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); > + while(1) { > + state = xenbus_read_integer(path); > + if ( state < 0) > + state = XenbusStateUnknown; > + switch(state) { > + case XenbusStateUnknown: > + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); > + return -1; > + case XenbusStateClosed: > + TPMFRONT_LOG("Backend Closed\n"); > + return 0; > + case XenbusStateReconfigured: > + TPMFRONT_LOG("Backend Reconfigured\n"); > + return 0; > + default: > + xenbus_wait_for_watch(events); > + } > + } > + > +} > + > static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { > char* err; > int ret = 0; > @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState > case XenbusStateClosed: > ret = wait_for_backend_closed(&events, path); > break; > - default: > + case XenbusStateReconfigured: > + ret = wait_for_backend_reconfig(&events, path); > break; > + default: > + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); > } > > if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { > @@ -190,13 +219,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 +257,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 +269,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"); > > @@ -279,6 +307,15 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) > goto error; > } > > + /* Publish protocol v2 feature */ > + snprintf(path, 512, "%s/feature-protocol-v2", dev->nodename); > + if ((err = xenbus_write(XBT_NIL, path, "1"))) > + { > + TPMFRONT_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > + free(err); > + goto error; > + } > + > /* Create and publish grant reference and event channel */ > if (tpmfront_connect(dev)) { > goto error; > @@ -289,18 +326,18 @@ 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) { > + snprintf(path, 512, "%s/feature-protocol-v2", dev->bepath); > + if((err = xenbus_read(XBT_NIL, path, &value))) { > + TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = %s\n", path, err); > + free(err); > 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; > - } > + if(strcmp(value, "1")) { > + TPMFRONT_ERR("%s has an invalid value (%s)\n", path, value); > + free(value); > + goto error; > } > + free(value); > > TPMFRONT_LOG("Initialization Completed successfully\n"); > > @@ -314,12 +351,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > { > char* err; > char path[512]; > - int i; > - tpmif_tx_request_t* tx; > if(dev == NULL) { > return; > } > - TPMFRONT_LOG("Shutting down tpmfront\n"); > + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); > /* disconnect */ > if(dev->state == XenbusStateConnected) { > dev->state = XenbusStateClosing; > @@ -349,27 +384,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 +407,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 +431,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 +455,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 +522,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 >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Nov-27 22:08 UTC
Re: [PATCH 1/4] stubdom: Change vTPM shared page ABI
On 11/27/2012 04:29 PM, Matthew Fioravante wrote:> I can''t get this patch to apply. It looks like your editor or something else is converting tabs to whitespace. For instance the line in tpmback.h > > domid_t domid; /* Domid of the frontend */ > > has tabs between domid; and /*. It looks like this also happened to your linux patch.The problem looks like it''s on your end; my patch has a tab character there, and it shows up with a tab character in my copy of the xen-devel list. As a quick workaround, I have pushed these patches to my github repository: https://github.com/danieldg/xen-unstable/commits/vtpm> > On 11/27/2012 10:14 AM, Daniel De Graaf wrote: >> 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. >> >> 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 | 159 +++++++++++++++++++------------------ >> extras/mini-os/tpmfront.c | 162 ++++++++++++++++++++++---------------- >> xen/include/public/io/tpmif.h | 45 +++-------- >> 5 files changed, 191 insertions(+), 183 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 */
Daniel De Graaf
2012-Nov-27 22:16 UTC
[PATCH] 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 | 66 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c index b343bd8..f988606 100644 --- a/stubdom/vtpm/vtpmblk.c +++ b/stubdom/vtpm/vtpmblk.c @@ -23,6 +23,8 @@ /*Encryption key and block sizes */ #define BLKSZ 16 +/* Maximum size of one saved-state slot */ +#define SLOT_SIZE 32768 static struct blkfront_dev* blkdev = NULL; static int blkfront_fd = -1; @@ -59,15 +61,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); + if (data_length > SLOT_SIZE - 4) { + error("write(data) cannot fit in data slot (%d). Increase SLOT_SIZE.", data_length); + 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 +89,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 +104,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) { @@ -221,6 +232,8 @@ egress: return rc; } +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 +241,15 @@ 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 */ + 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 +272,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 +287,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; + /* Read slot 0 from disk now */ + 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, hash0); + if(!memcmp(hash0, hashkey, HASHSZ)) + goto valid; + + free(cipher); + cipher = NULL; + + active_slot = 1; + /* Read slot 1 from disk now */ + 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, hash); - if(memcmp(hash, hashkey, HASHSZ)) { + sha1(cipher, cipher_len, hash1); + if(!memcmp(hash1, hashkey, HASHSZ)) + goto valid; + + { int i; error("NVM Storage Checksum failed!"); printf("Expected: "); @@ -285,14 +320,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 +341,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
Konrad Rzeszutek Wilk
2012-Nov-28 20:46 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
On Fri, Nov 23, 2012 at 11:04:06AM +0000, Ian Campbell wrote:> On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: > > This was something I''ve been wanting to do for a while so I''m very > > happy you went ahead and fixed it yourself. Once you submit the linux > > version I''ll test it on my system. > > > > Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > > Do we need to synchronise with anything else (Linux drivers?) or I can I > just throw this into the tree once it is done? > > Are we hanging any existing users of the tpm stuff out to dry? Could we > get a feature-protocol-v2 flag in xenstore so users at least get an > error message from either the front or backend to give a hint why it > isn''t working?We could cop out and just name this new driver differently. Then we would not have to deal with the older ones.> > > 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 > > Dodgy indentation? (I saw a bunch of these) > > > - * Copyright (c) 2005, IBM Corporation > > - * > > - * Author: Stefan Berger, stefanb@us.ibm.com > > - * Grant table support: Mahadevan Gomathisankaran > > Did you really remove everything these guys wrote? > > > - * This code has been derived from tools/libxc/xen/io/netif.h > > - * > > - * Copyright (c) 2003-2004, Keir Fraser > > I guess I can buy this bit no longer being true given that you reworked > the whole protocol. > > Ian > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel >
Samuel Thibault
2012-Nov-28 21:58 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
Matthew Fioravante, le Tue 27 Nov 2012 14:48:29 -0500, a écrit :> What is really needed is a way to do an xl shutdown on mini-os domains to > let vtpm-stubdom shutdown correctly. From what I understand there is not yet > any support for this in mini-os. How tricky would it be to add that? Samuel > any ideas?I have just posted a patch for this. Samuel
Matthew Fioravante
2012-Nov-28 22:22 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
On 11/28/2012 03:46 PM, Konrad Rzeszutek Wilk wrote:> On Fri, Nov 23, 2012 at 11:04:06AM +0000, Ian Campbell wrote: >> On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: >>> This was something I''ve been wanting to do for a while so I''m very >>> happy you went ahead and fixed it yourself. Once you submit the linux >>> version I''ll test it on my system. >>> >>> Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >> Do we need to synchronise with anything else (Linux drivers?) or I can I >> just throw this into the tree once it is done? >> >> Are we hanging any existing users of the tpm stuff out to dry? Could we >> get a feature-protocol-v2 flag in xenstore so users at least get an >> error message from either the front or backend to give a hint why it >> isn''t working? > We could cop out and just name this new driver differently. Then > we would not have to deal with the older ones.I''ve already done that with my patch on the linux mailing list. The old frontend driver name was tpm_xenu.ko, the new one is xen-tpmfront.ko.> >>> 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 >> Dodgy indentation? (I saw a bunch of these) >> >>> - * Copyright (c) 2005, IBM Corporation >>> - * >>> - * Author: Stefan Berger, stefanb@us.ibm.com >>> - * Grant table support: Mahadevan Gomathisankaran >> Did you really remove everything these guys wrote? >> >>> - * This code has been derived from tools/libxc/xen/io/netif.h >>> - * >>> - * Copyright (c) 2003-2004, Keir Fraser >> I guess I can buy this bit no longer being true given that you reworked >> the whole protocol. >> >> Ian >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xen.org >> http://lists.xen.org/xen-devel >>_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
On Wed, 2012-11-28 at 22:22 +0000, Matthew Fioravante wrote:> On 11/28/2012 03:46 PM, Konrad Rzeszutek Wilk wrote:> > We could cop out and just name this new driver differently. Then > > we would not have to deal with the older ones. > I''ve already done that with my patch on the linux mailing list. The old > frontend driver name was tpm_xenu.ko, the new one is xen-tpmfront.ko.The name of the driver module isn''t really relevant here, what matters is the name component of the xenstore paths used to trigger the creation the front and back devices, if they end up loading mutually incomprehensible versions of front and back then I expect that the failure case will be pretty hard to diagnose. The code I''m talking about is a handful of lines in both front and back, with $OTHEREND substituted as appropriate: err = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1"); if (err) { message = "writing feature-protocol-v2"; goto abort_transaction; } ... if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-protocol-v2", "%d", &val) < 0) { printk(KERN_WARN "Warning: $OTHEREND does not appear to support feature-protocol-v2\n"); printk(KERN_WARN "Perhaps it is running the obsolete out of tree vtpm driver?\n"); return -EFOOBAR; } Tweak the actual wording to taste. If there is a better/more descriptive name for the new protocol than "protocol-v2" that would be better, or you could put the 2 into the value (e.g. protocol = 2) and check via that instead (a bit more future proof perhaps?). Ian.
Matthew Fioravante
2012-Nov-29 14:14 UTC
Re: [PATCH 1/4] stubdom: Change vTPM shared page ABI
Ok I''ve taken time to look at your patch. I had to make some minor changes to make it work but other than that I was able to test it and it worked. Comments inlined. On 11/27/2012 10:14 AM, Daniel De Graaf wrote:> 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. > > 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 | 159 +++++++++++++++++++------------------ > extras/mini-os/tpmfront.c | 162 ++++++++++++++++++++++---------------- > xen/include/public/io/tpmif.h | 45 +++-------- > 5 files changed, 191 insertions(+), 183 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); > * */f > 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..2d31061 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; > @@ -266,6 +263,7 @@ int insert_tpmif(tpmif_t* tpmif) > unsigned int i, j; > tpmif_t* tmp; > char* err; > + char path[512]; > > local_irq_save(flags); > > @@ -303,6 +301,16 @@ int insert_tpmif(tpmif_t* tpmif) > > local_irq_restore(flags); > > + snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); > + if ((err = xenbus_write(XBT_NIL, path, "1"))) > + { > + /* if we got an error here we should carefully remove the interface and then return */ > + TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > + free(err); > + remove_tpmif(tpmif); > + goto error_post_irq; > + } > +My preference is still to do away with the versioning stuff since tpm is just getting released. Its not even in linux yet so there is no confusion. We can even merge the linux patches together and resubmit as one if thats preferrable. Konrad, Ian, your final votes on that? If we do go the versioning route, I''d rather a feature-protocol key with value=2 or something like that to make it upgradable. Also don''t forget to add this to the linux side, its not in the patch you sent me yet.> /*Listen for state changes on the new interface */ > if((err = xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path, tpmif->fe_state_path, >pmdev.events))) > { > @@ -312,7 +320,6 @@ int insert_tpmif(tpmif_t* tpmif) > remove_tpmif(tpmif); > goto error_post_irq; > } > - > return 0; > error: > local_irq_restore(flags); > @@ -386,8 +393,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 +401,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 +433,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 +483,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 +526,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); > @@ -584,12 +582,26 @@ int connect_fe(tpmif_t* tpmif) > } > free(value); > > + /* Check that protocol v2 is being used */ > + snprintf(path, 512, "%s/feature-protocol-v2", tpmif->fe_path); > + if((err = xenbus_read(XBT_NIL, path, &value))) { > + TPMBACK_ERR("Unable to read %s during tpmback initialization! error = %s\n", path, err); > + free(err); > + return -1; > + } > + if(strcmp(value, "1")) { > + TPMBACK_ERR("%s has an invalid value (%s)\n", path, value); > + free(value); > + return -1; > + } > + 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,10 +630,28 @@ 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; > } > > +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, XenbusStateReconfigured); > + > + TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int) tpmif->domid, tpmif->handle); > +} > +This function is flagged by -Wunused-function. I think you meant to include this in your second patch that does the reconfig stuff.> static int frontend_changed(tpmif_t* tpmif) > { > int state = xenbus_read_integer(tpmif->fe_state_path); > @@ -874,6 +904,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 +915,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 +930,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 +976,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 +1007,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..c1cbab3 100644 > --- a/extras/mini-os/tpmfront.c > +++ b/extras/mini-os/tpmfront.c > @@ -153,6 +153,32 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) > > } > > +static int wait_for_backend_reconfig(xenbus_event_queue* events, char* path) > +{ > + int state; > + > + TPMFRONT_LOG("Waiting for backend to reconfigure...\n"); > + while(1) { > + state = xenbus_read_integer(path); > + if ( state < 0) > + state = XenbusStateUnknown; > + switch(state) { > + case XenbusStateUnknown: > + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); > + return -1; > + case XenbusStateClosed: > + TPMFRONT_LOG("Backend Closed\n"); > + return 0; > + case XenbusStateReconfigured: > + TPMFRONT_LOG("Backend Reconfigured\n"); > + return 0; > + default: > + xenbus_wait_for_watch(events); > + } > + } > + > +} > +Does this reconfigure stuff make sense without patch 2?> static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { > char* err; > int ret = 0; > @@ -175,8 +201,11 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState > case XenbusStateClosed: > ret = wait_for_backend_closed(&events, path); > break; > - default: > + case XenbusStateReconfigured: > + ret = wait_for_backend_reconfig(&events, path); > break; > + default: > + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); > }See above comment> > if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { > @@ -190,13 +219,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 +257,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 +269,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"); > > @@ -279,6 +307,15 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) > goto error; > } > > + /* Publish protocol v2 feature */ > + snprintf(path, 512, "%s/feature-protocol-v2", dev->nodename); > + if ((err = xenbus_write(XBT_NIL, path, "1"))) > + { > + TPMFRONT_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > + free(err); > + goto error; > + } > + > /* Create and publish grant reference and event channel */ > if (tpmfront_connect(dev)) { > goto error; > @@ -289,18 +326,18 @@ 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) { > + snprintf(path, 512, "%s/feature-protocol-v2", dev->bepath); > + if((err = xenbus_read(XBT_NIL, path, &value))) { > + TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = %s\n", path, err); > + free(err); > 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; > - } > + if(strcmp(value, "1")) { > + TPMFRONT_ERR("%s has an invalid value (%s)\n", path, value); > + free(value); > + goto error; > } > + free(value); > > TPMFRONT_LOG("Initialization Completed successfully\n"); > > @@ -314,12 +351,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > { > char* err; > char path[512]; > - int i; > - tpmif_tx_request_t* tx; > if(dev == NULL) { > return; > } > - TPMFRONT_LOG("Shutting down tpmfront\n"); > + TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : "");I think the above line belongs in your second patch. for_reconfig is undefined, causing compilation to fail.> /* disconnect */ > if(dev->state == XenbusStateConnected) { > dev->state = XenbusStateClosing; > @@ -349,27 +384,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 +407,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 +431,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; > }I think it might be useful to #define a TPMIF_CAP_PROP_BUFFER_SIZE in tpmif.h so people know ahead of time the largest command they can send. Then they can create arrays on the stack with the correct length etc.. This brings up another issue. According to the TPM PC Client spec section 11.3.8, there is a capability TPM_CAP_PROP_BUFFER_SIZE. We should probably patch the emulator in vtpm-stubdom to make it return TPMIF_CAP_PROP_BUFFER_SIZE for this capability. You don''t have to worry about this now if you don''t want to. I can do it later once this stuff is in. If you do decide to tackle it, make it a separate patch.> + 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 +455,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 +522,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 >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Nov-29 18:07 UTC
Re: [PATCH] stubdom/vtpm: make state save operation atomic
On 11/27/2012 05:16 PM, Daniel De Graaf wrote:> 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 | 66 +++++++++++++++++++++++++++++++++++++++++--------- > 1 file changed, 54 insertions(+), 12 deletions(-) > > diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c > index b343bd8..f988606 100644 > --- a/stubdom/vtpm/vtpmblk.c > +++ b/stubdom/vtpm/vtpmblk.c > @@ -23,6 +23,8 @@ > > /*Encryption key and block sizes */ > #define BLKSZ 16 > +/* Maximum size of one saved-state slot */ > +#define SLOT_SIZE 32768Instead of statically defining a slot size and stressing over whether or not it may be too small, why not make it half the size of the disk image? You can retrieve the disk size by doing fstat(blkfront_fd).> > static struct blkfront_dev* blkdev = NULL; > static int blkfront_fd = -1; > @@ -59,15 +61,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);Should add which slot were writing to and possibly the disk offset as well to the debug print> > + if (data_length > SLOT_SIZE - 4) { > + error("write(data) cannot fit in data slot (%d). Increase SLOT_SIZE.", data_length); > + 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 +89,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 +104,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) { > @@ -221,6 +232,8 @@ egress: > return rc; > } > > +static int active_slot = -1;I think we should initialize to 0 or 1 because -1 is an invalid state. For a new vtpm, read_vtpmblk() will fail and I think this is what happens: read_vtpmblk() try_fetch_key_from_manager() -> fails goto abort_egress active_slot = -1 (you have this below) Then later write_vtpmblk() active_slot = !active_slot (!-1 = 0) The last line happens to work correctly but I don''t think its very clear. I think we should initialize to 1 and set it to 1 if read_vtpmblk() fails. Also a minor nitpick, the name is active_slot, but what it really is is the last_slot_written_to because everytime you write you change it first.> + > int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { > int rc; > uint8_t* cipher = NULL; > @@ -228,12 +241,15 @@ 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 */ > + 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 +272,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 +287,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; > + /* Read slot 0 from disk now */ > + 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, hash0); > + if(!memcmp(hash0, hashkey, HASHSZ)) > + goto valid; > + > + free(cipher); > + cipher = NULL; > + > + active_slot = 1; > + /* Read slot 1 from disk now */ > + 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, hash); > - if(memcmp(hash, hashkey, HASHSZ)) { > + sha1(cipher, cipher_len, hash1); > + if(!memcmp(hash1, hashkey, HASHSZ)) > + goto valid; > + > + { > int i; > error("NVM Storage Checksum failed!"); > printf("Expected: "); > @@ -285,14 +320,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 +341,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data > } > goto egress; > abort_egress: > + active_slot = -1;See my comment above> egress: > free(cipher); > free(hashkey);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Nov-29 18:53 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
The purpose of this is to allow 2 entities in the same vm to use tpm drivers, pv_grub and the linux guest. The Xenbus Reconfigure states are new to me. Is this intended behavior in line with the original purpose of the Reconfigure states or are we hijacking them to do something not in the original xen front/back driver spec? It looks like pv-grub just shuts down blkfront and the others without any reconfigure magic. Given that vtpm-stubdom will no longer automatically shutdown with your later patch, is there any reason we cannot just do the same here? On 11/27/2012 10:14 AM, Daniel De Graaf wrote:> 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/include/tpmfront.h | 2 +- > extras/mini-os/lib/sys.c | 2 +- > extras/mini-os/tpmback.c | 5 +++++ > extras/mini-os/tpmfront.c | 15 +++++++++------ > stubdom/vtpm/vtpm.c | 2 +- > 5 files changed, 17 insertions(+), 9 deletions(-) > > diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h > index a0c7c4d..913faa4 100644 > --- a/extras/mini-os/include/tpmfront.h > +++ b/extras/mini-os/include/tpmfront.h > @@ -61,7 +61,7 @@ struct tpmfront_dev { > /*Initialize frontend */ > struct tpmfront_dev* init_tpmfront(const char* nodename); > /*Shutdown frontend */ > -void shutdown_tpmfront(struct tpmfront_dev* dev); > +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig); > > /* Send a tpm command to the backend and wait for the response > * > diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c > index 3cc3340..03da4f0 100644 > --- a/extras/mini-os/lib/sys.c > +++ b/extras/mini-os/lib/sys.c > @@ -459,7 +459,7 @@ int close(int fd) > #endif > #ifdef CONFIG_TPMFRONT > case FTYPE_TPMFRONT: > - shutdown_tpmfront(files[fd].tpmfront.dev); > + shutdown_tpmfront(files[fd].tpmfront.dev, 0); > files[fd].type = FTYPE_NONE; > return 0; > #endif > diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c > index 2d31061..ea42235 100644 > --- a/extras/mini-os/tpmback.c > +++ b/extras/mini-os/tpmback.c > @@ -664,6 +664,7 @@ static int frontend_changed(tpmif_t* tpmif) > switch (state) { > case XenbusStateInitialising: > case XenbusStateInitialised: > + case XenbusStateReconfigured: > break; > > case XenbusStateConnected: > @@ -678,6 +679,10 @@ static int frontend_changed(tpmif_t* tpmif) > tpmif_change_state(tpmif, XenbusStateClosing); > break; > > + case XenbusStateReconfiguring: > + disconnect_fe(tpmif); > + break; > + > case XenbusStateUnknown: /* keep it here */ > case XenbusStateClosed: > free_tpmif(tpmif); > diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c > index c1cbab3..b725ba0 100644 > --- a/extras/mini-os/tpmfront.c > +++ b/extras/mini-os/tpmfront.c > @@ -344,10 +344,10 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) > return dev; > > error: > - shutdown_tpmfront(dev); > + shutdown_tpmfront(dev, 0); > return NULL; > } > -void shutdown_tpmfront(struct tpmfront_dev* dev) > +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig)It might be cleaner to create a new function like reconfigure_tpmfront() or something like that instead of adding an option to shutdown_tpmfront().> { > char* err; > char path[512]; > @@ -357,8 +357,7 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); > /* disconnect */ > if(dev->state == XenbusStateConnected) { > - dev->state = XenbusStateClosing; > - //FIXME: Transaction for this? > + dev->state = for_reconfig ? XenbusStateReconfiguring : XenbusStateClosing; > /* Tell backend we are closing */ > if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { > free(err); > @@ -374,15 +373,19 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) > free(err); > } > > + if (for_reconfig) > + wait_for_backend_state_changed(dev, XenbusStateReconfigured); > + > /* Tell backend we are closed */ > - dev->state = XenbusStateClosed; > + dev->state = for_reconfig ? XenbusStateInitialising : XenbusStateClosed; > 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); > } > > /* Wait for the backend to close and unmap shared pages, ignore any errors */ > - wait_for_backend_state_changed(dev, XenbusStateClosed); > + if (!for_reconfig) > + wait_for_backend_state_changed(dev, XenbusStateClosed); > > /* Close event channel and unmap shared page */ > mask_evtchn(dev->evtchn); > diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c > index 71aef78..c33e078 100644 > --- a/stubdom/vtpm/vtpm.c > +++ b/stubdom/vtpm/vtpm.c > @@ -394,7 +394,7 @@ abort_postvtpmblk: > abort_postrng: > > /* Close devices */ > - shutdown_tpmfront(tpmfront_dev); > + shutdown_tpmfront(tpmfront_dev, 0); > abort_posttpmfront: > shutdown_tpmback(); >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Nov-29 19:09 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
Looks good. I''m actually kind of surprised that the emulator doesn''t provide an interface to set the requested locality. Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> On 11/27/2012 10:14 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. > This also enables a single vTPM to provide multiple tpmback interfaces > so that several closely related domains can share a vTPM (for example, a > qemu device stubdom and its target domain). > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- > stubdom/vtpm/vtpm.c | 16 +++--------- > 2 files changed, 59 insertions(+), 18 deletions(-) > > diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch > index b84eff1..31ace1a 100644 > --- a/stubdom/tpmemu-0.7.4.patch > +++ b/stubdom/tpmemu-0.7.4.patch > @@ -1,9 +1,60 @@ > -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c > ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 > -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 > -@@ -249,7 +249,7 @@ > +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c > +index aabe6c3..440a01b 100644 > +--- a/tpm/tpm_emulator_extern.c > ++++ b/tpm/tpm_emulator_extern.c > +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr > #else /* TPM_NO_EXTERN */ > - > + > int (*tpm_extern_init)(void) = NULL; > -int (*tpm_extern_release)(void) = NULL; > +void (*tpm_extern_release)(void) = NULL; > diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c > index c33e078..dcfc3b9 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) { > @@ -183,7 +173,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); > } > @@ -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(); > > } >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Nov-29 19:20 UTC
Re: [PATCH 4/4] stubdom/vtpm: Support multiple backends and locality
On 11/29/2012 02:09 PM, Matthew Fioravante wrote:> Looks good. I''m actually kind of surprised that the emulator doesn''t provide > an interface to set the requested locality.It does; however, it''s a rather bad interface: you can send a vendor-specific command to change the entire STANY_FLAGS data structure, which contains the locality field along with some others that really shouldn''t be changed. This patch restricts that vendor-specific command interface to locality 8, which can itself be restricted or unavailable once locality restrictions are implemented. The number 8 was chosen because it''s not usable as a quoting locality since (1<<8) won''t fit in uint8_t.> Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > > On 11/27/2012 10:14 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. >> This also enables a single vTPM to provide multiple tpmback interfaces >> so that several closely related domains can share a vTPM (for example, a >> qemu device stubdom and its target domain). >> >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >> --- >> stubdom/tpmemu-0.7.4.patch | 61 ++++++++++++++++++++++++++++++++++++++++++---- >> stubdom/vtpm/vtpm.c | 16 +++--------- >> 2 files changed, 59 insertions(+), 18 deletions(-) >> >> diff --git a/stubdom/tpmemu-0.7.4.patch b/stubdom/tpmemu-0.7.4.patch >> index b84eff1..31ace1a 100644 >> --- a/stubdom/tpmemu-0.7.4.patch >> +++ b/stubdom/tpmemu-0.7.4.patch >> @@ -1,9 +1,60 @@ >> -diff -Naur tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c tpm_emulator-x86_64/tpm/tpm_emulator_extern.c >> ---- tpm_emulator-x86_64-back/tpm/tpm_emulator_extern.c 2012-04-27 10:55:46.581963398 -0400 >> -+++ tpm_emulator-x86_64/tpm/tpm_emulator_extern.c 2012-04-27 10:56:02.193034152 -0400 >> -@@ -249,7 +249,7 @@ >> +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/tpm/tpm_emulator_extern.c b/tpm/tpm_emulator_extern.c >> +index aabe6c3..440a01b 100644 >> +--- a/tpm/tpm_emulator_extern.c >> ++++ b/tpm/tpm_emulator_extern.c >> +@@ -249,7 +249,7 @@ int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_fr >> #else /* TPM_NO_EXTERN */ >> - >> + >> int (*tpm_extern_init)(void) = NULL; >> -int (*tpm_extern_release)(void) = NULL; >> +void (*tpm_extern_release)(void) = NULL; >> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >> index c33e078..dcfc3b9 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) { >> @@ -183,7 +173,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); >> } >> @@ -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(); >> } >> > >-- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Nov-29 19:28 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
On 11/29/2012 01:53 PM, Matthew Fioravante wrote:> The purpose of this is to allow 2 entities in the same vm to use tpm drivers, pv_grub and the linux guest. The Xenbus Reconfigure states are new to me. Is this intended behavior in line with the original purpose of the Reconfigure states or are we hijacking them to do something not in the original xen front/back driver spec? > > It looks like pv-grub just shuts down blkfront and the others without any reconfigure magic. Given that vtpm-stubdom will no longer automatically shutdown with your later patch, is there any reason we cannot just do the same here?The vtpm backend in mini-os cleans up after itself destructively when it is closed: it removes xenstore entries and frees the data structures, and so requires the xenstore directory to be re-created. I originally wanted to keep the shutdown semantics the same (to preserve the vtpm auto-shutdown), although that''s not reflected in this patch queue. I think the correct method here is to make the backend act like it does for the reconfigure on close, and trigger free only when the xenstore entry vanishes.> On 11/27/2012 10:14 AM, Daniel De Graaf wrote: >> 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/include/tpmfront.h | 2 +- >> extras/mini-os/lib/sys.c | 2 +- >> extras/mini-os/tpmback.c | 5 +++++ >> extras/mini-os/tpmfront.c | 15 +++++++++------ >> stubdom/vtpm/vtpm.c | 2 +- >> 5 files changed, 17 insertions(+), 9 deletions(-) >> >> diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h >> index a0c7c4d..913faa4 100644 >> --- a/extras/mini-os/include/tpmfront.h >> +++ b/extras/mini-os/include/tpmfront.h >> @@ -61,7 +61,7 @@ struct tpmfront_dev { >> /*Initialize frontend */ >> struct tpmfront_dev* init_tpmfront(const char* nodename); >> /*Shutdown frontend */ >> -void shutdown_tpmfront(struct tpmfront_dev* dev); >> +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig); >> /* Send a tpm command to the backend and wait for the response >> * >> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c >> index 3cc3340..03da4f0 100644 >> --- a/extras/mini-os/lib/sys.c >> +++ b/extras/mini-os/lib/sys.c >> @@ -459,7 +459,7 @@ int close(int fd) >> #endif >> #ifdef CONFIG_TPMFRONT >> case FTYPE_TPMFRONT: >> - shutdown_tpmfront(files[fd].tpmfront.dev); >> + shutdown_tpmfront(files[fd].tpmfront.dev, 0); >> files[fd].type = FTYPE_NONE; >> return 0; >> #endif >> diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c >> index 2d31061..ea42235 100644 >> --- a/extras/mini-os/tpmback.c >> +++ b/extras/mini-os/tpmback.c >> @@ -664,6 +664,7 @@ static int frontend_changed(tpmif_t* tpmif) >> switch (state) { >> case XenbusStateInitialising: >> case XenbusStateInitialised: >> + case XenbusStateReconfigured: >> break; >> case XenbusStateConnected: >> @@ -678,6 +679,10 @@ static int frontend_changed(tpmif_t* tpmif) >> tpmif_change_state(tpmif, XenbusStateClosing); >> break; >> + case XenbusStateReconfiguring: >> + disconnect_fe(tpmif); >> + break; >> + >> case XenbusStateUnknown: /* keep it here */ >> case XenbusStateClosed: >> free_tpmif(tpmif); >> diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c >> index c1cbab3..b725ba0 100644 >> --- a/extras/mini-os/tpmfront.c >> +++ b/extras/mini-os/tpmfront.c >> @@ -344,10 +344,10 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) >> return dev; >> error: >> - shutdown_tpmfront(dev); >> + shutdown_tpmfront(dev, 0); >> return NULL; >> } >> -void shutdown_tpmfront(struct tpmfront_dev* dev) >> +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig) > It might be cleaner to create a new function like reconfigure_tpmfront() or something like that instead of adding an option to shutdown_tpmfront(). >> { >> char* err; >> char path[512]; >> @@ -357,8 +357,7 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) >> TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); >> /* disconnect */ >> if(dev->state == XenbusStateConnected) { >> - dev->state = XenbusStateClosing; >> - //FIXME: Transaction for this? >> + dev->state = for_reconfig ? XenbusStateReconfiguring : XenbusStateClosing; >> /* Tell backend we are closing */ >> if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { >> free(err); >> @@ -374,15 +373,19 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) >> free(err); >> } >> + if (for_reconfig) >> + wait_for_backend_state_changed(dev, XenbusStateReconfigured); >> + >> /* Tell backend we are closed */ >> - dev->state = XenbusStateClosed; >> + dev->state = for_reconfig ? XenbusStateInitialising : XenbusStateClosed; >> 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); >> } >> /* Wait for the backend to close and unmap shared pages, ignore any errors */ >> - wait_for_backend_state_changed(dev, XenbusStateClosed); >> + if (!for_reconfig) >> + wait_for_backend_state_changed(dev, XenbusStateClosed); >> /* Close event channel and unmap shared page */ >> mask_evtchn(dev->evtchn); >> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >> index 71aef78..c33e078 100644 >> --- a/stubdom/vtpm/vtpm.c >> +++ b/stubdom/vtpm/vtpm.c >> @@ -394,7 +394,7 @@ abort_postvtpmblk: >> abort_postrng: >> /* Close devices */ >> - shutdown_tpmfront(tpmfront_dev); >> + shutdown_tpmfront(tpmfront_dev, 0); >> abort_posttpmfront: >> shutdown_tpmback(); >> > >-- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-29 19:47 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
On 11/29/2012 02:28 PM, Daniel De Graaf wrote:> On 11/29/2012 01:53 PM, Matthew Fioravante wrote: >> The purpose of this is to allow 2 entities in the same vm to use tpm drivers, pv_grub and the linux guest. The Xenbus Reconfigure states are new to me. Is this intended behavior in line with the original purpose of the Reconfigure states or are we hijacking them to do something not in the original xen front/back driver spec? >> >> It looks like pv-grub just shuts down blkfront and the others without any reconfigure magic. Given that vtpm-stubdom will no longer automatically shutdown with your later patch, is there any reason we cannot just do the same here? > The vtpm backend in mini-os cleans up after itself destructively when it is > closed: it removes xenstore entries and frees the data structures, and so > requires the xenstore directory to be re-created. I originally wanted to keep > the shutdown semantics the same (to preserve the vtpm auto-shutdown), although > that''s not reflected in this patch queue. > > I think the correct method here is to make the backend act like it does for the > reconfigure on close, and trigger free only when the xenstore entry vanishes.A cursory look at blkback in linux and it looks like the backend driver doesn''t tear down the xenstore entries at all. I think its supposed to be the job of libxl to do that no? So I think I agree with you that what we really want is to change the backend to leave xenstore alone and maintain enough state so that the device can reconnect later.> >> On 11/27/2012 10:14 AM, Daniel De Graaf wrote: >>> 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/include/tpmfront.h | 2 +- >>> extras/mini-os/lib/sys.c | 2 +- >>> extras/mini-os/tpmback.c | 5 +++++ >>> extras/mini-os/tpmfront.c | 15 +++++++++------ >>> stubdom/vtpm/vtpm.c | 2 +- >>> 5 files changed, 17 insertions(+), 9 deletions(-) >>> >>> diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h >>> index a0c7c4d..913faa4 100644 >>> --- a/extras/mini-os/include/tpmfront.h >>> +++ b/extras/mini-os/include/tpmfront.h >>> @@ -61,7 +61,7 @@ struct tpmfront_dev { >>> /*Initialize frontend */ >>> struct tpmfront_dev* init_tpmfront(const char* nodename); >>> /*Shutdown frontend */ >>> -void shutdown_tpmfront(struct tpmfront_dev* dev); >>> +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig); >>> /* Send a tpm command to the backend and wait for the response >>> * >>> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c >>> index 3cc3340..03da4f0 100644 >>> --- a/extras/mini-os/lib/sys.c >>> +++ b/extras/mini-os/lib/sys.c >>> @@ -459,7 +459,7 @@ int close(int fd) >>> #endif >>> #ifdef CONFIG_TPMFRONT >>> case FTYPE_TPMFRONT: >>> - shutdown_tpmfront(files[fd].tpmfront.dev); >>> + shutdown_tpmfront(files[fd].tpmfront.dev, 0); >>> files[fd].type = FTYPE_NONE; >>> return 0; >>> #endif >>> diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c >>> index 2d31061..ea42235 100644 >>> --- a/extras/mini-os/tpmback.c >>> +++ b/extras/mini-os/tpmback.c >>> @@ -664,6 +664,7 @@ static int frontend_changed(tpmif_t* tpmif) >>> switch (state) { >>> case XenbusStateInitialising: >>> case XenbusStateInitialised: >>> + case XenbusStateReconfigured: >>> break; >>> case XenbusStateConnected: >>> @@ -678,6 +679,10 @@ static int frontend_changed(tpmif_t* tpmif) >>> tpmif_change_state(tpmif, XenbusStateClosing); >>> break; >>> + case XenbusStateReconfiguring: >>> + disconnect_fe(tpmif); >>> + break; >>> + >>> case XenbusStateUnknown: /* keep it here */ >>> case XenbusStateClosed: >>> free_tpmif(tpmif); >>> diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c >>> index c1cbab3..b725ba0 100644 >>> --- a/extras/mini-os/tpmfront.c >>> +++ b/extras/mini-os/tpmfront.c >>> @@ -344,10 +344,10 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) >>> return dev; >>> error: >>> - shutdown_tpmfront(dev); >>> + shutdown_tpmfront(dev, 0); >>> return NULL; >>> } >>> -void shutdown_tpmfront(struct tpmfront_dev* dev) >>> +void shutdown_tpmfront(struct tpmfront_dev* dev, int for_reconfig) >> It might be cleaner to create a new function like reconfigure_tpmfront() or something like that instead of adding an option to shutdown_tpmfront(). >>> { >>> char* err; >>> char path[512]; >>> @@ -357,8 +357,7 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) >>> TPMFRONT_LOG("Shutting down tpmfront%s\n", for_reconfig ? " for reconfigure" : ""); >>> /* disconnect */ >>> if(dev->state == XenbusStateConnected) { >>> - dev->state = XenbusStateClosing; >>> - //FIXME: Transaction for this? >>> + dev->state = for_reconfig ? XenbusStateReconfiguring : XenbusStateClosing; >>> /* Tell backend we are closing */ >>> if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { >>> free(err); >>> @@ -374,15 +373,19 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) >>> free(err); >>> } >>> + if (for_reconfig) >>> + wait_for_backend_state_changed(dev, XenbusStateReconfigured); >>> + >>> /* Tell backend we are closed */ >>> - dev->state = XenbusStateClosed; >>> + dev->state = for_reconfig ? XenbusStateInitialising : XenbusStateClosed; >>> 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); >>> } >>> /* Wait for the backend to close and unmap shared pages, ignore any errors */ >>> - wait_for_backend_state_changed(dev, XenbusStateClosed); >>> + if (!for_reconfig) >>> + wait_for_backend_state_changed(dev, XenbusStateClosed); >>> /* Close event channel and unmap shared page */ >>> mask_evtchn(dev->evtchn); >>> diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c >>> index 71aef78..c33e078 100644 >>> --- a/stubdom/vtpm/vtpm.c >>> +++ b/stubdom/vtpm/vtpm.c >>> @@ -394,7 +394,7 @@ abort_postvtpmblk: >>> abort_postrng: >>> /* Close devices */ >>> - shutdown_tpmfront(tpmfront_dev); >>> + shutdown_tpmfront(tpmfront_dev, 0); >>> abort_posttpmfront: >>> shutdown_tpmback(); >>> >> >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Nov-29 20:24 UTC
Re: [PATCH] stubdom/vtpm: make state save operation atomic
On 11/29/2012 01:07 PM, Matthew Fioravante wrote:> On 11/27/2012 05:16 PM, Daniel De Graaf wrote: >> 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 | 66 +++++++++++++++++++++++++++++++++++++++++--------- >> 1 file changed, 54 insertions(+), 12 deletions(-) >> >> diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c >> index b343bd8..f988606 100644 >> --- a/stubdom/vtpm/vtpmblk.c >> +++ b/stubdom/vtpm/vtpmblk.c >> @@ -23,6 +23,8 @@ >> /*Encryption key and block sizes */ >> #define BLKSZ 16 >> +/* Maximum size of one saved-state slot */ >> +#define SLOT_SIZE 32768 > Instead of statically defining a slot size and stressing over whether or not it may be too small, why not make it half the size of the disk image? You can retrieve the disk size by doing fstat(blkfront_fd).Ah, I didn''t see that information was available in mini-os. Actually, the blkinfo structure in init_vtpmblk is more convenient, so I''ll use that.>> static struct blkfront_dev* blkdev = NULL; >> static int blkfront_fd = -1; >> @@ -59,15 +61,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); > Should add which slot were writing to and possibly the disk offset as well to the debug printA number of debug outputs will be improved with slot info.>> + if (data_length > SLOT_SIZE - 4) { >> + error("write(data) cannot fit in data slot (%d). Increase SLOT_SIZE.", data_length); >> + 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 +89,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 +104,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) { >> @@ -221,6 +232,8 @@ egress: >> return rc; >> } >> +static int active_slot = -1; > I think we should initialize to 0 or 1 because -1 is an invalid state. > For a new vtpm, read_vtpmblk() will fail and I think this is what happens: > read_vtpmblk() > try_fetch_key_from_manager() -> fails > goto abort_egress > active_slot = -1 (you have this below)Yes, that''s intentional. That way, you can tell the difference between slot 1 being active and no slot being active.> Then later > write_vtpmblk() > active_slot = !active_slot (!-1 = 0) > > The last line happens to work correctly but I don''t think its very clear. I think we should initialize to 1 and set it to 1 if read_vtpmblk() fails.I think I''ll just put a comment at the !active_slot to note that active_slot is -1 => 0 if no active slots existed.> Also a minor nitpick, the name is active_slot, but what it really is is the last_slot_written_to because everytime you write you change it first.That still makes it the active slot: at the point when it''s changed, the value is the new active slot (and we''re just working to commit that change to disk).>> + >> int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { >> int rc; >> uint8_t* cipher = NULL; >> @@ -228,12 +241,15 @@ 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 */ >> + 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 +272,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 +287,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; >> + /* Read slot 0 from disk now */ >> + 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, hash0); >> + if(!memcmp(hash0, hashkey, HASHSZ)) >> + goto valid; >> + >> + free(cipher); >> + cipher = NULL; >> + >> + active_slot = 1; >> + /* Read slot 1 from disk now */ >> + 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, hash); >> - if(memcmp(hash, hashkey, HASHSZ)) { >> + sha1(cipher, cipher_len, hash1); >> + if(!memcmp(hash1, hashkey, HASHSZ)) >> + goto valid; >> + >> + { >> int i; >> error("NVM Storage Checksum failed!"); >> printf("Expected: "); >> @@ -285,14 +320,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 +341,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data >> } >> goto egress; >> abort_egress: >> + active_slot = -1; > See my comment above >> egress: >> free(cipher); >> free(hashkey); > >-- Daniel De Graaf National Security Agency
Matthew Fioravante
2012-Nov-29 20:48 UTC
Re: [PATCH] stubdom/vtpm: make state save operation atomic
On 11/29/2012 03:24 PM, Daniel De Graaf wrote:> On 11/29/2012 01:07 PM, Matthew Fioravante wrote: >> On 11/27/2012 05:16 PM, Daniel De Graaf wrote: >>> 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 | 66 +++++++++++++++++++++++++++++++++++++++++--------- >>> 1 file changed, 54 insertions(+), 12 deletions(-) >>> >>> diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c >>> index b343bd8..f988606 100644 >>> --- a/stubdom/vtpm/vtpmblk.c >>> +++ b/stubdom/vtpm/vtpmblk.c >>> @@ -23,6 +23,8 @@ >>> /*Encryption key and block sizes */ >>> #define BLKSZ 16 >>> +/* Maximum size of one saved-state slot */ >>> +#define SLOT_SIZE 32768 >> Instead of statically defining a slot size and stressing over whether or not it may be too small, why not make it half the size of the disk image? You can retrieve the disk size by doing fstat(blkfront_fd). > Ah, I didn''t see that information was available in mini-os. Actually, the blkinfo > structure in init_vtpmblk is more convenient, so I''ll use that. > >>> static struct blkfront_dev* blkdev = NULL; >>> static int blkfront_fd = -1; >>> @@ -59,15 +61,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); >> Should add which slot were writing to and possibly the disk offset as well to the debug print > A number of debug outputs will be improved with slot info. > >>> + if (data_length > SLOT_SIZE - 4) { >>> + error("write(data) cannot fit in data slot (%d). Increase SLOT_SIZE.", data_length); >>> + 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 +89,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 +104,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) { >>> @@ -221,6 +232,8 @@ egress: >>> return rc; >>> } >>> +static int active_slot = -1; >> I think we should initialize to 0 or 1 because -1 is an invalid state. >> For a new vtpm, read_vtpmblk() will fail and I think this is what happens: >> read_vtpmblk() >> try_fetch_key_from_manager() -> fails >> goto abort_egress >> active_slot = -1 (you have this below) > Yes, that''s intentional. That way, you can tell the difference between slot 1 > being active and no slot being active.Other than possibly for debugging, do we really care if no slot is active? If there is no logical active slot then either slot 0 or 1 is valid for the next write.> >> Then later >> write_vtpmblk() >> active_slot = !active_slot (!-1 = 0) >> >> The last line happens to work correctly but I don''t think its very clear. I think we should initialize to 1 and set it to 1 if read_vtpmblk() fails. > I think I''ll just put a comment at the !active_slot to note that active_slot is > -1 => 0 if no active slots existed.If we keep the -1, then defiantly a comment is warranted. There should be a block comment at active_slot''s definition to briefly explain all of this, what the valid states of active_slot are (-1, 0, 1), and what they mean because at first glance its not intuitive and looks like it could be a bug. Another self documenting option would be to use an enum or #define INVALID_SLOT -1 if you don''t want to write as much comment text.> >> Also a minor nitpick, the name is active_slot, but what it really is is the last_slot_written_to because everytime you write you change it first. > That still makes it the active slot: at the point when it''s changed, the value is > the new active slot (and we''re just working to commit that change to disk). > >>> + >>> int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { >>> int rc; >>> uint8_t* cipher = NULL; >>> @@ -228,12 +241,15 @@ 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 */ >>> + 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 +272,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 +287,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; >>> + /* Read slot 0 from disk now */ >>> + 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, hash0); >>> + if(!memcmp(hash0, hashkey, HASHSZ)) >>> + goto valid; >>> + >>> + free(cipher); >>> + cipher = NULL; >>> + >>> + active_slot = 1; >>> + /* Read slot 1 from disk now */ >>> + 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, hash); >>> - if(memcmp(hash, hashkey, HASHSZ)) { >>> + sha1(cipher, cipher_len, hash1); >>> + if(!memcmp(hash1, hashkey, HASHSZ)) >>> + goto valid; >>> + >>> + { >>> int i; >>> error("NVM Storage Checksum failed!"); >>> printf("Expected: "); >>> @@ -285,14 +320,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 +341,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data >>> } >>> goto egress; >>> abort_egress: >>> + active_slot = -1; >> See my comment above >>> egress: >>> free(cipher); >>> free(hashkey); >> >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Samuel Thibault
2012-Nov-29 21:37 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
Matthew Fioravante, le Thu 29 Nov 2012 14:47:17 -0500, a écrit :> I think I agree with you that what we really want is to change the > backend to leave xenstore alone and maintain enough state so that the > device can reconnect later.Yes, I believe that''s much nicer. Samuel
Ian Campbell
2012-Nov-30 09:59 UTC
Re: [PATCH 2/4] stubdom/vtpm: Add reconfiguration support
(can you not top post please) On Thu, 2012-11-29 at 18:53 +0000, Matthew Fioravante wrote:> The purpose of this is to allow 2 entities in the same vm to use tpm > drivers, pv_grub and the linux guest. The Xenbus Reconfigure states are > new to me. Is this intended behavior in line with the original purpose > of the Reconfigure states or are we hijacking them to do something not > in the original xen front/back driver spec?I''m not sure there was ever such a thing. The reconfigure states were originally added by the pcifront/back drivers which used them to implement device hotplug iirc. It''s looks to me like the use case here is more akin to the "online" node which the block and net stuff has? Ian.
Konrad Rzeszutek Wilk
2012-Nov-30 16:11 UTC
Re: [PATCH RFC] stubdom: Change vTPM shared page ABI
On Wed, Nov 28, 2012 at 05:22:59PM -0500, Matthew Fioravante wrote:> On 11/28/2012 03:46 PM, Konrad Rzeszutek Wilk wrote: > >On Fri, Nov 23, 2012 at 11:04:06AM +0000, Ian Campbell wrote: > >>On Tue, 2012-11-20 at 16:16 +0000, Fioravante, Matthew E. wrote: > >>>This was something I''ve been wanting to do for a while so I''m very > >>>happy you went ahead and fixed it yourself. Once you submit the linux > >>>version I''ll test it on my system. > >>> > >>>Acked by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > >>Do we need to synchronise with anything else (Linux drivers?) or I can I > >>just throw this into the tree once it is done? > >> > >>Are we hanging any existing users of the tpm stuff out to dry? Could we > >>get a feature-protocol-v2 flag in xenstore so users at least get an > >>error message from either the front or backend to give a hint why it > >>isn''t working? > >We could cop out and just name this new driver differently. Then > >we would not have to deal with the older ones. > I''ve already done that with my patch on the linux mailing list. The > old frontend driver name was tpm_xenu.ko, the new one is > xen-tpmfront.ko.I meant the XenBus directory name. It is ''vtpm'' - if it was called ''vtpm2'' we would avoid the "older" drivers from even seeing this one.> > > >>> 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 > >>Dodgy indentation? (I saw a bunch of these) > >> > >>>- * Copyright (c) 2005, IBM Corporation > >>>- * > >>>- * Author: Stefan Berger, stefanb@us.ibm.com > >>>- * Grant table support: Mahadevan Gomathisankaran > >>Did you really remove everything these guys wrote? > >> > >>>- * This code has been derived from tools/libxc/xen/io/netif.h > >>>- * > >>>- * Copyright (c) 2003-2004, Keir Fraser > >>I guess I can buy this bit no longer being true given that you reworked > >>the whole protocol. > >> > >>Ian > >> > >> > >>_______________________________________________ > >>Xen-devel mailing list > >>Xen-devel@lists.xen.org > >>http://lists.xen.org/xen-devel > >> > >> _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Konrad Rzeszutek Wilk
2012-Dec-07 21:25 UTC
Re: [PATCH 1/4] stubdom: Change vTPM shared page ABI
> >+ snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); > >+ if ((err = xenbus_write(XBT_NIL, path, "1"))) > >+ { > >+ /* if we got an error here we should carefully remove the interface and then return */ > >+ TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > >+ free(err); > >+ remove_tpmif(tpmif); > >+ goto error_post_irq; > >+ } > >+ > My preference is still to do away with the versioning stuff since > tpm is just getting released. Its not even in linux yet so there is > no confusion. We can even merge the linux patches together and > resubmit as one if thats preferrable. Konrad, Ian, your final votes > on that?I am up for just removing the versioning stuff - and if one really wants to be fool-proof - rename the ''backend/vtpm'' to ''backend/vtpm2'' Perhaps?
On Fri, 2012-12-07 at 21:25 +0000, Konrad Rzeszutek Wilk wrote:> > >+ snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); > > >+ if ((err = xenbus_write(XBT_NIL, path, "1"))) > > >+ { > > >+ /* if we got an error here we should carefully remove the interface and then return */ > > >+ TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); > > >+ free(err); > > >+ remove_tpmif(tpmif); > > >+ goto error_post_irq; > > >+ } > > >+ > > My preference is still to do away with the versioning stuff since > > tpm is just getting released.It is present in the 2.6.18-xen tree and has made its way into distros, at least SLES11.> Its not even in linux yet so there is > > no confusion. We can even merge the linux patches together and > > resubmit as one if thats preferrable. Konrad, Ian, your final votes > > on that? > > I am up for just removing the versioning stuff - and if one really > wants to be fool-proof - rename the ''backend/vtpm'' to ''backend/vtpm2'' > Perhaps? >
Matthew Fioravante
2012-Dec-10 15:03 UTC
Re: [PATCH 1/4] stubdom: Change vTPM shared page ABI
Ok why don''t we go with backend/vtpm2. That seems to be the less intrusive approach. On 12/10/2012 04:58 AM, Ian Campbell wrote:> On Fri, 2012-12-07 at 21:25 +0000, Konrad Rzeszutek Wilk wrote: >>>> + snprintf(path, 512, "backend/vtpm/%u/%u/feature-protocol-v2", (unsigned int) tpmif->domid, tpmif->handle); >>>> + if ((err = xenbus_write(XBT_NIL, path, "1"))) >>>> + { >>>> + /* if we got an error here we should carefully remove the interface and then return */ >>>> + TPMBACK_ERR("Unable to write feature-protocol-v2 node: %s\n", err); >>>> + free(err); >>>> + remove_tpmif(tpmif); >>>> + goto error_post_irq; >>>> + } >>>> + >>> My preference is still to do away with the versioning stuff since >>> tpm is just getting released. > It is present in the 2.6.18-xen tree and has made its way into distros, > at least SLES11. > >> Its not even in linux yet so there is >>> no confusion. We can even merge the linux patches together and >>> resubmit as one if thats preferrable. Konrad, Ian, your final votes >>> on that? >> I am up for just removing the versioning stuff - and if one really >> wants to be fool-proof - rename the ''backend/vtpm'' to ''backend/vtpm2'' >> Perhaps? >> >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Reasonably Related Threads
- [PATCH] linux-2.6.18/backends: use xenbus_be.ko interfaces instead of open-coding them
- xenpaging fixes for kernel and hypervisor
- [PATCH 0 of 2] Paging support updates for XCP dom0
- vTPM NVM, loadkey and trousers questions
- PATCH [base vtpm and libxl patches 3/6] Fix bugs in vtpm hotplug scripts