|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] stubdom/vtpm: make state save operation atomic
On 11/29/2012 01:07 PM, Matthew Fioravante wrote:
> On 11/27/2012 05:16 PM, Daniel De Graaf wrote:
>> This changes the save format of the vtpm stubdom to include two copies
>> of the saved data: one active, and one inactive. When saving the state,
>> data is written to the inactive slot before updating the key and hash
>> saved with the TPM Manager, which determines the active slot when the
>> vTPM starts up.
>>
>> Signed-off-by: Daniel De Graaf <dgdegra@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
> Instead of statically defining a slot size and stressing over whether or not
> it may be too small, why not make it half the size of the disk image? You can
> retrieve the disk size by doing fstat(blkfront_fd).
Ah, I didn't see that information was available in mini-os. Actually, the
blkinfo
structure in init_vtpmblk is more convenient, so I'll use that.
>> static struct blkfront_dev* blkdev = NULL;
>> static int blkfront_fd = -1;
>> @@ -59,15 +61,20 @@ void shutdown_vtpmblk(void)
>> blkdev = NULL;
>> }
>> -int write_vtpmblk_raw(uint8_t *data, size_t data_length)
>> +static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot)
>> {
>> int rc;
>> uint32_t lenbuf;
>> debug("Begin Write data=%p len=%u", data, data_length);
> Should add which slot were writing to and possibly the disk offset as well to
> the debug print
A number of debug outputs will be improved with slot info.
>> + if (data_length > SLOT_SIZE - 4) {
>> + error("write(data) cannot fit in data slot (%d). Increase
>> SLOT_SIZE.", data_length);
>> + return -1;
>> + }
>> +
>> lenbuf = cpu_to_be32((uint32_t)data_length);
>> - lseek(blkfront_fd, 0, SEEK_SET);
>> + lseek(blkfront_fd, slot * SLOT_SIZE, SEEK_SET);
>> if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
>> error("write(length) failed! error was %s", strerror(errno));
>> return -1;
>> @@ -82,12 +89,12 @@ int write_vtpmblk_raw(uint8_t *data, size_t data_length)
>> return 0;
>> }
>> -int read_vtpmblk_raw(uint8_t **data, size_t *data_length)
>> +static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot)
>> {
>> int rc;
>> uint32_t lenbuf;
>> - lseek(blkfront_fd, 0, SEEK_SET);
>> + lseek(blkfront_fd, slot * SLOT_SIZE, SEEK_SET);
>> if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
>> error("read(length) failed! error was %s", strerror(errno));
>> return -1;
>> @@ -97,6 +104,10 @@ int read_vtpmblk_raw(uint8_t **data, size_t *data_length)
>> error("read 0 data_length for NVM");
>> return -1;
>> }
>> + if(*data_length > SLOT_SIZE - 4) {
>> + error("read invalid data_length for NVM");
>> + return -1;
>> + }
>> *data = tpm_malloc(*data_length);
>> if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) {
>> @@ -221,6 +232,8 @@ egress:
>> return rc;
>> }
>> +static int active_slot = -1;
> I think we should initialize to 0 or 1 because -1 is an invalid state.
> For a new vtpm, read_vtpmblk() will fail and I think this is what happens:
> read_vtpmblk()
> try_fetch_key_from_manager() -> fails
> goto abort_egress
> active_slot = -1 (you have this below)
Yes, that's intentional. That way, you can tell the difference between slot 1
being active and no slot being active.
> Then later
> write_vtpmblk()
> active_slot = !active_slot (!-1 = 0)
>
> The last line happens to work correctly but I don't think its very clear. I
> think we should initialize to 1 and set it to 1 if read_vtpmblk() fails.
I think I'll just put a comment at the !active_slot to note that active_slot is
-1 => 0 if no active slots existed.
> Also a minor nitpick, the name is active_slot, but what it really is is the
> last_slot_written_to because everytime you write you change it first.
That still makes it the active slot: at the point when it's changed, the value
is
the new active slot (and we're just working to commit that change to disk).
>> +
>> int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t
>> data_length) {
>> int rc;
>> uint8_t* cipher = NULL;
>> @@ -228,12 +241,15 @@ int write_vtpmblk(struct tpmfront_dev* tpmfront_dev,
>> uint8_t* data, size_t data_
>> uint8_t hashkey[HASHKEYSZ];
>> uint8_t* symkey = hashkey + HASHSZ;
>> + /* Switch to the other slot */
>> + active_slot = !active_slot;
>> +
>> /* Encrypt the data */
>> if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len,
>> symkey))) {
>> goto abort_egress;
>> }
>> /* Write to disk */
>> - if((rc = write_vtpmblk_raw(cipher, cipher_len))) {
>> + if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) {
>> goto abort_egress;
>> }
>> /* Get sha1 hash of data */
>> @@ -256,7 +272,8 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev,
>> uint8_t** data, size_t *data
>> size_t cipher_len = 0;
>> size_t keysize;
>> uint8_t* hashkey = NULL;
>> - uint8_t hash[HASHSZ];
>> + uint8_t hash0[HASHSZ];
>> + uint8_t hash1[HASHSZ];
>> uint8_t* symkey;
>> /* Retreive the hash and the key from the manager */
>> @@ -270,14 +287,32 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev,
>> uint8_t** data, size_t *data
>> }
>> symkey = hashkey + HASHSZ;
>> - /* Read from disk now */
>> - if((rc = read_vtpmblk_raw(&cipher, &cipher_len))) {
>> + active_slot = 0;
>> + /* Read slot 0 from disk now */
>> + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) {
>> + goto abort_egress;
>> + }
>> +
>> + /* Compute the hash of the cipher text and compare */
>> + sha1(cipher, cipher_len, hash0);
>> + if(!memcmp(hash0, hashkey, HASHSZ))
>> + goto valid;
>> +
>> + free(cipher);
>> + cipher = NULL;
>> +
>> + active_slot = 1;
>> + /* Read slot 1 from disk now */
>> + if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) {
>> goto abort_egress;
>> }
>> /* Compute the hash of the cipher text and compare */
>> - sha1(cipher, cipher_len, hash);
>> - if(memcmp(hash, hashkey, HASHSZ)) {
>> + sha1(cipher, cipher_len, hash1);
>> + if(!memcmp(hash1, hashkey, HASHSZ))
>> + goto valid;
>> +
>> + {
>> int i;
>> error("NVM Storage Checksum failed!");
>> printf("Expected: ");
>> @@ -285,14 +320,20 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev,
>> uint8_t** data, size_t *data
>> printf("%02hhX ", hashkey[i]);
>> }
>> printf("\n");
>> - printf("Actual: ");
>> + printf("Slot 0: ");
>> + for(i = 0; i < HASHSZ; ++i) {
>> + printf("%02hhX ", hash0[i]);
>> + }
>> + printf("\n");
>> + printf("Slot 1: ");
>> for(i = 0; i < HASHSZ; ++i) {
>> - printf("%02hhX ", hash[i]);
>> + printf("%02hhX ", hash1[i]);
>> }
>> printf("\n");
>> rc = -1;
>> goto abort_egress;
>> }
>> +valid:
>> /* Decrypt the blob */
>> if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length,
>> symkey))) {
>> @@ -300,6 +341,7 @@ int read_vtpmblk(struct tpmfront_dev* tpmfront_dev,
>> uint8_t** data, size_t *data
>> }
>> goto egress;
>> abort_egress:
>> + active_slot = -1;
> See my comment above
>> egress:
>> free(cipher);
>> free(hashkey);
>
>
--
Daniel De Graaf
National Security Agency
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |