This patch queue goes on top of Matthew Fioravante''s [VTPM v7 0/8] series. The xenbus device name has changed to "vtpm2", and some documentation has been added about PCRs (those extended by pv-grub and those added in locality 5). A new Linux patch is also needed, and will be posted as a reply to this email; the layout of the shared page has changed slightly (length field changed from uint16_t to uint32_t). Patches have been reordered a bit in an attempt to have the series make the most sense possible if partially applied. Patch #8 still breaks automatic vTPM domain shutdown, so only applying #1-6 would be useful if we would like that feature to continue working while the libxl-based shutdown request is not finished. Patch 10-13 are new here; they allow localities to be restricted for certain domains. This is an important security feature if multiple domains are accessing the same vTPM, and without this feature the locality 5 PCRs introduced by #7 are no different from the lower 24 defined in the TPM specification. Patch 14 is a build cleanup that fixes the third consecutive build without an intervening "make clean" when NEWLIB_STAMPFILE is touched after gmp is extracted. New ABI patches: [PATCH 01/14] mini-os/tpm{back,front}: Change shared page ABI [PATCH 02/14] stubdom/vtpm: correct the buffer size returned by [PATCH 03/14] stubdom/vtpm: Support locality field New vTPM features: [PATCH 04/14] stubdom/vtpm: Allow repoen of closed devices [PATCH 05/14] stubdom/vtpm: make state save operation atomic [PATCH 06/14] stubdom/grub: send kernel measurements to vTPM Support for multiple client domains distinguished by locality: [PATCH 07/14] stubdom/vtpm: Add locality-5 PCRs [PATCH 08/14] stubdom/vtpm: support multiple backends [PATCH 09/14] stubdom/vtpm: Add PCR pass-through to hardware TPM [PATCH 10/14] mini-os/tpmback: set up callbacks before enumeration [PATCH 11/14] mini-os/tpmback: Replace UUID field with opaque [PATCH 12/14] mini-os/tpmback: add tpmback_get_peercontext [PATCH 13/14] stubdom/vtpm: constrain locality by XSM label Other: [PATCH 14/14] stubdom/Makefile: Fix gmp extract rule
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 01/14] mini-os/tpm{back, front}: Change 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. The vtpm xenbus device has been renamed to "vtpm2" to avoid conflicts with existing (xen-patched) kernels supporting the old interface. While the contents of the shared page have been defined to allow packets larger than a single page (actually 4088 bytes) by allowing the client to add extra grant references, the mapping of these extra references has not been implemented; a feature node in xenstore may be used in the future to indicate full support for the multi-page protocol. Most uses of the TPM should not require this feature. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/include/tpmback.h | 1 + extras/mini-os/include/tpmfront.h | 7 +- extras/mini-os/tpmback.c | 135 ++++++++++++++------------------------ extras/mini-os/tpmfront.c | 119 +++++++++++++-------------------- tools/libxl/libxl.c | 8 +-- xen/include/public/io/tpmif.h | 45 +++---------- 6 files changed, 114 insertions(+), 201 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..50f8a5d 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -86,10 +86,7 @@ struct tpmif { evtchn_port_t evtchn; /* Shared page */ - tpmif_tx_interface_t* tx; - - /* pointer to TPMIF_RX_RING_SIZE pages */ - void** pages; + vtpm_shared_page_t *page; enum xenbus_state state; enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; @@ -312,7 +309,6 @@ int insert_tpmif(tpmif_t* tpmif) remove_tpmif(tpmif); goto error_post_irq; } - return 0; error: local_irq_restore(flags); @@ -336,7 +332,7 @@ int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) if (tpmif->state == state) return 0; - snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/state", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_read(XBT_NIL, path, &value))) { TPMBACK_ERR("Unable to read backend state %s, error was %s\n", path, err); @@ -362,7 +358,7 @@ int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) } /*update xenstore*/ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) { TPMBACK_ERR("Error writing to xenstore %s, error was %s new state=%d\n", path, err, state); free(err); @@ -386,8 +382,7 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) tpmif->fe_state_path = NULL; tpmif->state = XenbusStateInitialising; tpmif->status = DISCONNECTED; - tpmif->tx = NULL; - tpmif->pages = NULL; + tpmif->page = NULL; tpmif->flags = 0; memset(tpmif->uuid, 0, sizeof(tpmif->uuid)); return tpmif; @@ -395,9 +390,6 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) void __free_tpmif(tpmif_t* tpmif) { - if(tpmif->pages) { - free(tpmif->pages); - } if(tpmif->fe_path) { free(tpmif->fe_path); } @@ -424,23 +416,17 @@ tpmif_t* new_tpmif(domid_t domid, unsigned int handle) tpmif = __init_tpmif(domid, handle); /* Get the uuid from xenstore */ - snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid, handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/uuid", (unsigned int) domid, handle); if((!xenbus_read_uuid(path, tpmif->uuid))) { TPMBACK_ERR("Error reading %s\n", path); 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; } - snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int) domid, handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/frontend", (unsigned int) domid, handle); if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) { TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s), Error = %s", path, err); free(err); @@ -486,7 +472,7 @@ void free_tpmif(tpmif_t* tpmif) tpmif->status = DISCONNECTING; mask_evtchn(tpmif->evtchn); - if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1)) { + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1)) { TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); } @@ -508,7 +494,7 @@ void free_tpmif(tpmif_t* tpmif) schedule(); /* Remove the old xenbus entries */ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_rm(XBT_NIL, path))) { TPMBACK_ERR("Error cleaning up xenbus entries path=%s error=%s\n", path, err); free(err); @@ -529,9 +515,10 @@ void free_tpmif(tpmif_t* tpmif) void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *data) { tpmif_t* tpmif = (tpmif_t*) data; - tpmif_tx_request_t* tx = &tpmif->tx->ring[0].req; - /* Throw away 0 size events, these can trigger from event channel unmasking */ - if(tx->size == 0) + vtpm_shared_page_t* pg = tpmif->page; + + /* Only pay attention if the request is ready */ + if (pg->state == 0) return; TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); @@ -585,11 +572,10 @@ int connect_fe(tpmif_t* tpmif) free(value); domid = tpmif->domid; - if((tpmif->tx = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { + if((tpmif->page = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); return -1; } - memset(tpmif->tx, 0, PAGE_SIZE); /*Bind the event channel */ if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tpmif, &tpmif->evtchn))) @@ -600,7 +586,7 @@ int connect_fe(tpmif_t* tpmif) unmask_evtchn(tpmif->evtchn); /* Write the ready flag and change status to connected */ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) { TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n", (unsigned int) tpmif->domid, tpmif->handle); free(err); @@ -618,7 +604,7 @@ error_post_evtchn: mask_evtchn(tpmif->evtchn); unbind_evtchn(tpmif->evtchn); error_post_map: - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1); + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1); return -1; } @@ -670,8 +656,8 @@ static int parse_eventstr(const char* evstr, domid_t* domid, unsigned int* handl char* value; unsigned int udomid = 0; tpmif_t* tpmif; - /* First check for new frontends, this occurs when /backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to fail on the last %s */ - if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd) == 2) { + /* First check for new frontends, this occurs when /backend/vtpm2/<domid>/<handle> gets created. Note we what the sscanf to fail on the last %s */ + if (sscanf(evstr, "backend/vtpm2/%u/%u/%40s", &udomid, handle, cmd) == 2) { *domid = udomid; /* Make sure the entry exists, if this event triggers because the entry dissapeared then ignore it */ if((err = xenbus_read(XBT_NIL, evstr, &value))) { @@ -685,7 +671,7 @@ static int parse_eventstr(const char* evstr, domid_t* domid, unsigned int* handl return EV_NONE; } return EV_NEWFE; - } else if((ret = sscanf(evstr, "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) { + } else if((ret = sscanf(evstr, "/local/domain/%u/device/vtpm2/%u/%40s", &udomid, handle, cmd)) == 3) { *domid = udomid; if (!strcmp(cmd, "state")) return EV_STCHNG; @@ -784,7 +770,7 @@ void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)) static void event_listener(void) { - const char* bepath = "backend/vtpm"; + const char* bepath = "backend/vtpm2"; char **path; char* err; @@ -874,6 +860,7 @@ void shutdown_tpmback(void) inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, unsigned char uuid[16]) { tpmcmd->domid = domid; + tpmcmd->locality = -1; tpmcmd->handle = handle; memcpy(tpmcmd->uuid, uuid, sizeof(tpmcmd->uuid)); tpmcmd->req = NULL; @@ -884,12 +871,12 @@ inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, un tpmcmd_t* get_request(tpmif_t* tpmif) { tpmcmd_t* cmd; - tpmif_tx_request_t* tx; - int offset; - int tocopy; - int i; - uint32_t domid; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG + int i; +#endif local_irq_save(flags); @@ -899,35 +886,22 @@ tpmcmd_t* get_request(tpmif_t* tpmif) { } init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); - tx = &tpmif->tx->ring[0].req; - cmd->req_len = tx->size; + shr = tpmif->page; + cmd->req_len = shr->length; + cmd->locality = shr->locality; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->req_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } /* Allocate the buffer */ if(cmd->req_len) { if((cmd->req = malloc(cmd->req_len)) == NULL) { goto error; } } - /* Copy the bits from the shared pages */ - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_READ)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->req_len - offset, PAGE_SIZE); - memcpy(&cmd->req[offset], tpmif->pages[i], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); - - } + /* Copy the bits from the shared page(s) */ + memcpy(cmd->req, offset + (uint8_t*)shr, cmd->req_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len); @@ -958,38 +932,24 @@ error: void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) { - tpmif_tx_request_t* tx; - int offset; - int i; - uint32_t domid; - int tocopy; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG +int i; +#endif local_irq_save(flags); - tx = &tpmif->tx->ring[0].req; - tx->size = cmd->resp_len; - - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_WRITE)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->resp_len - offset, PAGE_SIZE); - memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); + shr = tpmif->page; + shr->length = cmd->resp_len; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->resp_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; } + memcpy(offset + (uint8_t*)shr, cmd->resp, cmd->resp_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->resp_len); @@ -1003,6 +963,7 @@ void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) #endif /* clear the ready flag and send the event channel notice to the frontend */ tpmif_req_finished(tpmif); + shr->state = 0; notify_remote_via_evtchn(tpmif->evtchn); error: local_irq_restore(flags); diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index 0218d7f..ac9ba42 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -176,7 +176,7 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState ret = wait_for_backend_closed(&events, path); break; default: - break; + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +190,13 @@ static int tpmfront_connect(struct tpmfront_dev* dev) { char* err; /* Create shared page */ - dev->tx = (tpmif_tx_interface_t*) alloc_page(); - if(dev->tx == NULL) { + dev->page = (vtpm_shared_page_t*) alloc_page(); + if(dev->page == NULL) { TPMFRONT_ERR("Unable to allocate page for shared memory\n"); goto error; } - memset(dev->tx, 0, PAGE_SIZE); - dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->tx), 0); + memset(dev->page, 0, PAGE_SIZE); + dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->page), 0); TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref); /*Create event channel */ @@ -228,7 +228,7 @@ error_postevtchn: unbind_evtchn(dev->evtchn); error_postmap: gnttab_end_access(dev->ring_ref); - free_page(dev->tx); + free_page(dev->page); error: return -1; } @@ -240,7 +240,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) char path[512]; char* value, *err; unsigned long long ival; - int i; printk("============= Init TPM Front ================\n"); @@ -251,7 +250,7 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) dev->fd = -1; #endif - nodename = _nodename ? _nodename : "device/vtpm/0"; + nodename = _nodename ? _nodename : "device/vtpm2/0"; dev->nodename = strdup(nodename); init_waitqueue_head(&dev->waitq); @@ -289,19 +288,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) goto error; } - /* Allocate pages that will contain the messages */ - dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE); - if(dev->pages == NULL) { - goto error; - } - memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - dev->pages[i] = (void*)alloc_page(); - if(dev->pages[i] == NULL) { - goto error; - } - } - TPMFRONT_LOG("Initialization Completed successfully\n"); return dev; @@ -314,8 +300,6 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } @@ -349,27 +333,12 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) /* Wait for the backend to close and unmap shared pages, ignore any errors */ wait_for_backend_state_changed(dev, XenbusStateClosed); - /* Cleanup any shared pages */ - if(dev->pages) { - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - if(dev->pages[i]) { - tx = &dev->tx->ring[i].req; - if(tx->ref != 0) { - gnttab_end_access(tx->ref); - } - free_page(dev->pages[i]); - } - } - free(dev->pages); - } - /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); unbind_evtchn(dev->evtchn); gnttab_end_access(dev->ring_ref); - free_page(dev->tx); - + free_page(dev->page); } /* Cleanup memory usage */ @@ -387,13 +356,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) { + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG int i; - tpmif_tx_request_t* tx = NULL; +#endif /* Error Checking */ if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to send message through disconnected frontend\n"); return -1; } + shr = dev->page; #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length); @@ -407,19 +380,16 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) #endif /* Copy to shared pages now */ - for(i = 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) { - /* Share the page */ - tx = &dev->tx->ring[i].req; - tx->unused = 0; - tx->addr = virt_to_mach(dev->pages[i]); - tx->ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->pages[i]), 0); - /* Copy the bits to the page */ - tx->size = length > PAGE_SIZE ? PAGE_SIZE : length; - memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size); - - /* Update counters */ - length -= tx->size; + offset = sizeof(*shr); + if (length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Message too long for shared page\n"); + return -1; } + memcpy(offset + (uint8_t*)shr, msg, length); + shr->length = length; + barrier(); + shr->state = 1; + dev->waiting = 1; dev->resplen = 0; #ifdef HAVE_LIBC @@ -434,44 +404,41 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) } int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *length) { - tpmif_tx_request_t* tx; - int i; + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG +int i; +#endif if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to receive message from disconnected frontend\n"); return -1; } /*Wait for the response */ wait_event(dev->waitq, (!dev->waiting)); + shr = dev->page; + if (shr->state != 0) + goto quit; /* Initialize */ *msg = NULL; - *length = 0; + *length = shr->length; + offset = sizeof(*shr); - /* special case, just quit */ - tx = &dev->tx->ring[0].req; - if(tx->size == 0 ) { - goto quit; - } - /* Get the total size */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - *length += tx->size; + if (*length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Reply too long for shared page\n"); + return -1; } + /* Alloc the buffer */ if(dev->respbuf) { free(dev->respbuf); } *msg = dev->respbuf = malloc(*length); dev->resplen = *length; + /* Copy the bits */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size); - gnttab_end_access(tx->ref); - tx->ref = 0; - } + memcpy(*msg, offset + (uint8_t*)shr, *length); + #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned int) *length); for(i = 0; i < *length; ++i) { @@ -504,6 +471,14 @@ int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t* return 0; } +int tpmfront_set_locality(struct tpmfront_dev* dev, int locality) +{ + if (!dev || !dev->page) + return -1; + dev->page->locality = locality; + return 0; +} + #ifdef HAVE_LIBC #include <errno.h> int tpmfront_open(struct tpmfront_dev* dev) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 8d921bc..7af5da3 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1756,7 +1756,7 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, goto out; } l = libxl__xs_directory(gc, XBT_NULL, - GCSPRINTF("%s/device/vtpm", dompath), &nb); + GCSPRINTF("%s/device/vtpm2", dompath), &nb); if(l == NULL || nb == 0) { vtpm->devid = 0; } else { @@ -1815,7 +1815,7 @@ libxl_device_vtpm *libxl_device_vtpm_list(libxl_ctx *ctx, uint32_t domid, int *n *num = 0; - fe_path = libxl__sprintf(gc, "%s/device/vtpm", libxl__xs_get_dompath(gc, domid)); + fe_path = libxl__sprintf(gc, "%s/device/vtpm2", libxl__xs_get_dompath(gc, domid)); dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs); if(dir) { vtpms = malloc(sizeof(*vtpms) * ndirs); @@ -1830,7 +1830,7 @@ libxl_device_vtpm *libxl_device_vtpm_list(libxl_ctx *ctx, uint32_t domid, int *n vtpm->devid = atoi(*dir); tmp = libxl__xs_read(gc, XBT_NULL, - GCSPRINTF("%s/%s/backend_id", + GCSPRINTF("%s/%s/backend-id", fe_path, *dir)); vtpm->backend_domid = atoi(tmp); @@ -1863,7 +1863,7 @@ int libxl_device_vtpm_getinfo(libxl_ctx *ctx, dompath = libxl__xs_get_dompath(gc, domid); vtpminfo->devid = vtpm->devid; - vtpmpath = GCSPRINTF("%s/device/vtpm/%d", dompath, vtpminfo->devid); + vtpmpath = GCSPRINTF("%s/device/vtpm2/%d", dompath, vtpminfo->devid); vtpminfo->backend = xs_read(ctx->xsh, XBT_NULL, GCSPRINTF("%s/backend", vtpmpath), NULL); if (!vtpminfo->backend) { diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h index 02ccdab..7c96530 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 { + uint32_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 pad; -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-Dec-10 19:55 UTC
[PATCH 02/14] stubdom/vtpm: correct the buffer size returned by TPM_CAP_PROP_INPUT_BUFFER
The vtpm2 ABI supports packets of up to 4088 bytes by default; expose this property though the TPM''s interface so clients do not attempt to send larger packets. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-bufsize.patch | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 stubdom/vtpm-bufsize.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index 709b71e..12f8a6f 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -207,6 +207,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz tar xzf $< mv tpm_emulator-$(TPMEMU_VERSION) $@ patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; + patch -d $@ -p1 < vtpm-bufsize.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-bufsize.patch b/stubdom/vtpm-bufsize.patch new file mode 100644 index 0000000..9c9304c --- /dev/null +++ b/stubdom/vtpm-bufsize.patch @@ -0,0 +1,13 @@ +diff --git a/config.h.in b/config.h.in +index d16a997..8088a2a 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -27,7 +27,7 @@ + #define TPM_STORAGE_NAME "${TPM_STORAGE_NAME}" + #define TPM_DEVICE_NAME "${TPM_DEVICE_NAME}" + #define TPM_LOG_FILE "${TPM_LOG_FILE}" +-#define TPM_CMD_BUF_SIZE 4096 ++#define TPM_CMD_BUF_SIZE 4088 + + #endif /* _CONFIG_H_ */ + -- 1.7.11.7
The vTPM protocol now contains a field allowing the locality of a command to be specified; pass this to the TPM when processing a packet. While the locality is not currently checked for validity, a binding between locality and some distinguishing feature of the client domain (such as the XSM label) will need to be defined in order to properly support a multi-client vTPM. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Acked-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> --- stubdom/Makefile | 1 + stubdom/vtpm-locality.patch | 50 +++++++++++++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm.c | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 stubdom/vtpm-locality.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index 12f8a6f..fb0e5f9 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -208,6 +208,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz mv tpm_emulator-$(TPMEMU_VERSION) $@ patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; patch -d $@ -p1 < vtpm-bufsize.patch + patch -d $@ -p1 < vtpm-locality.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-locality.patch b/stubdom/vtpm-locality.patch new file mode 100644 index 0000000..8ab7dea --- /dev/null +++ b/stubdom/vtpm-locality.patch @@ -0,0 +1,50 @@ +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c +index 60bbb90..f8f7f0f 100644 +--- a/tpm/tpm_capability.c ++++ b/tpm/tpm_capability.c +@@ -949,6 +949,8 @@ static TPM_RESULT set_vendor(UINT32 subCap, BYTE *setValue, + UINT32 setValueSize, BOOL ownerAuth, + BOOL deactivated, BOOL disabled) + { ++ if (tpmData.stany.flags.localityModifier != 8) ++ return TPM_BAD_PARAMETER; + /* set the capability area with the specified data, on failure + deactivate the TPM */ + switch (subCap) { +diff --git a/tpm/tpm_cmd_handler.c b/tpm/tpm_cmd_handler.c +index 288d1ce..9e1cfb4 100644 +--- a/tpm/tpm_cmd_handler.c ++++ b/tpm/tpm_cmd_handler.c +@@ -4132,7 +4132,7 @@ void tpm_emulator_shutdown() + tpm_extern_release(); + } + +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size) ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality) + { + TPM_REQUEST req; + TPM_RESPONSE rsp; +@@ -4140,7 +4140,9 @@ int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint3 + UINT32 len; + BOOL free_out; + +- debug("tpm_handle_command()"); ++ debug("tpm_handle_command(%d)", locality); ++ if (locality != -1) ++ tpmData.stany.flags.localityModifier = locality; + + /* we need the whole packet at once, otherwise unmarshalling will fail */ + if (tpm_unmarshal_TPM_REQUEST((uint8_t**)&in, &in_size, &req) != 0) { +diff --git a/tpm/tpm_emulator.h b/tpm/tpm_emulator.h +index eed749e..4c228bd 100644 +--- a/tpm/tpm_emulator.h ++++ b/tpm/tpm_emulator.h +@@ -59,7 +59,7 @@ void tpm_emulator_shutdown(void); + * its usage. In case of an error, all internally allocated memory + * is released and the the state of out and out_size is unspecified. + */ +-int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size); ++int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size, int locality); + + #endif /* _TPM_EMULATOR_H_ */ + diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index 71aef78..eb7912f 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -183,7 +183,7 @@ static void main_loop(void) { } /* If not disabled, do the command */ else { - if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len)) != 0) { + if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len, tpmcmd->locality)) != 0) { error("tpm_handle_command() failed"); create_error_response(tpmcmd, TPM_FAIL); } -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 04/14] stubdom/vtpm: Allow repoen of closed devices
Allow the vtpm device to be disconnected and reconnected so that a bootloader (like pv-grub) can submit measurements and return the vtpm device to its initial state before booting the target kernel. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/tpmback.c | 23 ++++++++++++++++++++++- extras/mini-os/tpmfront.c | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 50f8a5d..69a7f2d 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -608,6 +608,24 @@ error_post_map: return -1; } +static void disconnect_fe(tpmif_t* tpmif) +{ + if (tpmif->status == CONNECTED) { + tpmif->status = DISCONNECTING; + mask_evtchn(tpmif->evtchn); + + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1)) { + TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); + } + + unbind_evtchn(tpmif->evtchn); + } + tpmif->status = DISCONNECTED; + tpmif_change_state(tpmif, XenbusStateInitWait); + + TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int) tpmif->domid, tpmif->handle); +} + static int frontend_changed(tpmif_t* tpmif) { int state = xenbus_read_integer(tpmif->fe_state_path); @@ -634,8 +652,11 @@ static int frontend_changed(tpmif_t* tpmif) tpmif_change_state(tpmif, XenbusStateClosing); break; - case XenbusStateUnknown: /* keep it here */ case XenbusStateClosed: + disconnect_fe(tpmif); + break; + + case XenbusStateUnknown: /* keep it here */ free_tpmif(tpmif); break; diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index ac9ba42..1ef51cf 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -146,6 +146,9 @@ static int wait_for_backend_closed(xenbus_event_queue* events, char* path) case XenbusStateClosed: TPMFRONT_LOG("Backend Closed\n"); return 0; + case XenbusStateInitWait: + TPMFRONT_LOG("Backend Closed (waiting for reconnect)\n"); + return 0; default: xenbus_wait_for_watch(events); } @@ -306,10 +309,10 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) TPMFRONT_LOG("Shutting down tpmfront\n"); /* disconnect */ if(dev->state == XenbusStateConnected) { - dev->state = XenbusStateClosing; - //FIXME: Transaction for this? /* Tell backend we are closing */ + dev->state = XenbusStateClosing; if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename, err); free(err); } @@ -333,6 +336,13 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) /* Wait for the backend to close and unmap shared pages, ignore any errors */ wait_for_backend_state_changed(dev, XenbusStateClosed); + /* Prepare for a later reopen (possibly by a kexec''d kernel) */ + dev->state = XenbusStateInitialising; + if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename, err); + free(err); + } + /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); unbind_evtchn(dev->evtchn); -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 05/14] stubdom/vtpm: make state save operation atomic
This changes the save format of the vtpm stubdom to include two copies of the saved data: one active, and one inactive. When saving the state, data is written to the inactive slot before updating the key and hash saved with the TPM Manager, which determines the active slot when the vTPM starts up. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/vtpm/vtpmblk.c | 74 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c index b343bd8..fe529ab 100644 --- a/stubdom/vtpm/vtpmblk.c +++ b/stubdom/vtpm/vtpmblk.c @@ -26,6 +26,7 @@ static struct blkfront_dev* blkdev = NULL; static int blkfront_fd = -1; +static uint64_t slot_size = 0; int init_vtpmblk(struct tpmfront_dev* tpmfront_dev) { @@ -45,6 +46,8 @@ int init_vtpmblk(struct tpmfront_dev* tpmfront_dev) goto error; } + slot_size = blkinfo.sectors * blkinfo.sector_size / 2; + return 0; error: shutdown_blkfront(blkdev); @@ -59,15 +62,20 @@ void shutdown_vtpmblk(void) blkdev = NULL; } -int write_vtpmblk_raw(uint8_t *data, size_t data_length) +static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot) { int rc; uint32_t lenbuf; - debug("Begin Write data=%p len=%u", data, data_length); + debug("Begin Write data=%p len=%u slot=%u ssize=%u", data, data_length, slot, slot_size); + + if (data_length > slot_size - 4) { + error("vtpm data cannot fit in data slot (%d/%d).", data_length, slot_size - 4); + return -1; + } lenbuf = cpu_to_be32((uint32_t)data_length); - lseek(blkfront_fd, 0, SEEK_SET); + lseek(blkfront_fd, slot * slot_size, SEEK_SET); if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { error("write(length) failed! error was %s", strerror(errno)); return -1; @@ -82,12 +90,12 @@ int write_vtpmblk_raw(uint8_t *data, size_t data_length) return 0; } -int read_vtpmblk_raw(uint8_t **data, size_t *data_length) +static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot) { int rc; uint32_t lenbuf; - lseek(blkfront_fd, 0, SEEK_SET); + lseek(blkfront_fd, slot * slot_size, SEEK_SET); if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { error("read(length) failed! error was %s", strerror(errno)); return -1; @@ -97,6 +105,10 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length) error("read 0 data_length for NVM"); return -1; } + if(*data_length > slot_size - 4) { + error("read invalid data_length for NVM"); + return -1; + } *data = tpm_malloc(*data_length); if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) { @@ -104,7 +116,7 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length) return -1; } - info("Read %u bytes from NVM persistent storage", *data_length); + info("Read %u bytes from NVM persistent storage (slot %d)", *data_length, slot); return 0; } @@ -221,6 +233,9 @@ egress: return rc; } +/* Current active state slot, or -1 if no valid saved state exists */ +static int active_slot = -1; + int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { int rc; uint8_t* cipher = NULL; @@ -228,12 +243,17 @@ int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_ uint8_t hashkey[HASHKEYSZ]; uint8_t* symkey = hashkey + HASHSZ; + /* Switch to the other slot. Note that in a new vTPM, the read will not + * succeed, so active_slot will be -1 and we will write to slot 0. + */ + active_slot = !active_slot; + /* Encrypt the data */ if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) { goto abort_egress; } /* Write to disk */ - if((rc = write_vtpmblk_raw(cipher, cipher_len))) { + if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) { goto abort_egress; } /* Get sha1 hash of data */ @@ -256,7 +276,8 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data size_t cipher_len = 0; size_t keysize; uint8_t* hashkey = NULL; - uint8_t hash[HASHSZ]; + uint8_t hash0[HASHSZ]; + uint8_t hash1[HASHSZ]; uint8_t* symkey; /* Retreive the hash and the key from the manager */ @@ -270,14 +291,32 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data } symkey = hashkey + HASHSZ; - /* Read from disk now */ - if((rc = read_vtpmblk_raw(&cipher, &cipher_len))) { + active_slot = 0; + debug("Reading slot 0 from disk\n"); + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) { goto abort_egress; } /* Compute the hash of the cipher text and compare */ - sha1(cipher, cipher_len, hash); - if(memcmp(hash, hashkey, HASHSZ)) { + sha1(cipher, cipher_len, hash0); + if(!memcmp(hash0, hashkey, HASHSZ)) + goto valid; + + free(cipher); + cipher = NULL; + + active_slot = 1; + debug("Reading slot 1 from disk (offset=%u)\n", slot_size); + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) { + goto abort_egress; + } + + /* Compute the hash of the cipher text and compare */ + sha1(cipher, cipher_len, hash1); + if(!memcmp(hash1, hashkey, HASHSZ)) + goto valid; + + { int i; error("NVM Storage Checksum failed!"); printf("Expected: "); @@ -285,14 +324,20 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data printf("%02hhX ", hashkey[i]); } printf("\n"); - printf("Actual: "); + printf("Slot 0: "); + for(i = 0; i < HASHSZ; ++i) { + printf("%02hhX ", hash0[i]); + } + printf("\n"); + printf("Slot 1: "); for(i = 0; i < HASHSZ; ++i) { - printf("%02hhX ", hash[i]); + printf("%02hhX ", hash1[i]); } printf("\n"); rc = -1; goto abort_egress; } +valid: /* Decrypt the blob */ if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) { @@ -300,6 +345,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data } goto egress; abort_egress: + active_slot = -1; egress: free(cipher); free(hashkey); -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 06/14] 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> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Acked-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> --- docs/misc/vtpm.txt | 41 ++++++++++++++++++++++++++++--------- stubdom/Makefile | 2 +- stubdom/grub/Makefile | 1 + stubdom/grub/kexec.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ stubdom/grub/minios.cfg | 1 + 5 files changed, 89 insertions(+), 10 deletions(-) diff --git a/docs/misc/vtpm.txt b/docs/misc/vtpm.txt index fc6029a..6ea27bd 100644 --- a/docs/misc/vtpm.txt +++ b/docs/misc/vtpm.txt @@ -1,7 +1,7 @@ Copyright (c) 2010-2012 United States Government, as represented by the Secretary of Defense. All rights reserved. November 12 2012 -Authors: Matthew Fioravante (JHUAPL), +Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA) This document describes the virtual Trusted Platform Module (vTPM) subsystem for Xen. The reader is assumed to have familiarity with building and installing @@ -15,7 +15,8 @@ operating system (a DomU). This allows programs to interact with a TPM in a virtual system the same way they interact with a TPM on the physical system. Each guest gets its own unique, emulated, software TPM. However, each of the vTPM''s secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain, which -seals the secrets to the Physical TPM. Thus, the vTPM subsystem extends the +seals the secrets to the Physical TPM. If the process of creating each of these +domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each major component of vTPM is implemented as a separate domain, providing secure separation guaranteed by the hypervisor. The vTPM domains are implemented in @@ -119,14 +120,17 @@ the stubdom tree. Compiling the LINUX dom0 kernel: -------------------------------- -The Linux dom0 kernel has no special prerequisites. +The Linux dom0 kernel should not try accessing the TPM while the vTPM +Manager domain is accessing it; the simplest way to accomplish this is +to ensure the kernel is compiled without a driver for the TPM, or avoid +loading the driver by blacklisting the module. Compiling the LINUX domU kernel: -------------------------------- -The domU kernel used by domains with vtpms must -include the xen-tpmfront.ko driver. It can be built -directly into the kernel or as a module. +The domU kernel used by domains with vtpms must include the xen-tpmfront.ko +driver. It can be built directly into the kernel or as a module; however, some +features such as IMA require the TPM to be built in to the kernel. CONFIG_TCG_TPM=y CONFIG_TCG_XEN=y @@ -160,9 +164,10 @@ disk=["file:/var/vtpmmgrdom.img,hda,w"] name="vtpmmgrdom" iomem=["fed40,5"] -The iomem line tells xl to allow access to the TPM -IO memory pages, which are 5 pages that start at -0xfed40000. +The iomem line tells xl to allow access to all of the TPM IO memory +pages, which are 5 pages (one per locality) that start at 0xfed40000. By +default, the TPM manager uses locality 0 (so only the page at 0xfed40 is +needed); this can be changed on the domain''s command line. Starting and stopping the manager: ---------------------------------- @@ -285,6 +290,24 @@ On guest: You may wish to write a script to start your vtpm and guest together. ------------------------------ +INTEGRATION WITH PV-GRUB +------------------------------ + +The vTPM currently starts up with all PCRs set to their default values (all +zeros for the lower 16). This means that any decisions about the +trustworthiness of the created domain must be made based on the environment that +created the vTPM and the domU; for example, a system that only constructs images +using a trusted configuration and guest kernel be able to provide guarantees +about the guests and any measurements done that kernel (such as the IMA TCB +log). Guests wishing to use a custom kernel in such a secure environment are +often started using the pv-grub bootloader as the kernel, which then can load +the untrusted kernel without needing to parse an untrusted filesystem and kernel +in dom0. If the pv-grub stub domain succeeds in connecting to a vTPM, it will +extend the hash of the kernel that it boots into PCR #4, and will extend the +command line and initrd into PCR #5 before booting so that a domU booted in this +way can attest to its early boot state. + +------------------------------ MORE INFORMATION ------------------------------ diff --git a/stubdom/Makefile b/stubdom/Makefile index fb0e5f9..95e10f3 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -398,7 +398,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar.gz done .PHONY: grub -grub: grub-upstream $(CROSS_ROOT) +grub: cross-polarssl grub-upstream $(CROSS_ROOT) mkdir -p grub-$(XEN_TARGET_ARCH) CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) DESTDIR= -C $@ OBJ_DIR=$(CURDIR)/grub-$(XEN_TARGET_ARCH) diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile index d6e3a1e..6bd2c4c 100644 --- a/stubdom/grub/Makefile +++ b/stubdom/grub/Makefile @@ -60,6 +60,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) $(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__ PV_GRUB_SOURCES = kexec.c mini-os.c +PV_GRUB_SOURCES += ../polarssl-$(XEN_TARGET_ARCH)/library/sha1.o SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES) diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c index b21c91a..cef357e 100644 --- a/stubdom/grub/kexec.c +++ b/stubdom/grub/kexec.c @@ -28,7 +28,9 @@ #include <blkfront.h> #include <netfront.h> #include <fbfront.h> +#include <tpmfront.h> #include <shared.h> +#include <byteswap.h> #include "mini-os.h" @@ -54,6 +56,22 @@ static unsigned long allocated; int pin_table(xc_interface *xc_handle, unsigned int type, unsigned long mfn, domid_t dom); +#define TPM_TAG_RQU_COMMAND 0xC1 +#define TPM_ORD_Extend 20 + +struct pcr_extend_cmd { + uint16_t tag; + uint32_t size; + uint32_t ord; + + uint32_t pcr; + unsigned char hash[20]; +} __attribute__((packed)); + +/* Not imported from polarssl''s header since the prototype unhelpfully defines + * the input as unsigned char, which causes pointer type mismatches */ +void sha1(const void *input, size_t ilen, unsigned char output[20]); + /* We need mfn to appear as target_pfn, so exchange with the MFN there */ static void do_exchange(struct xc_dom_image *dom, xen_pfn_t target_pfn, xen_pfn_t source_mfn) { @@ -117,6 +135,40 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) return 0; } +static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline) +{ + struct tpmfront_dev* tpm = init_tpmfront(NULL); + uint8_t *resp; + size_t resplen = 0; + struct pcr_extend_cmd cmd; + + /* If all guests have access to a vTPM, it may be useful to replace this + * with ASSERT(tpm) to prevent configuration errors from allowing a guest + * to boot without a TPM (or with a TPM that has not been sent any + * measurements, which could allow forging the measurements). + */ + if (!tpm) + return; + + cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND); + cmd.size = bswap_32(sizeof(cmd)); + cmd.ord = bswap_32(TPM_ORD_Extend); + cmd.pcr = bswap_32(4); // PCR #4 for kernel + sha1(dom->kernel_blob, dom->kernel_size, cmd.hash); + + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = bswap_32(5); // PCR #5 for cmdline + sha1(cmdline, strlen(cmdline), cmd.hash); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + cmd.pcr = bswap_32(5); // PCR #5 for initrd + sha1(dom->ramdisk_blob, dom->ramdisk_size, cmd.hash); + tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen); + + shutdown_tpmfront(tpm); +} + void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) { struct xc_dom_image *dom; @@ -151,6 +203,8 @@ void kexec(void *kernel, long kernel_size, void *module, long module_size, char dom->console_evtchn = start_info.console.domU.evtchn; dom->xenstore_evtchn = start_info.store_evtchn; + tpm_hash2pcr(dom, cmdline); + if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) { grub_printf("xc_dom_boot_xen_init returned %d\n", rc); errnum = ERR_BOOT_FAILURE; diff --git a/stubdom/grub/minios.cfg b/stubdom/grub/minios.cfg index 40cfa68..8df4909 100644 --- a/stubdom/grub/minios.cfg +++ b/stubdom/grub/minios.cfg @@ -1,2 +1,3 @@ CONFIG_START_NETWORK=n CONFIG_SPARSE_BSS=n +CONFIG_TPMFRONT=y -- 1.7.11.7
This defines new PCRs (24-31) that are restricted to locality 5, which can be used by an agent outside a domain to record information about its measurements and activity. These PCRs cannot be initialized from the hardware TPM (since most hardware TPMs do not define PCR 24+). This definition may need to be changed in the future, as the TCG''s VTPM working group is working to define the meaning of PCRs above 23 on a vTPM; the existing PC-client specification allows these PCRs to be implementation-defined. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-locality5-pcrs.patch | 33 +++++++++++++++++++++++++++++++++ stubdom/vtpm/README | 15 ++++++++++++++- stubdom/vtpm/vtpm.c | 8 ++++---- stubdom/vtpm/vtpm_pcrs.h | 6 +++--- 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 stubdom/vtpm-locality5-pcrs.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index 95e10f3..a657fd2 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -209,6 +209,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz patch -d $@ -p1 < tpmemu-$(TPMEMU_VERSION).patch; patch -d $@ -p1 < vtpm-bufsize.patch patch -d $@ -p1 < vtpm-locality.patch + patch -d $@ -p1 < vtpm-locality5-pcrs.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-locality5-pcrs.patch b/stubdom/vtpm-locality5-pcrs.patch new file mode 100644 index 0000000..f697035 --- /dev/null +++ b/stubdom/vtpm-locality5-pcrs.patch @@ -0,0 +1,33 @@ +diff --git a/tpm/tpm_data.c b/tpm/tpm_data.c +index 50c9697..d8cac09 100644 +--- a/tpm/tpm_data.c ++++ b/tpm/tpm_data.c +@@ -151,9 +151,12 @@ void tpm_init_data(void) + init_pcr_attr(22, TRUE, 0x04, 0x04); + init_pcr_attr(23, TRUE, 0x1f, 0x1f); + } +- for (i = 24; i < TPM_NUM_PCR; i++) { +- init_pcr_attr(i, TRUE, 0x00, 0x00); +- } ++ for (i = 24; i < 28 && i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, FALSE, 0x00, 0x20); ++ for (i = 28; i < 32 && i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, TRUE, 0x20, 0x20); ++ for (i = 32; i < TPM_NUM_PCR; i++) ++ init_pcr_attr(i, FALSE, 0x00, 0xC0); + if (tpmConf & TPM_CONF_GENERATE_EK) { + /* generate a new endorsement key */ + tpm_rsa_generate_key(&tpmData.permanent.data.endorsementKey, 2048); +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h +index f746c05..08cef1e 100644 +--- a/tpm/tpm_structures.h ++++ b/tpm/tpm_structures.h +@@ -676,7 +676,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { + /* + * Number of PCRs of the TPM (must be a multiple of eight) + */ +-#define TPM_NUM_PCR 24 ++#define TPM_NUM_PCR 32 + + /* + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) diff --git a/stubdom/vtpm/README b/stubdom/vtpm/README index 11bdacb..b0bd8f9 100644 --- a/stubdom/vtpm/README +++ b/stubdom/vtpm/README @@ -1,7 +1,7 @@ Copyright (c) 2010-2012 United States Government, as represented by the Secretary of Defense. All rights reserved. November 12 2012 -Authors: Matthew Fioravante (JHUAPL), +Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA) This document describes the operation and command line interface of vtpm-stubdom. See docs/misc/vtpm.txt for details on the @@ -68,6 +68,19 @@ hwinitpcr=<PCRSPEC>: Initialize the virtual Platform Configuration Registers will copy pcrs 5, 12, 13, 14, 15, and 16. ------------------------------ +VIRTUAL-TPM SPECIFIC FEATURES +------------------------------ + +The virtual TPM emulator provides some extensions to the TPM specification that +are useful in a virtualized environment. The featues added to the emulator are: + + * Support for specifying localities beyond the standard 0-4 + * Extended PCRs 24-31 that can only be extended by locality 5 + +Locality 5 is intended for use by a measurement agent running outside the +primary domain using the VM. + +------------------------------ REFERENCES ------------------------------ diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index eb7912f..aaf1a24 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -253,18 +253,18 @@ int parse_cmd_line(int argc, char** argv) opt_args.hwinitpcrs = VTPM_PCRNONE; } else if(sscanf(pch, "%u", &v1) == 1) { //Set one - if(v1 >= TPM_NUM_PCR) { + if(v1 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } opt_args.hwinitpcrs |= (1 << v1); } else if(sscanf(pch, "%u-%u", &v1, &v2) == 2) { //Set range - if(v1 >= TPM_NUM_PCR) { + if(v1 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } - if(v2 >= TPM_NUM_PCR) { + if(v2 >= VTPM_NUMPCRS) { error("hwinitpcr error: Invalid PCR index %u", v1); return -1; } @@ -312,7 +312,7 @@ int parse_cmd_line(int argc, char** argv) pcrstr[0] = ''\0''; info("The following PCRs will be initialized with values from the hardware TPM:"); - for(unsigned int i = 0; i < TPM_NUM_PCR; ++i) { + for(unsigned int i = 0; i < VTPM_NUMPCRS; ++i) { if(opt_args.hwinitpcrs & (1 << i)) { ptr += sprintf(ptr, "%u, ", i); } diff --git a/stubdom/vtpm/vtpm_pcrs.h b/stubdom/vtpm/vtpm_pcrs.h index 11835f9..bd9068c 100644 --- a/stubdom/vtpm/vtpm_pcrs.h +++ b/stubdom/vtpm/vtpm_pcrs.h @@ -40,11 +40,11 @@ #define VTPM_PCR22 1 << 22 #define VTPM_PCR23 1 << 23 -#define VTPM_PCRALL (1 << TPM_NUM_PCR) - 1 -#define VTPM_PCRNONE 0 - #define VTPM_NUMPCRS 24 +#define VTPM_PCRALL (1 << VTPM_NUMPCRS) - 1 +#define VTPM_PCRNONE 0 + struct tpmfront_dev; TPM_RESULT vtpm_initialize_hw_pcrs(struct tpmfront_dev* tpmfront_dev, unsigned long pcrs); -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 08/14] stubdom/vtpm: support multiple backends
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/vtpm/vtpm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index aaf1a24..d576c8f 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -141,8 +141,6 @@ int check_ordinal(tpmcmd_t* tpmcmd) { static void main_loop(void) { tpmcmd_t* tpmcmd = NULL; - domid_t domid; /* Domid of frontend */ - unsigned int handle; /* handle of frontend */ int res = -1; info("VTPM Initializing\n"); @@ -162,15 +160,7 @@ static void main_loop(void) { goto abort_postpcrs; } - /* Wait for the frontend domain to connect */ - info("Waiting for frontend domain to connect.."); - if(tpmback_wait_for_frontend_connect(&domid, &handle) == 0) { - info("VTPM attached to Frontend %u/%u", (unsigned int) domid, handle); - } else { - error("Unable to attach to a frontend"); - } - - tpmcmd = tpmback_req(domid, handle); + tpmcmd = tpmback_req_any(); while(tpmcmd) { /* Handle the request */ if(tpmcmd->req_len) { @@ -194,7 +184,7 @@ static void main_loop(void) { tpmback_resp(tpmcmd); /* Wait for the next request */ - tpmcmd = tpmback_req(domid, handle); + tpmcmd = tpmback_req_any(); } -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 09/14] stubdom/vtpm: Add PCR pass-through to hardware TPM
This allows the hardware TPM''s PCRs to be accessed from a vTPM for debugging and as a simple alternative to a deep quote in situations where the integrity of the vTPM''s own TCB is not in question. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 stubdom/vtpm-pcr-passthrough.patch diff --git a/stubdom/Makefile b/stubdom/Makefile index a657fd2..053fe18 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -210,6 +210,7 @@ tpm_emulator-$(XEN_TARGET_ARCH): tpm_emulator-$(TPMEMU_VERSION).tar.gz patch -d $@ -p1 < vtpm-bufsize.patch patch -d $@ -p1 < vtpm-locality.patch patch -d $@ -p1 < vtpm-locality5-pcrs.patch + patch -d $@ -p1 < vtpm-pcr-passthrough.patch mkdir $@/build cd $@/build; $(CMAKE) .. -DCMAKE_C_COMPILER=${CC} -DCMAKE_C_FLAGS="-std=c99 -DTPM_NO_EXTERN $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-declaration-after-statement" touch $@ diff --git a/stubdom/vtpm-pcr-passthrough.patch b/stubdom/vtpm-pcr-passthrough.patch new file mode 100644 index 0000000..4e898a5 --- /dev/null +++ b/stubdom/vtpm-pcr-passthrough.patch @@ -0,0 +1,73 @@ +diff --git a/tpm/tpm_capability.c b/tpm/tpm_capability.c +index f8f7f0f..885af52 100644 +--- a/tpm/tpm_capability.c ++++ b/tpm/tpm_capability.c +@@ -72,7 +72,7 @@ static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, + switch (property) { + case TPM_CAP_PROP_PCR: + debug("[TPM_CAP_PROP_PCR]"); +- return return_UINT32(respSize, resp, TPM_NUM_PCR); ++ return return_UINT32(respSize, resp, TPM_NUM_PCR_V); + + case TPM_CAP_PROP_DIR: + debug("[TPM_CAP_PROP_DIR]"); +diff --git a/tpm/tpm_emulator_extern.h b/tpm/tpm_emulator_extern.h +index 36a32dd..77ed595 100644 +--- a/tpm/tpm_emulator_extern.h ++++ b/tpm/tpm_emulator_extern.h +@@ -56,6 +56,7 @@ void (*tpm_free)(/*const*/ void *ptr); + /* random numbers */ + + void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); ++void tpm_get_extern_pcr(int index, void *buf); + + /* usec since last call */ + +diff --git a/tpm/tpm_integrity.c b/tpm/tpm_integrity.c +index 66ece83..f3c4196 100644 +--- a/tpm/tpm_integrity.c ++++ b/tpm/tpm_integrity.c +@@ -56,8 +56,11 @@ TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, + TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) + { + info("TPM_PCRRead()"); +- if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; +- memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); ++ if (pcrIndex >= TPM_NUM_PCR_V) return TPM_BADINDEX; ++ if (pcrIndex >= TPM_NUM_PCR) ++ tpm_get_extern_pcr(pcrIndex - TPM_NUM_PCR, outDigest); ++ else ++ memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); + return TPM_SUCCESS; + } + +@@ -138,12 +141,15 @@ TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, + BYTE *buf, *ptr; + info("tpm_compute_pcr_digest()"); + /* create PCR composite */ +- if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR ++ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR_V + || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; + for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { + /* is PCR number i selected ? */ + if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { +- memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); ++ if (i >= TPM_NUM_PCR) ++ tpm_get_extern_pcr(i - TPM_NUM_PCR, &comp.pcrValue[j++]); ++ else ++ memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); + } + } + memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); +diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h +index 08cef1e..8c97fc5 100644 +--- a/tpm/tpm_structures.h ++++ b/tpm/tpm_structures.h +@@ -677,6 +677,7 @@ typedef struct tdTPM_CMK_MA_APPROVAL { + * Number of PCRs of the TPM (must be a multiple of eight) + */ + #define TPM_NUM_PCR 32 ++#define TPM_NUM_PCR_V (TPM_NUM_PCR + 24) + + /* + * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c index 7eae98b..ed058fb 100644 --- a/stubdom/vtpm/vtpm_cmd.c +++ b/stubdom/vtpm/vtpm_cmd.c @@ -134,6 +134,44 @@ egress: } +extern struct tpmfront_dev* tpmfront_dev; +void tpm_get_extern_pcr(int index, void *buf) { + TPM_RESULT status = TPM_SUCCESS; + uint8_t* cmdbuf, *resp, *bptr; + size_t resplen = 0; + UINT32 len; + + /*Ask the real tpm for the PCR value */ + TPM_TAG tag = TPM_TAG_RQU_COMMAND; + UINT32 size; + TPM_COMMAND_CODE ord = TPM_ORD_PCRRead; + len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32); + + /*Create the raw tpm command */ + bptr = cmdbuf = malloc(size); + TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord)); + TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, index)); + + /* Send cmd, wait for response */ + TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), + ERR_TPMFRONT); + + bptr = resp; len = resplen; + TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED); + + //Check return status of command + CHECKSTATUSGOTO(ord, "TPM_PCRRead()"); + + //Get the PCR value out + TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, buf, 20), ERR_MALFORMED); + + goto egress; +abort_egress: + memset(buf, 0x20, 20); +egress: + free(cmdbuf); +} + TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length) { TPM_RESULT status = TPM_SUCCESS; -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 10/14] mini-os/tpmback: set up callbacks before enumeration
The open/close callbacks in tpmback cannot be properly initalized in order to catch the initial enumeration events because init_tpmback clears the callbacks and then asynchronously starts the enumeration of existing tpmback devices. Fix this by passing the callbacks to init_tpmback so they can be installed before enumeration. This also removes the unused callbacks for suspend and resume. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/include/tpmback.h | 12 +----------- extras/mini-os/tpmback.c | 31 +++---------------------------- stubdom/vtpm/vtpm.c | 2 +- stubdom/vtpmmgr/init.c | 2 +- 4 files changed, 6 insertions(+), 41 deletions(-) diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h index ec9eda4..3c11c34 100644 --- a/extras/mini-os/include/tpmback.h +++ b/extras/mini-os/include/tpmback.h @@ -56,7 +56,7 @@ struct tpmcmd { typedef struct tpmcmd tpmcmd_t; /* Initialize the tpm backend driver */ -void init_tpmback(void); +void init_tpmback(void (*open_cb)(domid_t, unsigned int), void (*close_cb)(domid_t, unsigned int)); /* Shutdown tpm backend driver */ void shutdown_tpmback(void); @@ -94,14 +94,4 @@ int tpmback_num_frontends(void); * The return value is internally allocated, so don''t free it */ unsigned char* tpmback_get_uuid(domid_t domid, unsigned int handle); -/* Specify a function to call when a new tpm device connects */ -void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)); - -/* Specify a function to call when a tpm device disconnects */ -void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)); - -//Not Implemented -void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int)); -void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)); - #endif diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 69a7f2d..1c46e5d 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -114,8 +114,6 @@ struct tpmback_dev { /* Callbacks */ void (*open_callback)(domid_t, unsigned int); void (*close_callback)(domid_t, unsigned int); - void (*suspend_callback)(domid_t, unsigned int); - void (*resume_callback)(domid_t, unsigned int); }; typedef struct tpmback_dev tpmback_dev_t; @@ -131,8 +129,6 @@ static tpmback_dev_t gtpmdev = { .events = NULL, .open_callback = NULL, .close_callback = NULL, - .suspend_callback = NULL, - .resume_callback = NULL, }; struct wait_queue_head waitq; int globalinit = 0; @@ -772,23 +768,6 @@ unsigned char* tpmback_get_uuid(domid_t domid, unsigned int handle) return tpmif->uuid; } -void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)) -{ - gtpmdev.open_callback = cb; -} -void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)) -{ - gtpmdev.close_callback = cb; -} -void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int)) -{ - gtpmdev.suspend_callback = cb; -} -void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)) -{ - gtpmdev.resume_callback = cb; -} - static void event_listener(void) { const char* bepath = "backend/vtpm2"; @@ -835,7 +814,7 @@ void event_thread(void* p) { event_listener(); } -void init_tpmback(void) +void init_tpmback(void (*open_cb)(domid_t, unsigned int), void (*close_cb)(domid_t, unsigned int)) { if(!globalinit) { init_waitqueue_head(&waitq); @@ -847,8 +826,8 @@ void init_tpmback(void) gtpmdev.num_tpms = 0; gtpmdev.flags = 0; - gtpmdev.open_callback = gtpmdev.close_callback = NULL; - gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL; + gtpmdev.open_callback = open_cb; + gtpmdev.close_callback = close_cb; eventthread = create_thread("tpmback-listener", event_thread, NULL); @@ -856,10 +835,6 @@ void init_tpmback(void) void shutdown_tpmback(void) { - /* Disable callbacks */ - gtpmdev.open_callback = gtpmdev.close_callback = NULL; - gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL; - TPMBACK_LOG("Shutting down tpm backend\n"); /* Set the quit flag */ gtpmdev.flags = TPMIF_CLOSED; diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index d576c8f..feb8aa3 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -357,7 +357,7 @@ int main(int argc, char **argv) } /* Initialize devices */ - init_tpmback(); + init_tpmback(NULL, NULL); if((tpmfront_dev = init_tpmfront(NULL)) == NULL) { error("Unable to initialize tpmfront device"); goto abort_posttpmfront; diff --git a/stubdom/vtpmmgr/init.c b/stubdom/vtpmmgr/init.c index a158020..00dd9f3 100644 --- a/stubdom/vtpmmgr/init.c +++ b/stubdom/vtpmmgr/init.c @@ -462,7 +462,7 @@ TPM_RESULT vtpmmgr_init(int argc, char** argv) { } //Setup tpmback device - init_tpmback(); + init_tpmback(NULL, NULL); //Setup tpm access switch(opts.tpmdriver) { -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 11/14] mini-os/tpmback: Replace UUID field with opaque pointer
Instead of only recording the UUID field, which may not be of interest to all tpmback implementations, provide a user-settable opaque pointer associated with the tpmback instance. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/include/tpmback.h | 9 +++++++-- extras/mini-os/tpmback.c | 31 ++++++++++++++++++++++++++++--- stubdom/vtpmmgr/init.c | 8 +++++++- stubdom/vtpmmgr/vtpmmgr.c | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h index 3c11c34..a6cbbf1 100644 --- a/extras/mini-os/include/tpmback.h +++ b/extras/mini-os/include/tpmback.h @@ -45,10 +45,10 @@ 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 */ + void *opaque; /* Opaque pointer taken from the tpmback instance */ - unsigned int req_len; /* Size of the command in buf - set by tpmback driver */ uint8_t* req; /* tpm command bits, allocated by driver, DON''T FREE IT */ + unsigned int req_len; /* Size of the command in buf - set by tpmback driver */ unsigned int resp_len; /* Size of the outgoing command, you set this before passing the cmd object to tpmback_resp */ uint8_t* resp; /* Buffer for response - YOU MUST ALLOCATE IT, YOU MUST ALSO FREE IT */ @@ -94,4 +94,9 @@ int tpmback_num_frontends(void); * The return value is internally allocated, so don''t free it */ unsigned char* tpmback_get_uuid(domid_t domid, unsigned int handle); +/* Get and set the opaque pointer for a tpmback instance */ +void* tpmback_get_opaque(domid_t domid, unsigned int handle); +/* Returns zero if successful, nonzero on failure (no such frontend) */ +int tpmback_set_opaque(domid_t domid, unsigned int handle, void* opaque); + #endif diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index 1c46e5d..cac07fc 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -92,6 +92,7 @@ struct tpmif { enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; unsigned char uuid[16]; + void* opaque; /* state flags */ int flags; @@ -380,6 +381,7 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) tpmif->status = DISCONNECTED; tpmif->page = NULL; tpmif->flags = 0; + tpmif->opaque = NULL; memset(tpmif->uuid, 0, sizeof(tpmif->uuid)); return tpmif; } @@ -757,6 +759,29 @@ static void generate_backend_events(const char* path) return; } +void* tpmback_get_opaque(domid_t domid, unsigned int handle) +{ + tpmif_t* tpmif; + if((tpmif = get_tpmif(domid, handle)) == NULL) { + TPMBACK_DEBUG("get_opaque() failed, %u/%u is an invalid frontend\n", (unsigned int) domid, handle); + return NULL; + } + + return tpmif->opaque; +} + +int tpmback_set_opaque(domid_t domid, unsigned int handle, void *opaque) +{ + tpmif_t* tpmif; + if((tpmif = get_tpmif(domid, handle)) == NULL) { + TPMBACK_DEBUG("set_opaque() failed, %u/%u is an invalid frontend\n", (unsigned int) domid, handle); + return -1; + } + + tpmif->opaque = opaque; + return 0; +} + unsigned char* tpmback_get_uuid(domid_t domid, unsigned int handle) { tpmif_t* tpmif; @@ -853,12 +878,12 @@ void shutdown_tpmback(void) schedule(); } -inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, unsigned char uuid[16]) +static void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, void *opaque) { tpmcmd->domid = domid; tpmcmd->locality = -1; tpmcmd->handle = handle; - memcpy(tpmcmd->uuid, uuid, sizeof(tpmcmd->uuid)); + tpmcmd->opaque = opaque; tpmcmd->req = NULL; tpmcmd->req_len = 0; tpmcmd->resp = NULL; @@ -880,7 +905,7 @@ tpmcmd_t* get_request(tpmif_t* tpmif) { if((cmd = malloc(sizeof(*cmd))) == NULL) { goto error; } - init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); + init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->opaque); shr = tpmif->page; cmd->req_len = shr->length; diff --git a/stubdom/vtpmmgr/init.c b/stubdom/vtpmmgr/init.c index 00dd9f3..33ac152 100644 --- a/stubdom/vtpmmgr/init.c +++ b/stubdom/vtpmmgr/init.c @@ -436,6 +436,12 @@ egress: return status; } +/* Set up the opaque field to contain a pointer to the UUID */ +static void set_opaque_to_uuid(domid_t domid, unsigned int handle) +{ + tpmback_set_opaque(domid, handle, tpmback_get_uuid(domid, handle)); +} + TPM_RESULT vtpmmgr_init(int argc, char** argv) { TPM_RESULT status = TPM_SUCCESS; @@ -462,7 +468,7 @@ TPM_RESULT vtpmmgr_init(int argc, char** argv) { } //Setup tpmback device - init_tpmback(NULL, NULL); + init_tpmback(set_opaque_to_uuid, NULL); //Setup tpm access switch(opts.tpmdriver) { diff --git a/stubdom/vtpmmgr/vtpmmgr.c b/stubdom/vtpmmgr/vtpmmgr.c index 563f4e8..270ca8a 100644 --- a/stubdom/vtpmmgr/vtpmmgr.c +++ b/stubdom/vtpmmgr/vtpmmgr.c @@ -61,7 +61,7 @@ void main_loop(void) { tpmcmd->resp = respbuf; /* Process the command */ - vtpmmgr_handle_cmd(tpmcmd->uuid, tpmcmd); + vtpmmgr_handle_cmd(tpmcmd->opaque, tpmcmd); /* Send response */ tpmback_resp(tpmcmd); -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 12/14] mini-os/tpmback: add tpmback_get_peercontext
This allows the XSM label of the TPM''s client domain to be retrieved. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- extras/mini-os/events.c | 22 ++++++++++++++++++++++ extras/mini-os/include/events.h | 1 + extras/mini-os/include/tpmback.h | 2 ++ extras/mini-os/tpmback.c | 11 +++++++++++ 4 files changed, 36 insertions(+) diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index 2f359a5..5327e14 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -21,6 +21,7 @@ #include <mini-os/hypervisor.h> #include <mini-os/events.h> #include <mini-os/lib.h> +#include <xen/xsm/flask_op.h> #define NR_EVS 1024 @@ -258,6 +259,27 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, return rc; } +int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size) +{ + int rc; + uint32_t sid; + struct xen_flask_op op; + op.cmd = FLASK_GET_PEER_SID; + op.interface_version = XEN_FLASK_INTERFACE_VERSION; + op.u.peersid.evtchn = local_port; + rc = _hypercall1(int, xsm_op, &op); + if (rc) + return rc; + sid = op.u.peersid.sid; + op.cmd = FLASK_SID_TO_CONTEXT; + op.u.sid_context.sid = sid; + op.u.sid_context.size = size; + set_xen_guest_handle(op.u.sid_context.context, ctx); + rc = _hypercall1(int, xsm_op, &op); + return rc; +} + + /* * Local variables: * mode: C diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index 912e4cf..0e9d3a7 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -37,6 +37,7 @@ int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, evtchn_handler_t handler, void *data, evtchn_port_t *local_port); +int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size); void unbind_all_ports(void); static inline int notify_remote_via_evtchn(evtchn_port_t port) diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h index a6cbbf1..4408986 100644 --- a/extras/mini-os/include/tpmback.h +++ b/extras/mini-os/include/tpmback.h @@ -99,4 +99,6 @@ void* tpmback_get_opaque(domid_t domid, unsigned int handle); /* Returns zero if successful, nonzero on failure (no such frontend) */ int tpmback_set_opaque(domid_t domid, unsigned int handle, void* opaque); +/* Get the XSM context of the given domain (using the tpmback event channel) */ +int tpmback_get_peercontext(domid_t domid, unsigned int handle, void* buffer, int buflen); #endif diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c index cac07fc..ab69cb7 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -793,6 +793,17 @@ unsigned char* tpmback_get_uuid(domid_t domid, unsigned int handle) return tpmif->uuid; } +int tpmback_get_peercontext(domid_t domid, unsigned int handle, void* buffer, int buflen) +{ + tpmif_t* tpmif; + if((tpmif = get_tpmif(domid, handle)) == NULL) { + TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid frontend\n", (unsigned int) domid, handle); + return -1; + } + + return evtchn_get_peercontext(tpmif->evtchn, buffer, buflen); +} + static void event_listener(void) { const char* bepath = "backend/vtpm2"; -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 13/14] stubdom/vtpm: constrain locality by XSM label
This adds the ability for a vTPM to constrain what localities a given client domain can use based on its XSM label. For example: locality=user_1:vm_r:domU_t=0,1,2 locality=user_1:vm_r:watcher_t=5 Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/vtpm/vtpm.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c index feb8aa3..3fbdc59 100644 --- a/stubdom/vtpm/vtpm.c +++ b/stubdom/vtpm/vtpm.c @@ -139,6 +139,30 @@ int check_ordinal(tpmcmd_t* tpmcmd) { return true; } +struct locality_item { + char* lbl; + uint8_t mask[32]; +}; +#define MAX_CLIENT_LOCALITIES 16 +static struct locality_item client_locality[MAX_CLIENT_LOCALITIES]; +static int nr_client_localities = 0; + +static void *generate_locality_mask(domid_t domid, unsigned int handle) +{ + char label[512]; + int i; + if (tpmback_get_peercontext(domid, handle, label, sizeof(label))) + BUG(); + for(i=0; i < nr_client_localities; i++) { + if (!strcmp(client_locality[i].lbl, label)) + goto found; + } + return NULL; + found: + tpmback_set_opaque(domid, handle, client_locality[i].mask); + return client_locality[i].mask; +} + static void main_loop(void) { tpmcmd_t* tpmcmd = NULL; int res = -1; @@ -164,11 +188,24 @@ static void main_loop(void) { while(tpmcmd) { /* Handle the request */ if(tpmcmd->req_len) { + uint8_t* locality_mask = tpmcmd->opaque; + uint8_t locality_bit = (1 << (tpmcmd->locality & 7)); + int locality_byte = tpmcmd->locality >> 3; tpmcmd->resp = NULL; tpmcmd->resp_len = 0; - /* First check for disabled ordinals */ - if(!check_ordinal(tpmcmd)) { + if (nr_client_localities && !locality_mask) + locality_mask = generate_locality_mask(tpmcmd->domid, tpmcmd->handle); + if (nr_client_localities && !locality_mask) { + error("Unknown client label in tpm_handle_command"); + create_error_response(tpmcmd, TPM_FAIL); + } + else if (nr_client_localities && !(locality_mask[locality_byte] & locality_bit)) { + error("Invalid locality (%d) for client in tpm_handle_command", tpmcmd->locality); + create_error_response(tpmcmd, TPM_FAIL); + } + /* Check for disabled ordinals */ + else if(!check_ordinal(tpmcmd)) { create_error_response(tpmcmd, TPM_BAD_ORDINAL); } /* If not disabled, do the command */ @@ -273,6 +310,36 @@ int parse_cmd_line(int argc, char** argv) pch = strtok(NULL, ","); } } + else if(!strncmp(argv[i], "locality=", 9)) { + char *lbl = argv[i] + 9; + char *pch = strchr(lbl, ''=''); + uint8_t* locality_mask = client_locality[nr_client_localities].mask; + if (pch == NULL) { + error("Invalid locality specification: %s", lbl); + return -1; + } + if (nr_client_localities == MAX_CLIENT_LOCALITIES) { + error("Too many locality specifications"); + return -1; + } + client_locality[nr_client_localities].lbl = lbl; + memset(locality_mask, 0, 32); + nr_client_localities++; + *pch = 0; + pch = strtok(pch + 1, ","); + while (pch != NULL) { + int loc; + if (sscanf(pch, "%u", &loc) == 1) { + uint8_t locality_bit = (1 << (loc & 7)); + int locality_byte = loc >> 3; + locality_mask[locality_byte] |= locality_bit; + } else { + error("Invalid locality item: %s", pch); + return -1; + } + pch = strtok(NULL, ","); + } + } else { error("Invalid command line option `%s''", argv[i]); } -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 19:55 UTC
[PATCH 14/14] stubdom/Makefile: Fix gmp extract rule
When NEWLIB_STAMPFILE is updated but gmp has already been extracted, the mv command will incorrectly create a subdirectory instead of renaming. Remove the old target before renaming to fix this. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- stubdom/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/stubdom/Makefile b/stubdom/Makefile index 053fe18..a2463fe 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -162,6 +162,7 @@ ifeq ($(XEN_TARGET_ARCH), x86_32) endif gmp-$(XEN_TARGET_ARCH): gmp-$(GMP_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) tar xjf $< + rm $@ -rf || : mv gmp-$(GMP_VERSION) $@ #patch -d $@ -p0 < gmp.patch cd $@; CPPFLAGS="-isystem $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include $(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" CC=$(CC) $(GMPEXT) ./configure --disable-shared --enable-static --disable-fft --without-readline --prefix=$(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf -- 1.7.11.7
Daniel De Graaf
2012-Dec-10 20:00 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 | 195 +++++++------------------------------ include/xen/interface/io/tpmif.h | 42 ++------ 2 files changed, 42 insertions(+), 195 deletions(-) diff --git a/drivers/char/tpm/xen-tpmfront_if.c b/drivers/char/tpm/xen-tpmfront_if.c index ba7fad8..374ad1b 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) @@ -457,10 +393,10 @@ static int tpmif_connect(struct xenbus_device *dev, } static const struct xenbus_device_id tpmfront_ids[] = { - { "vtpm" }, + { "vtpm2" }, { "" } }; -MODULE_ALIAS("xen:vtpm"); +MODULE_ALIAS("xen:vtpm2"); static DEFINE_XENBUS_DRIVER(tpmfront, , .probe = tpmfront_probe, @@ -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..b55ac56 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 { + uint32_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 pad; -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
Samuel Thibault
2012-Dec-10 21:20 UTC
Re: [PATCH 12/14] mini-os/tpmback: add tpmback_get_peercontext
Daniel De Graaf, le Mon 10 Dec 2012 14:55:45 -0500, a écrit :> +int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)I don''t know about peercontext, is it supposed to be a string, or just data? In the latter case, void* would be better. Samuel
Daniel De Graaf
2012-Dec-10 21:22 UTC
Re: [PATCH 12/14] mini-os/tpmback: add tpmback_get_peercontext
On 12/10/2012 04:20 PM, Samuel Thibault wrote:> Daniel De Graaf, le Mon 10 Dec 2012 14:55:45 -0500, a écrit : >> +int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size) > > I don''t know about peercontext, is it supposed to be a string, or just > data? In the latter case, void* would be better. > > SamuelIt is a string, for example "user_1:vm_r:domU_t" as used in #13 -- Daniel De Graaf National Security Agency
Samuel Thibault
2012-Dec-10 21:24 UTC
Re: [PATCH 14/14] stubdom/Makefile: Fix gmp extract rule
Daniel De Graaf, le Mon 10 Dec 2012 14:55:47 -0500, a écrit :> gmp-$(XEN_TARGET_ARCH): gmp-$(GMP_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) > tar xjf $< > + rm $@ -rf || :I''m realizing...> mv gmp-$(GMP_VERSION) $@ > #patch -d $@ -p0 < gmp.patch > cd $@; CPPFLAGS="-isystem $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include $(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" CC=$(CC) $(GMPEXT) ./configure --disable-shared --enable-static --disable-fft --without-readline --prefix=$(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elfWhich is configure invoked here? In the other cases, we have used a stampfile, to separate unpacking and configure stages, which avoids the issue. Is it because libgmp does not support build out of tree? If so, then I''m fine with the rm change, although -rm $@ -rf instead of || : would be more readable. Samuel
Samuel Thibault
2012-Dec-10 21:25 UTC
Re: [PATCH 12/14] mini-os/tpmback: add tpmback_get_peercontext
Daniel De Graaf, le Mon 10 Dec 2012 16:22:23 -0500, a écrit :> On 12/10/2012 04:20 PM, Samuel Thibault wrote: > > Daniel De Graaf, le Mon 10 Dec 2012 14:55:45 -0500, a écrit : > >> +int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size) > > > > I don''t know about peercontext, is it supposed to be a string, or just > > data? In the latter case, void* would be better. > > > > Samuel > > It is a string, for example "user_1:vm_r:domU_t" as used in #13Ok, then Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Samuel
Daniel De Graaf
2012-Dec-10 21:28 UTC
Re: [PATCH 14/14] stubdom/Makefile: Fix gmp extract rule
On 12/10/2012 04:24 PM, Samuel Thibault wrote:> Daniel De Graaf, le Mon 10 Dec 2012 14:55:47 -0500, a écrit : >> gmp-$(XEN_TARGET_ARCH): gmp-$(GMP_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) >> tar xjf $< >> + rm $@ -rf || : > > I''m realizing... > >> mv gmp-$(GMP_VERSION) $@ >> #patch -d $@ -p0 < gmp.patch >> cd $@; CPPFLAGS="-isystem $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include $(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" CC=$(CC) $(GMPEXT) ./configure --disable-shared --enable-static --disable-fft --without-readline --prefix=$(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf > > Which is configure invoked here? In the other cases, we have used a > stampfile, to separate unpacking and configure stages, which avoids the > issue. Is it because libgmp does not support build out of tree? If so, > then I''m fine with the rm change, although -rm $@ -rf instead of || : > would be more readable. > > Samuel >I didn''t look too closely at the reasons why the configure is done here; the rm is needed regardless of where the configure is done, assuming the tarball could be touched while the directory exists. I chose "|| :" instead of -rm because it silences make''s output on the failure, which will be normal the first time it is run. If -rm is preferred, that''s trivial to fix. -- Daniel De Graaf National Security Agency
Samuel Thibault
2012-Dec-10 21:33 UTC
Re: [PATCH 14/14] stubdom/Makefile: Fix gmp extract rule
Daniel De Graaf, le Mon 10 Dec 2012 16:28:37 -0500, a écrit :> I chose "|| :" instead of -rm because it silences make''s output on the failure,Ok, right. Samuel
Jan Beulich
2012-Dec-11 11:52 UTC
Re: [PATCH] drivers/tpm-xen: Change vTPM shared page ABI
>>> On 10.12.12 at 21:00, Daniel De Graaf <dgdegra@tycho.nsa.gov> 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.Given -#define TPMIF_TX_RING_SIZE 1 where was the problem? Also, the patch replaces the old interface by the new one - how is that compatible with older implementations? The positive aspect is that the new interface isn''t address size dependent anymore (and hence mixed size backend/frontend can work together, which isn''t the case for the original one). Jan> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/char/tpm/xen-tpmfront_if.c | 195 +++++++------------------------------ > include/xen/interface/io/tpmif.h | 42 ++------ > 2 files changed, 42 insertions(+), 195 deletions(-) > > diff --git a/drivers/char/tpm/xen-tpmfront_if.c > b/drivers/char/tpm/xen-tpmfront_if.c > index ba7fad8..374ad1b 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) > @@ -457,10 +393,10 @@ static int tpmif_connect(struct xenbus_device *dev, > } > > static const struct xenbus_device_id tpmfront_ids[] = { > - { "vtpm" }, > + { "vtpm2" }, > { "" } > }; > -MODULE_ALIAS("xen:vtpm"); > +MODULE_ALIAS("xen:vtpm2"); > > static DEFINE_XENBUS_DRIVER(tpmfront, , > .probe = tpmfront_probe, > @@ -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..b55ac56 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 { > + uint32_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 pad; > > -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 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Dec-11 14:55 UTC
Re: [PATCH] drivers/tpm-xen: Change vTPM shared page ABI
On 12/11/2012 06:52 AM, Jan Beulich wrote:>>>> On 10.12.12 at 21:00, Daniel De Graaf <dgdegra@tycho.nsa.gov> 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. > > Given > > -#define TPMIF_TX_RING_SIZE 1 > > where was the problem?The shared ring still needed to refer to grants and a series of shared pages for requests and replies, and was implemented by mapping and unmapping grants on each request. While a persistent mapping (like being introduced in Linux) could also have addressed the efficiency issues, redoing the shared page seemed cleaner. Redoing the shared page allows potentially supporting TPM packets up to 1MB in size, although that requires using the extra_pages list which isn''t implemented (most, if not all, users won''t use large packets in order to support hardware TPMs with hard limitations on the packet size). It also allows introducing an out-of-band locality field for requests, and the status field could easily be extended to allow command cancellation - although that would require a vTPM supporting cancellation; CPU-based vTPMs are fast enough that cancellation is not needed to meet the timing requirements.> Also, the patch replaces the old interface by the new one - how > is that compatible with older implementations?It is not; we''ve decided to call this "vtpm2" in xenbus to address this. From the condition of the old vtpm code in Xen, there appear to be few users of the old implementation, even if there are many users of a kernel with the driver present.> The positive aspect is that the new interface isn''t address size > dependent anymore (and hence mixed size backend/frontend can > work together, which isn''t the case for the original one). > > Jan >
Daniel De Graaf
2012-Dec-14 20:12 UTC
Re: [PATCH 09/14] stubdom/vtpm: Add PCR pass-through to hardware TPM
On 12/10/2012 02:55 PM, Daniel De Graaf wrote:> This allows the hardware TPM''s PCRs to be accessed from a vTPM for > debugging and as a simple alternative to a deep quote in situations > where the integrity of the vTPM''s own TCB is not in question. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > stubdom/Makefile | 1 + > stubdom/vtpm-pcr-passthrough.patch | 73 ++++++++++++++++++++++++++++++++++++++ > stubdom/vtpm/vtpm_cmd.c | 38 ++++++++++++++++++++ > 3 files changed, 112 insertions(+) > create mode 100644 stubdom/vtpm-pcr-passthrough.patchThis patch is incomplete, so don''t apply it: seal operations can''t use the extra PCRs, and it''s likely other operations such as nvram have the same problem. It''s not a dependency for any other patch, and an alternative implementation should end up being more configurable anyway. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Dec-14 20:16 UTC
[PATCH v3.2] mini-os/tpm{back, front}: Change 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. The vtpm xenbus device has been renamed to "vtpm2" to avoid conflicts with existing (xen-patched) kernels supporting the old interface. While the contents of the shared page have been defined to allow packets larger than a single page (actually 4088 bytes) by allowing the client to add extra grant references, the mapping of these extra references has not been implemented; a feature node in xenstore may be used in the future to indicate full support for the multi-page protocol. Most uses of the TPM should not require this feature. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- Changes from v3: the change from "vtpm" to "vtpm2" in libxl was incomplete, causing the vtpm-attach and -detach commands to fail. extras/mini-os/include/tpmback.h | 1 + extras/mini-os/include/tpmfront.h | 7 +- extras/mini-os/tpmback.c | 135 +++++++++++++---------------------- extras/mini-os/tpmfront.c | 119 ++++++++++++------------------ tools/libxl/libxl.c | 12 ++-- tools/libxl/libxl_types_internal.idl | 2 +- xen/include/public/io/tpmif.h | 45 +++--------- 7 files changed, 117 insertions(+), 204 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..50f8a5d 100644 --- a/extras/mini-os/tpmback.c +++ b/extras/mini-os/tpmback.c @@ -86,10 +86,7 @@ struct tpmif { evtchn_port_t evtchn; /* Shared page */ - tpmif_tx_interface_t* tx; - - /* pointer to TPMIF_RX_RING_SIZE pages */ - void** pages; + vtpm_shared_page_t *page; enum xenbus_state state; enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; @@ -312,7 +309,6 @@ int insert_tpmif(tpmif_t* tpmif) remove_tpmif(tpmif); goto error_post_irq; } - return 0; error: local_irq_restore(flags); @@ -336,7 +332,7 @@ int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) if (tpmif->state == state) return 0; - snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/state", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_read(XBT_NIL, path, &value))) { TPMBACK_ERR("Unable to read backend state %s, error was %s\n", path, err); @@ -362,7 +358,7 @@ int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) } /*update xenstore*/ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) { TPMBACK_ERR("Error writing to xenstore %s, error was %s new state=%d\n", path, err, state); free(err); @@ -386,8 +382,7 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) tpmif->fe_state_path = NULL; tpmif->state = XenbusStateInitialising; tpmif->status = DISCONNECTED; - tpmif->tx = NULL; - tpmif->pages = NULL; + tpmif->page = NULL; tpmif->flags = 0; memset(tpmif->uuid, 0, sizeof(tpmif->uuid)); return tpmif; @@ -395,9 +390,6 @@ inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) void __free_tpmif(tpmif_t* tpmif) { - if(tpmif->pages) { - free(tpmif->pages); - } if(tpmif->fe_path) { free(tpmif->fe_path); } @@ -424,23 +416,17 @@ tpmif_t* new_tpmif(domid_t domid, unsigned int handle) tpmif = __init_tpmif(domid, handle); /* Get the uuid from xenstore */ - snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid, handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/uuid", (unsigned int) domid, handle); if((!xenbus_read_uuid(path, tpmif->uuid))) { TPMBACK_ERR("Error reading %s\n", path); 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; } - snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int) domid, handle); + snprintf(path, 512, "backend/vtpm2/%u/%u/frontend", (unsigned int) domid, handle); if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) { TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s), Error = %s", path, err); free(err); @@ -486,7 +472,7 @@ void free_tpmif(tpmif_t* tpmif) tpmif->status = DISCONNECTING; mask_evtchn(tpmif->evtchn); - if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1)) { + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1)) { TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); } @@ -508,7 +494,7 @@ void free_tpmif(tpmif_t* tpmif) schedule(); /* Remove the old xenbus entries */ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_rm(XBT_NIL, path))) { TPMBACK_ERR("Error cleaning up xenbus entries path=%s error=%s\n", path, err); free(err); @@ -529,9 +515,10 @@ void free_tpmif(tpmif_t* tpmif) void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *data) { tpmif_t* tpmif = (tpmif_t*) data; - tpmif_tx_request_t* tx = &tpmif->tx->ring[0].req; - /* Throw away 0 size events, these can trigger from event channel unmasking */ - if(tx->size == 0) + vtpm_shared_page_t* pg = tpmif->page; + + /* Only pay attention if the request is ready */ + if (pg->state == 0) return; TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); @@ -585,11 +572,10 @@ int connect_fe(tpmif_t* tpmif) free(value); domid = tpmif->domid; - if((tpmif->tx = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { + if((tpmif->page = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); return -1; } - memset(tpmif->tx, 0, PAGE_SIZE); /*Bind the event channel */ if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tpmif, &tpmif->evtchn))) @@ -600,7 +586,7 @@ int connect_fe(tpmif_t* tpmif) unmask_evtchn(tpmif->evtchn); /* Write the ready flag and change status to connected */ - snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + snprintf(path, 512, "backend/vtpm2/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) { TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n", (unsigned int) tpmif->domid, tpmif->handle); free(err); @@ -618,7 +604,7 @@ error_post_evtchn: mask_evtchn(tpmif->evtchn); unbind_evtchn(tpmif->evtchn); error_post_map: - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1); + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->page, 1); return -1; } @@ -670,8 +656,8 @@ static int parse_eventstr(const char* evstr, domid_t* domid, unsigned int* handl char* value; unsigned int udomid = 0; tpmif_t* tpmif; - /* First check for new frontends, this occurs when /backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to fail on the last %s */ - if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd) == 2) { + /* First check for new frontends, this occurs when /backend/vtpm2/<domid>/<handle> gets created. Note we what the sscanf to fail on the last %s */ + if (sscanf(evstr, "backend/vtpm2/%u/%u/%40s", &udomid, handle, cmd) == 2) { *domid = udomid; /* Make sure the entry exists, if this event triggers because the entry dissapeared then ignore it */ if((err = xenbus_read(XBT_NIL, evstr, &value))) { @@ -685,7 +671,7 @@ static int parse_eventstr(const char* evstr, domid_t* domid, unsigned int* handl return EV_NONE; } return EV_NEWFE; - } else if((ret = sscanf(evstr, "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) { + } else if((ret = sscanf(evstr, "/local/domain/%u/device/vtpm2/%u/%40s", &udomid, handle, cmd)) == 3) { *domid = udomid; if (!strcmp(cmd, "state")) return EV_STCHNG; @@ -784,7 +770,7 @@ void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)) static void event_listener(void) { - const char* bepath = "backend/vtpm"; + const char* bepath = "backend/vtpm2"; char **path; char* err; @@ -874,6 +860,7 @@ void shutdown_tpmback(void) inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, unsigned char uuid[16]) { tpmcmd->domid = domid; + tpmcmd->locality = -1; tpmcmd->handle = handle; memcpy(tpmcmd->uuid, uuid, sizeof(tpmcmd->uuid)); tpmcmd->req = NULL; @@ -884,12 +871,12 @@ inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, un tpmcmd_t* get_request(tpmif_t* tpmif) { tpmcmd_t* cmd; - tpmif_tx_request_t* tx; - int offset; - int tocopy; - int i; - uint32_t domid; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG + int i; +#endif local_irq_save(flags); @@ -899,35 +886,22 @@ tpmcmd_t* get_request(tpmif_t* tpmif) { } init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); - tx = &tpmif->tx->ring[0].req; - cmd->req_len = tx->size; + shr = tpmif->page; + cmd->req_len = shr->length; + cmd->locality = shr->locality; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->req_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } /* Allocate the buffer */ if(cmd->req_len) { if((cmd->req = malloc(cmd->req_len)) == NULL) { goto error; } } - /* Copy the bits from the shared pages */ - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_READ)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->req_len - offset, PAGE_SIZE); - memcpy(&cmd->req[offset], tpmif->pages[i], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); - - } + /* Copy the bits from the shared page(s) */ + memcpy(cmd->req, offset + (uint8_t*)shr, cmd->req_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len); @@ -958,38 +932,24 @@ error: void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) { - tpmif_tx_request_t* tx; - int offset; - int i; - uint32_t domid; - int tocopy; + vtpm_shared_page_t* shr; + unsigned int offset; int flags; +#ifdef TPMBACK_PRINT_DEBUG +int i; +#endif local_irq_save(flags); - tx = &tpmif->tx->ring[0].req; - tx->size = cmd->resp_len; - - offset = 0; - for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i) { - tx = &tpmif->tx->ring[i].req; - - /* Map the page with the data */ - domid = (uint32_t)tpmif->domid; - if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_WRITE)) == NULL) { - TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", (unsigned int) tpmif->domid, tpmif->handle); - goto error; - } - - /* do the copy now */ - tocopy = min(cmd->resp_len - offset, PAGE_SIZE); - memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy); - offset += tocopy; - - /* release the page */ - gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); + shr = tpmif->page; + shr->length = cmd->resp_len; + offset = sizeof(*shr) + 4*shr->nr_extra_pages; + if (offset > PAGE_SIZE || offset + cmd->resp_len > PAGE_SIZE) { + TPMBACK_ERR("%u/%u Command size too long for shared page!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; } + memcpy(offset + (uint8_t*)shr, cmd->resp, cmd->resp_len); #ifdef TPMBACK_PRINT_DEBUG TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->resp_len); @@ -1003,6 +963,7 @@ void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) #endif /* clear the ready flag and send the event channel notice to the frontend */ tpmif_req_finished(tpmif); + shr->state = 0; notify_remote_via_evtchn(tpmif->evtchn); error: local_irq_restore(flags); diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c index 0218d7f..ac9ba42 100644 --- a/extras/mini-os/tpmfront.c +++ b/extras/mini-os/tpmfront.c @@ -176,7 +176,7 @@ static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState ret = wait_for_backend_closed(&events, path); break; default: - break; + TPMFRONT_ERR("Bad wait state %d, ignoring\n", state); } if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { @@ -190,13 +190,13 @@ static int tpmfront_connect(struct tpmfront_dev* dev) { char* err; /* Create shared page */ - dev->tx = (tpmif_tx_interface_t*) alloc_page(); - if(dev->tx == NULL) { + dev->page = (vtpm_shared_page_t*) alloc_page(); + if(dev->page == NULL) { TPMFRONT_ERR("Unable to allocate page for shared memory\n"); goto error; } - memset(dev->tx, 0, PAGE_SIZE); - dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->tx), 0); + memset(dev->page, 0, PAGE_SIZE); + dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->page), 0); TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref); /*Create event channel */ @@ -228,7 +228,7 @@ error_postevtchn: unbind_evtchn(dev->evtchn); error_postmap: gnttab_end_access(dev->ring_ref); - free_page(dev->tx); + free_page(dev->page); error: return -1; } @@ -240,7 +240,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) char path[512]; char* value, *err; unsigned long long ival; - int i; printk("============= Init TPM Front ================\n"); @@ -251,7 +250,7 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) dev->fd = -1; #endif - nodename = _nodename ? _nodename : "device/vtpm/0"; + nodename = _nodename ? _nodename : "device/vtpm2/0"; dev->nodename = strdup(nodename); init_waitqueue_head(&dev->waitq); @@ -289,19 +288,6 @@ struct tpmfront_dev* init_tpmfront(const char* _nodename) goto error; } - /* Allocate pages that will contain the messages */ - dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE); - if(dev->pages == NULL) { - goto error; - } - memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - dev->pages[i] = (void*)alloc_page(); - if(dev->pages[i] == NULL) { - goto error; - } - } - TPMFRONT_LOG("Initialization Completed successfully\n"); return dev; @@ -314,8 +300,6 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) { char* err; char path[512]; - int i; - tpmif_tx_request_t* tx; if(dev == NULL) { return; } @@ -349,27 +333,12 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) /* Wait for the backend to close and unmap shared pages, ignore any errors */ wait_for_backend_state_changed(dev, XenbusStateClosed); - /* Cleanup any shared pages */ - if(dev->pages) { - for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { - if(dev->pages[i]) { - tx = &dev->tx->ring[i].req; - if(tx->ref != 0) { - gnttab_end_access(tx->ref); - } - free_page(dev->pages[i]); - } - } - free(dev->pages); - } - /* Close event channel and unmap shared page */ mask_evtchn(dev->evtchn); unbind_evtchn(dev->evtchn); gnttab_end_access(dev->ring_ref); - free_page(dev->tx); - + free_page(dev->page); } /* Cleanup memory usage */ @@ -387,13 +356,17 @@ void shutdown_tpmfront(struct tpmfront_dev* dev) int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) { + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG int i; - tpmif_tx_request_t* tx = NULL; +#endif /* Error Checking */ if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to send message through disconnected frontend\n"); return -1; } + shr = dev->page; #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length); @@ -407,19 +380,16 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) #endif /* Copy to shared pages now */ - for(i = 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) { - /* Share the page */ - tx = &dev->tx->ring[i].req; - tx->unused = 0; - tx->addr = virt_to_mach(dev->pages[i]); - tx->ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->pages[i]), 0); - /* Copy the bits to the page */ - tx->size = length > PAGE_SIZE ? PAGE_SIZE : length; - memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size); - - /* Update counters */ - length -= tx->size; + offset = sizeof(*shr); + if (length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Message too long for shared page\n"); + return -1; } + memcpy(offset + (uint8_t*)shr, msg, length); + shr->length = length; + barrier(); + shr->state = 1; + dev->waiting = 1; dev->resplen = 0; #ifdef HAVE_LIBC @@ -434,44 +404,41 @@ int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) } int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *length) { - tpmif_tx_request_t* tx; - int i; + unsigned int offset; + vtpm_shared_page_t* shr = NULL; +#ifdef TPMFRONT_PRINT_DEBUG +int i; +#endif if(dev == NULL || dev->state != XenbusStateConnected) { TPMFRONT_ERR("Tried to receive message from disconnected frontend\n"); return -1; } /*Wait for the response */ wait_event(dev->waitq, (!dev->waiting)); + shr = dev->page; + if (shr->state != 0) + goto quit; /* Initialize */ *msg = NULL; - *length = 0; + *length = shr->length; + offset = sizeof(*shr); - /* special case, just quit */ - tx = &dev->tx->ring[0].req; - if(tx->size == 0 ) { - goto quit; - } - /* Get the total size */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - *length += tx->size; + if (*length + offset > PAGE_SIZE) { + TPMFRONT_ERR("Reply too long for shared page\n"); + return -1; } + /* Alloc the buffer */ if(dev->respbuf) { free(dev->respbuf); } *msg = dev->respbuf = malloc(*length); dev->resplen = *length; + /* Copy the bits */ - tx = &dev->tx->ring[0].req; - for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { - tx = &dev->tx->ring[i].req; - memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size); - gnttab_end_access(tx->ref); - tx->ref = 0; - } + memcpy(*msg, offset + (uint8_t*)shr, *length); + #ifdef TPMFRONT_PRINT_DEBUG TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned int) *length); for(i = 0; i < *length; ++i) { @@ -504,6 +471,14 @@ int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t* return 0; } +int tpmfront_set_locality(struct tpmfront_dev* dev, int locality) +{ + if (!dev || !dev->page) + return -1; + dev->page->locality = locality; + return 0; +} + #ifdef HAVE_LIBC #include <errno.h> int tpmfront_open(struct tpmfront_dev* dev) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 8d921bc..77a3836 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1725,10 +1725,10 @@ static int libxl__device_from_vtpm(libxl__gc *gc, uint32_t domid, { device->backend_devid = vtpm->devid; device->backend_domid = vtpm->backend_domid; - device->backend_kind = LIBXL__DEVICE_KIND_VTPM; + device->backend_kind = LIBXL__DEVICE_KIND_VTPM2; device->devid = vtpm->devid; device->domid = domid; - device->kind = LIBXL__DEVICE_KIND_VTPM; + device->kind = LIBXL__DEVICE_KIND_VTPM2; return 0; } @@ -1756,7 +1756,7 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, goto out; } l = libxl__xs_directory(gc, XBT_NULL, - GCSPRINTF("%s/device/vtpm", dompath), &nb); + GCSPRINTF("%s/device/vtpm2", dompath), &nb); if(l == NULL || nb == 0) { vtpm->devid = 0; } else { @@ -1815,7 +1815,7 @@ libxl_device_vtpm *libxl_device_vtpm_list(libxl_ctx *ctx, uint32_t domid, int *n *num = 0; - fe_path = libxl__sprintf(gc, "%s/device/vtpm", libxl__xs_get_dompath(gc, domid)); + fe_path = libxl__sprintf(gc, "%s/device/vtpm2", libxl__xs_get_dompath(gc, domid)); dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs); if(dir) { vtpms = malloc(sizeof(*vtpms) * ndirs); @@ -1830,7 +1830,7 @@ libxl_device_vtpm *libxl_device_vtpm_list(libxl_ctx *ctx, uint32_t domid, int *n vtpm->devid = atoi(*dir); tmp = libxl__xs_read(gc, XBT_NULL, - GCSPRINTF("%s/%s/backend_id", + GCSPRINTF("%s/%s/backend-id", fe_path, *dir)); vtpm->backend_domid = atoi(tmp); @@ -1863,7 +1863,7 @@ int libxl_device_vtpm_getinfo(libxl_ctx *ctx, dompath = libxl__xs_get_dompath(gc, domid); vtpminfo->devid = vtpm->devid; - vtpmpath = GCSPRINTF("%s/device/vtpm/%d", dompath, vtpminfo->devid); + vtpmpath = GCSPRINTF("%s/device/vtpm2/%d", dompath, vtpminfo->devid); vtpminfo->backend = xs_read(ctx->xsh, XBT_NULL, GCSPRINTF("%s/backend", vtpmpath), NULL); if (!vtpminfo->backend) { diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl index c40120e..7fd43ab 100644 --- a/tools/libxl/libxl_types_internal.idl +++ b/tools/libxl/libxl_types_internal.idl @@ -19,7 +19,7 @@ libxl__device_kind = Enumeration("device_kind", [ (5, "VFB"), (6, "VKBD"), (7, "CONSOLE"), - (8, "VTPM"), + (8, "VTPM2"), ]) libxl__console_backend = Enumeration("console_backend", [ diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h index 02ccdab..7c96530 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 { + uint32_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 pad; -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