aboutsummaryrefslogtreecommitdiffstats
path: root/stubdom
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2013-03-21 16:11:25 -0400
committerIan Campbell <ian.campbell@citrix.com>2013-04-12 14:28:17 +0100
commit58c2ab7588c4d27ac569494ae4ec8e81795d0ca3 (patch)
tree470f15a329a86c5faeb19f0b98bacf4f75ce2628 /stubdom
parent57c265546e7d12d2f44225928c6b5679ad0a14ba (diff)
downloadxen-58c2ab7588c4d27ac569494ae4ec8e81795d0ca3.tar.gz
xen-58c2ab7588c4d27ac569494ae4ec8e81795d0ca3.tar.bz2
xen-58c2ab7588c4d27ac569494ae4ec8e81795d0ca3.zip
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>
Diffstat (limited to 'stubdom')
-rw-r--r--stubdom/vtpm/vtpmblk.c74
1 files changed, 60 insertions, 14 deletions
diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c
index b343bd84b2..fe529ab5ac 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);