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

[Xen-devel] [PATCH 8/9] stubdom/grub: verify vTPM label if requested



This adds an optional argument --vtpm-label=<label> to the pv-grub
command line.  If specified, a vtpm device must be connected to the
pv-grub domain and the backend of this device must have the given XSM
label (which may start with a * to indicate a wildcard).  Verifying the
label of the vTPM before sending measurements prevents a disaggregated
control domain that has access to xenstore but not to the guest domains
from causing the measurements performed by pv-grub to be discarded,
allowing the forgery of arbitrary kernel measurements in the TPM.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Cc: Samuel Thibault <samuel.thibault@xxxxxxxxxxxx>
---
 stubdom/grub/kexec.c   | 58 ++++++++++++++++++++++++++++++++++++++++++--------
 stubdom/grub/mini-os.c |  8 ++++++-
 stubdom/grub/mini-os.h |  2 ++
 3 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c
index cef357e..dc8db81 100644
--- a/stubdom/grub/kexec.c
+++ b/stubdom/grub/kexec.c
@@ -68,6 +68,14 @@ struct pcr_extend_cmd {
        unsigned char hash[20];
 } __attribute__((packed));
 
+struct pcr_extend_rsp {
+       uint16_t tag;
+       uint32_t size;
+       uint32_t status;
+
+       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]);
@@ -135,20 +143,49 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t 
up_to)
     return 0;
 }
 
+/* Filled from mini-os command line or left as NULL */
+char *vtpm_label;
+
 static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline)
 {
        struct tpmfront_dev* tpm = init_tpmfront(NULL);
-       uint8_t *resp;
+       struct pcr_extend_rsp *resp;
        size_t resplen = 0;
        struct pcr_extend_cmd cmd;
+       int rv;
 
-       /* 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 vtpm_label was specified on the command line, require a vTPM to be
+        * attached and for the domain providing the vTPM to have the given
+        * label.
         */
-       if (!tpm)
+       if (vtpm_label) {
+               char ctx[128];
+               if (!tpm) {
+                       printf("No TPM found and vtpm_label specified, 
aborting!\n");
+                       do_exit();
+               }
+               rv = evtchn_get_peercontext(tpm->evtchn, ctx, sizeof(ctx) - 1);
+               if (rv < 0) {
+                       printf("Could not verify vtpm_label: %d\n", rv);
+                       do_exit();
+               }
+               ctx[127] = 0;
+               rv = strcmp(ctx, vtpm_label);
+               if (rv && vtpm_label[0] == '*') {
+                       int match_len = strlen(vtpm_label) - 1;
+                       int offset = strlen(ctx) - match_len;
+                       if (offset > 0)
+                               rv = strcmp(ctx + offset, vtpm_label + 1);
+               }
+
+               if (rv) {
+                       printf("Mismatched vtpm_label: '%s' != '%s'\n", ctx, 
vtpm_label);
+                       do_exit();
+               }
+       } else if (!tpm) {
                return;
+       }
 
        cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND);
        cmd.size = bswap_32(sizeof(cmd));
@@ -156,15 +193,18 @@ static void tpm_hash2pcr(struct xc_dom_image *dom, char 
*cmdline)
        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);
+       rv = tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), (void*)&resp, 
&resplen);
+       ASSERT(rv == 0 && resp->status == 0);
 
        cmd.pcr = bswap_32(5); // PCR #5 for cmdline
        sha1(cmdline, strlen(cmdline), cmd.hash);
-       tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen);
+       rv = tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), (void*)&resp, 
&resplen);
+       ASSERT(rv == 0 && resp->status == 0);
 
        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);
+       rv = tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), (void*)&resp, 
&resplen);
+       ASSERT(rv == 0 && resp->status == 0);
 
        shutdown_tpmfront(tpm);
 }
diff --git a/stubdom/grub/mini-os.c b/stubdom/grub/mini-os.c
index 9d4bcc7..4fc052a 100644
--- a/stubdom/grub/mini-os.c
+++ b/stubdom/grub/mini-os.c
@@ -735,8 +735,14 @@ void __attribute__ ((noreturn)) grub_reboot (void)
  * for grub's 32bit pointers to work */
 char grub_scratch_mem[SCRATCH_MEMSIZE] __attribute__((aligned(PAGE_SIZE)));
 
-int main(int argc, char *argv[])
+int main(int argc, char **argv)
 {
+    if (argc > 1 && memcmp(argv[1], "--vtpm-label=", 13) == 0) {
+        vtpm_label = argv[1] + 13;
+        argc--;
+        argv++;
+    }
+
     if (argc > 1) {
         strncpy(config_file, argv[1], sizeof(config_file) - 1);
         config_file[sizeof(config_file) - 1] = 0;
diff --git a/stubdom/grub/mini-os.h b/stubdom/grub/mini-os.h
index 6c68441..9ec2bda 100644
--- a/stubdom/grub/mini-os.h
+++ b/stubdom/grub/mini-os.h
@@ -3,3 +3,5 @@ extern struct blkfront_dev **blk_dev;
 extern struct netfront_dev *net_dev;
 extern struct kbdfront_dev *kbd_dev;
 extern struct fbfront_dev *fb_dev;
+
+extern char* vtpm_label;
-- 
1.9.0


_______________________________________________
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®.