[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] stubdom/vtpm: make state save operation atomic



This changes the save format of the vtpm stubdom to include two copies
of the saved data: one active, and one inactive. When saving the state,
data is written to the inactive slot before updating the key and hash
saved with the TPM Manager, which determines the active slot when the
vTPM starts up.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
---
 stubdom/vtpm/vtpmblk.c | 66 +++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c
index b343bd8..f988606 100644
--- a/stubdom/vtpm/vtpmblk.c
+++ b/stubdom/vtpm/vtpmblk.c
@@ -23,6 +23,8 @@
 
 /*Encryption key and block sizes */
 #define BLKSZ 16
+/* Maximum size of one saved-state slot */
+#define SLOT_SIZE 32768
 
 static struct blkfront_dev* blkdev = NULL;
 static int blkfront_fd = -1;
@@ -59,15 +61,20 @@ void shutdown_vtpmblk(void)
    blkdev = NULL;
 }
 
-int write_vtpmblk_raw(uint8_t *data, size_t data_length)
+static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot)
 {
    int rc;
    uint32_t lenbuf;
    debug("Begin Write data=%p len=%u", data, data_length);
 
+   if (data_length > SLOT_SIZE - 4) {
+      error("write(data) cannot fit in data slot (%d). Increase SLOT_SIZE.", 
data_length);
+      return -1;
+   }
+
    lenbuf = cpu_to_be32((uint32_t)data_length);
 
-   lseek(blkfront_fd, 0, SEEK_SET);
+   lseek(blkfront_fd, slot * SLOT_SIZE, SEEK_SET);
    if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
       error("write(length) failed! error was %s", strerror(errno));
       return -1;
@@ -82,12 +89,12 @@ int write_vtpmblk_raw(uint8_t *data, size_t data_length)
    return 0;
 }
 
-int read_vtpmblk_raw(uint8_t **data, size_t *data_length)
+static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot)
 {
    int rc;
    uint32_t lenbuf;
 
-   lseek(blkfront_fd, 0, SEEK_SET);
+   lseek(blkfront_fd, slot * SLOT_SIZE, SEEK_SET);
    if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
       error("read(length) failed! error was %s", strerror(errno));
       return -1;
@@ -97,6 +104,10 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length)
       error("read 0 data_length for NVM");
       return -1;
    }
+   if(*data_length > SLOT_SIZE - 4) {
+      error("read invalid data_length for NVM");
+      return -1;
+   }
 
    *data = tpm_malloc(*data_length);
    if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) {
@@ -221,6 +232,8 @@ egress:
    return rc;
 }
 
+static int active_slot = -1;
+
 int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t 
data_length) {
    int rc;
    uint8_t* cipher = NULL;
@@ -228,12 +241,15 @@ int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, 
uint8_t* data, size_t data_
    uint8_t hashkey[HASHKEYSZ];
    uint8_t* symkey = hashkey + HASHSZ;
 
+   /* Switch to the other slot */
+   active_slot = !active_slot;
+
    /* Encrypt the data */
    if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) 
{
       goto abort_egress;
    }
    /* Write to disk */
-   if((rc = write_vtpmblk_raw(cipher, cipher_len))) {
+   if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) {
       goto abort_egress;
    }
    /* Get sha1 hash of data */
@@ -256,7 +272,8 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, 
uint8_t** data, size_t *data
    size_t cipher_len = 0;
    size_t keysize;
    uint8_t* hashkey = NULL;
-   uint8_t hash[HASHSZ];
+   uint8_t hash0[HASHSZ];
+   uint8_t hash1[HASHSZ];
    uint8_t* symkey;
 
    /* Retreive the hash and the key from the manager */
@@ -270,14 +287,32 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, 
uint8_t** data, size_t *data
    }
    symkey = hashkey + HASHSZ;
 
-   /* Read from disk now */
-   if((rc = read_vtpmblk_raw(&cipher, &cipher_len))) {
+   active_slot = 0;
+   /* Read slot 0 from disk now */
+   if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) {
+      goto abort_egress;
+   }
+
+   /* Compute the hash of the cipher text and compare */
+   sha1(cipher, cipher_len, hash0);
+   if(!memcmp(hash0, hashkey, HASHSZ))
+      goto valid;
+
+   free(cipher);
+   cipher = NULL;
+
+   active_slot = 1;
+   /* Read slot 1 from disk now */
+   if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) {
       goto abort_egress;
    }
 
    /* Compute the hash of the cipher text and compare */
-   sha1(cipher, cipher_len, hash);
-   if(memcmp(hash, hashkey, HASHSZ)) {
+   sha1(cipher, cipher_len, hash1);
+   if(!memcmp(hash1, hashkey, HASHSZ))
+      goto valid;
+
+   {
       int i;
       error("NVM Storage Checksum failed!");
       printf("Expected: ");
@@ -285,14 +320,20 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, 
uint8_t** data, size_t *data
         printf("%02hhX ", hashkey[i]);
       }
       printf("\n");
-      printf("Actual:   ");
+      printf("Slot 0:   ");
+      for(i = 0; i < HASHSZ; ++i) {
+        printf("%02hhX ", hash0[i]);
+      }
+      printf("\n");
+      printf("Slot 1:   ");
       for(i = 0; i < HASHSZ; ++i) {
-        printf("%02hhX ", hash[i]);
+        printf("%02hhX ", hash1[i]);
       }
       printf("\n");
       rc = -1;
       goto abort_egress;
    }
+valid:
 
    /* Decrypt the blob */
    if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) {
@@ -300,6 +341,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, 
uint8_t** data, size_t *data
    }
    goto egress;
 abort_egress:
+   active_slot = -1;
 egress:
    free(cipher);
    free(hashkey);
-- 
1.7.11.7


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.