This patch added verification for userspace memory integrity after s3 resume. Integrity verification for other memory (say kernel itself) has been done by tboot. Signed-off-by: Shane Wang Signed-off-by: Joseph Cihula diff -r 42870e183bd5 arch/x86/kernel/tboot.c --- a/arch/x86/kernel/tboot.c Fri Sep 25 06:06:39 2009 -0400 +++ b/arch/x86/kernel/tboot.c Fri Sep 25 11:03:04 2009 -0400 @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -30,12 +31,17 @@ #include #include #include +#include + +#include +#include #include #include #include #include #include +#include #include #include #include @@ -168,6 +174,80 @@ static void tboot_create_trampoline(void map_base, map_size); } +static vmac_t mem_mac; +static struct crypto_hash *tfm; + +static int tboot_gen_mem_integrity(const uint8_t key[], vmac_t *mac) +{ + int i, j, ret; + pg_data_t *pgdat; + struct hash_desc desc; + struct scatterlist sg[1]; + struct page *page; + uint64_t paddr, rstart, rend; + unsigned long pfn; + uint8_t zeroed_key[VMAC_KEY_LEN]; + + if (!tfm) + tfm = crypto_alloc_hash("vmac(aes)", 0, CRYPTO_ALG_ASYNC); + + if (IS_ERR(tfm)) { + tfm = NULL; + return -ENOMEM; + } + + desc.tfm = tfm; + desc.flags = 0; + + sg_init_table(sg, 1); + + ret = crypto_hash_init(&desc); + if (ret) + return ret; + ret = crypto_hash_setkey(desc.tfm, key, VMAC_KEY_LEN); + if (ret) + return ret; + + for_each_online_pgdat(pgdat) { + for (i = 0, pfn = pgdat->node_start_pfn; + i < pgdat->node_spanned_pages; + i++, pfn = pgdat->node_start_pfn + i) { + + if (!pfn_valid(pfn) || !page_is_ram(pfn)) + continue; + + page = pfn_to_page(pfn); + paddr = page_to_phys(page); + + /* If pg will be MACed by tboot, no need to MAC here */ + for (j = 0; j < tboot->num_mac_regions; j++) { + rstart = tboot->mac_regions[j].start; + rend = rstart + tboot->mac_regions[j].size; + if (((paddr + PAGE_SIZE) <= rstart) + || (rend <= paddr)) + continue; + break; + } + + if (j == tboot->num_mac_regions) { + sg_set_page(sg, page, PAGE_SIZE, 0); + ret = crypto_hash_update(&desc, sg, PAGE_SIZE); + if (ret) + return ret; + } + } + } + ret = crypto_hash_final(&desc, (uint8_t *)mac); + if (ret) + return ret; + + /* Clean the key */ + memset(zeroed_key, 0, sizeof(zeroed_key)); + crypto_hash_setkey(desc.tfm, zeroed_key, VMAC_KEY_LEN); + + return 0; +} + #ifdef CONFIG_ACPI_SLEEP static void add_mac_region(phys_addr_t start, unsigned long size) @@ -197,6 +277,16 @@ static int tboot_setup_sleep(void) /* kernel code + data + bss */ add_mac_region(virt_to_phys(_text), _end - _text); + /* stack */ + add_mac_region(virt_to_phys(current_thread_info()), THREAD_SIZE); + + /* MAC userspace memory not handled by tboot */ + get_random_bytes(tboot->s3_key, sizeof(tboot->s3_key)); + if (tboot_gen_mem_integrity(tboot->s3_key, &mem_mac)) { + panic("tboot: vmac generation failed\n"); + return -1; + } + tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address; return 0; @@ -212,6 +302,68 @@ static int tboot_setup_sleep(void) } #endif + +static struct thread_info *low_ti, *current_ti; + +static void tboot_do_stack_switch(struct thread_info *new_ti, + struct thread_info *old_ti) +{ + memcpy(new_ti, old_ti, THREAD_SIZE); +#ifdef CONFIG_X86_32 + asm volatile ( + " and %0, %%esp; " + " add %1, %%esp; " + : : "i" (THREAD_SIZE - 1), "r" (new_ti)); +#else + asm volatile ( + " and %0, %%rsp; " + " add %1, %%rsp; " + : : "i" (THREAD_SIZE - 1), "r" (new_ti)); + percpu_write(kernel_stack, (unsigned long)new_ti - + KERNEL_STACK_OFFSET + THREAD_SIZE); +#endif + current->stack = new_ti; +} + +void tboot_switch_stack(void) +{ + if (!tboot_enabled()) + return; + + current_ti = current_thread_info(); + + /* If thread info is above 4G, then switch stack */ + if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti))) + + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT)) + & 0xffffffff00000000ULL)) + return; + + if (low_ti == NULL) + low_ti = (struct thread_info *) + __get_free_pages(GFP_DMA32, THREAD_ORDER); + + tboot_do_stack_switch(low_ti, current_ti); +} + +void tboot_restore_stack(void) +{ + if (!tboot_enabled()) + return; + + if (current_ti == NULL) + BUG(); + + /* If thread info is above 4G, then restore stack */ + if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti))) + + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT)) + & 0xffffffff00000000ULL)) + return; + + if (low_ti == NULL) + BUG(); + + tboot_do_stack_switch(current_ti, low_ti); +} void tboot_shutdown(u32 shutdown_type) { @@ -292,6 +444,24 @@ void tboot_sleep(u8 sleep_state, u32 pm1 } tboot_shutdown(acpi_shutdown_map[sleep_state]); +} + +void tboot_sx_resume(void) +{ + vmac_t mac; + + if (!tboot_enabled()) + return; + + if (tboot_gen_mem_integrity(tboot->s3_key, &mac)) + panic("tboot: vmac generation failed\n"); + else if (mac != mem_mac) + panic("tboot: memory integrity was lost on resume\n"); + else + pr_info("memory integrity OK\n"); + + /* Clean s3_key */ + memset(tboot->s3_key, 0, sizeof(tboot->s3_key)); } static atomic_t ap_wfs_count; diff -r 42870e183bd5 drivers/acpi/sleep.c --- a/drivers/acpi/sleep.c Fri Sep 25 06:06:39 2009 -0400 +++ b/drivers/acpi/sleep.c Fri Sep 25 11:03:04 2009 -0400 @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -244,7 +245,10 @@ static int acpi_suspend_enter(suspend_st break; case ACPI_STATE_S3: + tboot_switch_stack(); do_suspend_lowlevel(); + tboot_sx_resume(); + tboot_restore_stack(); break; } diff -r 42870e183bd5 include/linux/tboot.h --- a/include/linux/tboot.h Fri Sep 25 06:06:39 2009 -0400 +++ b/include/linux/tboot.h Fri Sep 25 11:03:04 2009 -0400 @@ -147,7 +147,9 @@ extern struct acpi_table_header *tboot_g extern struct acpi_table_header *tboot_get_dmar_table( struct acpi_table_header *dmar_tbl); extern int tboot_force_iommu(void); - +extern void tboot_sx_resume(void); +extern void tboot_switch_stack(void); +extern void tboot_restore_stack(void); #else #define tboot_probe() do { } while (0) @@ -156,6 +158,9 @@ extern int tboot_force_iommu(void); do { } while (0) #define tboot_get_dmar_table(dmar_tbl) (dmar_tbl) #define tboot_force_iommu() 0 +#define tboot_sx_resume() do { } while (0) +#define tboot_switch_stack() do { } while (0) +#define tboot_restore_stack() do { } while (0) #endif /* !CONFIG_INTEL_TXT */ diff -r 42870e183bd5 security/Kconfig --- a/security/Kconfig Fri Sep 25 06:06:39 2009 -0400 +++ b/security/Kconfig Fri Sep 25 11:03:04 2009 -0400 @@ -116,6 +116,8 @@ config INTEL_TXT config INTEL_TXT bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" depends on HAVE_INTEL_TXT + select CRYPTO_VMAC + select CRYPTO_AES help This option enables support for booting the kernel with the Trusted Boot (tboot) module. This will utilize