Skip to content

Commit

Permalink
arch/x86: process DRTM policy
Browse files Browse the repository at this point in the history
Signed-off-by: Sergii Dmytruk <[email protected]>
  • Loading branch information
SergiiDmytruk committed Jan 7, 2024
1 parent 62863e0 commit 81ac532
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 0 deletions.
12 changes: 12 additions & 0 deletions xen/arch/x86/include/asm/intel_txt.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <xen/multiboot.h>

/*
* TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
*/
Expand Down Expand Up @@ -380,4 +382,14 @@ extern void txt_restore_mtrrs(bool e820_verbose);
void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size,
uint32_t type, uint8_t *log_data, unsigned log_data_size);

/* Measures essential parts of SLR table before making use of them. */
void tpm_measure_slrt(void);

/* Takes measurements of DRTM policy entries except for MBI and SLRT which
* should have been measured by the time this is called. Also performs sanity
* checks of the policy and panics on failure. In particular, the function
* verifies that DRTM is consistent with MultibootInfo (MBI) (the MBI address
* is assumed to be virtual). */
void tpm_process_drtm_policy(const multiboot_info_t *mbi);

#endif /* __ASSEMBLY__ */
9 changes: 9 additions & 0 deletions xen/arch/x86/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,9 @@ void __init noreturn __start_xen(unsigned long mbi_p)
{
/* Prepare for TXT-related code. */
map_txt_mem_regions();
/* Measure SLRT here because it gets used by init_e820(), the rest is
* measured below by tpm_process_drtm_policy(). */
tpm_measure_slrt();
/* Reserve TXT heap and SINIT. */
protect_txt_mem_regions();
}
Expand All @@ -1194,6 +1197,12 @@ void __init noreturn __start_xen(unsigned long mbi_p)
/* Create a temporary copy of the E820 map. */
memcpy(&boot_e820, &e820, sizeof(e820));

/* Process all yet unmeasured DRTM entries after E820 initialization to not
* do this while memory is uncached (too slow). This must also happen before
* fields of Multiboot modules change their format below. */
if ( slaunch_active )
tpm_process_drtm_policy(mbi);

/* Early kexec reservation (explicit static start address). */
nr_pages = 0;
for ( i = 0; i < e820.nr_map; i++ )
Expand Down
196 changes: 196 additions & 0 deletions xen/arch/x86/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,4 +963,200 @@ void __stdcall tpm_extend_mbi(uint32_t *mbi)
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi,
TXT_EVTYPE_SLAUNCH, NULL, 0);
}
#else
static struct slr_table *slr_get_table(void)
{
struct txt_os_mle_data *os_mle;
struct slr_table *slrt;

os_mle = txt_os_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));

map_l2(os_mle->slrt, PAGE_SIZE);
slrt = __va(os_mle->slrt);

if ( slrt->magic != SLR_TABLE_MAGIC )
panic("SLRT has invalid magic value: %#08x!\n", slrt->magic);
/* XXX: are newer revisions allowed? */
if ( slrt->revision != SLR_TABLE_REVISION )
panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision);
if ( slrt->architecture != SLR_INTEL_TXT )
panic("SLRT is for unexpected architecture: %#04x!\n",
slrt->architecture);
if ( slrt->size > slrt->max_size )
panic("SLRT is larger than its max size: %#08x > %#08x!\n",
slrt->size, slrt->max_size);

if ( slrt->size > PAGE_SIZE )
map_l2(os_mle->slrt, slrt->size);

return slrt;
}

void tpm_measure_slrt(void)
{
struct slr_table *slrt = slr_get_table();

if ( slrt->revision == 1 ) {
/* In revision one of the SLRT, only Intel info table is measured. */
struct slr_entry_intel_info *intel_info =
(void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
if ( intel_info == NULL )
panic("SLRT is missing Intel-specific information!\n");

tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info,
sizeof(*intel_info), TXT_EVTYPE_SLAUNCH, NULL, 0);
} else {
/*
* slr_get_table() checks that the revision is valid, so we must not
* get here unless the code is wrong.
*/
panic("Unhandled SLRT revision: %d!\n", slrt->revision);
}
}

static struct slr_entry_policy *slr_get_policy(struct slr_table *slrt)
{
struct slr_entry_policy *policy;

policy = (struct slr_entry_policy *)
slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DRTM_POLICY);
if (policy == NULL)
panic("SLRT is missing DRTM policy!\n");

/* XXX: are newer revisions allowed? */
if ( policy->revision != SLR_POLICY_REVISION )
panic("DRTM policy in SLRT is of unsupported revision: %#04x!\n",
slrt->revision);

return policy;
}

static void check_drtm_policy(struct slr_table *slrt,
struct slr_entry_policy *policy,
struct slr_policy_entry *policy_entry,
const multiboot_info_t *mbi)
{
uint32_t i;
module_t *mods;
uint32_t num_mod_entries;

if ( policy->nr_entries < 2 )
panic("DRTM policy in SLRT contains less than 2 entries (%d)!\n",
policy->nr_entries);

/* MBI policy entry must be the first one, so that measuring order matches
* policy order. */
if ( policy_entry[0].entity_type != SLR_ET_MULTIBOOT2_INFO )
panic("First entry of DRTM policy in SLRT is not MBI: %#04x!\n",
policy_entry[0].entity_type);
if ( policy_entry[0].pcr != DRTM_DATA_PCR )
panic("MBI was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR,
policy_entry[0].pcr);

/* SLRT policy entry must be the second one. */
if ( policy_entry[1].entity_type != SLR_ET_SLRT )
panic("Second entry of DRTM policy in SLRT is not SLRT: %#04x!\n",
policy_entry[1].entity_type);
if ( policy_entry[1].pcr != DRTM_DATA_PCR )
panic("SLRT was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR,
policy_entry[1].pcr);
if ( policy_entry[1].entity != (uint64_t)__pa(slrt) )
panic("SLRT address (%#08lx) differes from its DRTM entry (%#08lx)\n",
__pa(slrt), policy_entry[1].entity);

mods = __va(mbi->mods_addr);
for ( i = 0; i < mbi->mods_count; i++ ) {
uint16_t j;
uint64_t start = mods[i].mod_start;
uint64_t size = mods[i].mod_end - mods[i].mod_start;

for ( j = 0; j < policy->nr_entries; j++ ) {
if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE )
continue;

if ( policy_entry[j].entity == start &&
policy_entry[j].size == size )
break;
}

if ( j >= policy->nr_entries ) {
panic("Couldn't find Multiboot module \"%s\" (at %d) in DRTM of Secure Launch\n",
(const char *)__va(mods[i].string), i);
}
}

num_mod_entries = 0;
for ( i = 0; i < policy->nr_entries; i++ ) {
if ( policy_entry[i].entity_type == SLR_ET_MULTIBOOT2_MODULE )
num_mod_entries++;
}

if ( mbi->mods_count != num_mod_entries ) {
panic("Unexpected number of Multiboot modules: %d instead of %d\n",
(int)mbi->mods_count, (int)num_mod_entries);
}
}

void tpm_process_drtm_policy(const multiboot_info_t *mbi)
{
struct slr_table *slrt;
struct slr_entry_policy *policy;
struct slr_policy_entry *policy_entry;
uint16_t i;

slrt = slr_get_table();

policy = slr_get_policy(slrt);
policy_entry = (struct slr_policy_entry *)
((uint8_t *)policy + sizeof(*policy));

check_drtm_policy(slrt, policy, policy_entry, mbi);
/* MBI was measured in tpm_extend_mbi(). */
policy_entry[0].flags |= SLR_POLICY_FLAG_MEASURED;
/* SLRT was measured in tpm_measure_slrt(). */
policy_entry[1].flags |= SLR_POLICY_FLAG_MEASURED;

for ( i = 2; i < policy->nr_entries; i++ ) {
uint64_t start = policy_entry[i].entity;
uint64_t size = policy_entry[i].size;

/* No already measured entries are expected here. */
if ( policy_entry[i].flags & SLR_POLICY_FLAG_MEASURED )
panic("DRTM entry at %d was measured out of order!\n", i);

switch ( policy_entry[i].entity_type ) {
case SLR_ET_MULTIBOOT2_INFO:
panic("Duplicated MBI entry in DRTM of Secure Launch at %d\n", i);
case SLR_ET_SLRT:
panic("Duplicated SLRT entry in DRTM of Secure Launch at %d\n", i);

case SLR_ET_UNSPECIFIED:
case SLR_ET_BOOT_PARAMS:
case SLR_ET_SETUP_DATA:
case SLR_ET_CMDLINE:
case SLR_ET_UEFI_MEMMAP:
case SLR_ET_RAMDISK:
case SLR_ET_MULTIBOOT2_MODULE:
case SLR_ET_TXT_OS2MLE:
/* Measure this entry below. */
break;

case SLR_ET_UNUSED:
/* Skip this entry. */
continue;
}

if ( policy_entry[i].flags & SLR_POLICY_IMPLICIT_SIZE )
panic("Unexpected implicitly-sized DRTM entry of Secure Launch at %d\n",
i);

map_l2(start, size);
tpm_hash_extend(DRTM_LOC, policy_entry[i].pcr, __va(start), size,
TXT_EVTYPE_SLAUNCH, (uint8_t *)policy_entry[i].evt_info,
strnlen(policy_entry[i].evt_info,
TPM_EVENT_INFO_LENGTH));

policy_entry[i].flags |= SLR_POLICY_FLAG_MEASURED;
}
}
#endif

0 comments on commit 81ac532

Please sign in to comment.