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@tycho.nsa.gov>
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
Daniel De Graaf authored and Ian Campbell committed 2014-04-23 11:58:15 +01:00
1 parent f00b68e706
commit 331d4b0eb8
3 files changed
+58 -10

No files matched your search

+49 -9
View File
@@ -68,6 +68,14 @@ struct pcr_extend_cmd {
unsigned char hash[20]; unsigned char hash[20];
} __attribute__((packed)); } __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 /* Not imported from polarssl's header since the prototype unhelpfully defines
* the input as unsigned char, which causes pointer type mismatches */ * the input as unsigned char, which causes pointer type mismatches */
void sha1(const void *input, size_t ilen, unsigned char output[20]); 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; 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) static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline)
{ {
struct tpmfront_dev* tpm = init_tpmfront(NULL); struct tpmfront_dev* tpm = init_tpmfront(NULL);
uint8_t *resp; struct pcr_extend_rsp *resp;
size_t resplen = 0; size_t resplen = 0;
struct pcr_extend_cmd cmd; 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 * If vtpm_label was specified on the command line, require a vTPM to be
* to boot without a TPM (or with a TPM that has not been sent any * attached and for the domain providing the vTPM to have the given
* measurements, which could allow forging the measurements). * 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; return;
}
cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND); cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND);
cmd.size = bswap_32(sizeof(cmd)); 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 cmd.pcr = bswap_32(4); // PCR #4 for kernel
sha1(dom->kernel_blob, dom->kernel_size, cmd.hash); 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 cmd.pcr = bswap_32(5); // PCR #5 for cmdline
sha1(cmdline, strlen(cmdline), cmd.hash); 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 cmd.pcr = bswap_32(5); // PCR #5 for initrd
sha1(dom->ramdisk_blob, dom->ramdisk_size, cmd.hash); 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); shutdown_tpmfront(tpm);
} }
+7 -1
View File
@@ -735,8 +735,14 @@ void __attribute__ ((noreturn)) grub_reboot (void)
* for grub's 32bit pointers to work */ * for grub's 32bit pointers to work */
char grub_scratch_mem[SCRATCH_MEMSIZE] __attribute__((aligned(PAGE_SIZE))); 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) { if (argc > 1) {
strncpy(config_file, argv[1], sizeof(config_file) - 1); strncpy(config_file, argv[1], sizeof(config_file) - 1);
config_file[sizeof(config_file) - 1] = 0; config_file[sizeof(config_file) - 1] = 0;
+2
View File
@@ -3,3 +3,5 @@ extern struct blkfront_dev **blk_dev;
extern struct netfront_dev *net_dev; extern struct netfront_dev *net_dev;
extern struct kbdfront_dev *kbd_dev; extern struct kbdfront_dev *kbd_dev;
extern struct fbfront_dev *fb_dev; extern struct fbfront_dev *fb_dev;
extern char* vtpm_label;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.