Skip to contentSkip to conversation

intel_txt: add s3 userspace memory integrity verification

PATCH NAK Shane Wang 4 participants 9 messages Dec 4, 2009

Subsystems (5)
x86 ACPI MM core Security (LSM) +1 more subsystems
lore
Share & tools
lore

Shane Wang

author
#0 lore raw

PATCH 1/1 intel_txt: add s3 userspace memory integrity verification

This patch added verification for userspace memory integrity after S3 resume. Integrity verification for other memory (say kernel itself) has been done by tboot.

Thanks
Shane

---
 arch/x86/kernel/entry_64.S |   20 +++
 arch/x86/kernel/tboot.c    |  226 +++++++++++++++++++++++++++++++++++
 drivers/acpi/sleep.c       |    3
 include/linux/mm.h         |    8 -
 include/linux/tboot.h      |    3
 security/Kconfig           |    2
 6 files changed, 256 insertions(+), 6 deletions(-)
arch/x86/kernel/entry_64.S +20 -0
diff -r c878d454dc8b arch/x86/kernel/entry_64.S
@@ -1275,6 +1275,26 @@ ENTRY(call_softirq)
 	CFI_ENDPROC
 END(call_softirq)
 
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)
+	CFI_STARTPROC
+	push %rbp
+	CFI_ADJUST_CFA_OFFSET	8
+	CFI_REL_OFFSET	rbp,0
+	mov %rsp, %rbp
+	CFI_DEF_CFA_REGISTER	rbp
+	mov %rsi, %rsp
+	push %rbp
+	call *%rdi
+	leaveq
+	CFI_DEF_CFA_REGISTER	rsp
+	CFI_ADJUST_CFA_OFFSET	-8
+	ret
+	CFI_ENDPROC
+END(tboot_switch_stack_call)
+#endif
+
 #ifdef CONFIG_XEN
 zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
 
arch/x86/kernel/tboot.c +226 -0

262 lines not on this page · raw message

drivers/acpi/sleep.c +2 -1
diff -r c878d454dc8b drivers/acpi/sleep.c
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <linux/reboot.h>
+#include <linux/tboot.h>
 
 #include <asm/io.h>
 
@@ -244,7 +245,7 @@ static int acpi_suspend_enter(suspend_st
 		break;
 
 	case ACPI_STATE_S3:
-		do_suspend_lowlevel();
+		tboot_do_suspend_lowlevel();
 		break;
 	}
 
include/linux/mm.h +4 -4
diff -r c878d454dc8b include/linux/mm.h
@@ -1263,18 +1263,18 @@ static inline void enable_debug_pageallo
 {
 	debug_pagealloc_enabled = 1;
 }
-#ifdef CONFIG_HIBERNATION
+#if defined(CONFIG_HIBERNATION) || defined(CONFIG_INTEL_TXT)
 extern bool kernel_page_present(struct page *page);
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION || CONFIG_INTEL_TXT */
 #else
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable) {}
 static inline void enable_debug_pagealloc(void)
 {
 }
-#ifdef CONFIG_HIBERNATION
+#if defined(CONFIG_HIBERNATION) || defined(CONFIG_INTEL_TXT)
 static inline bool kernel_page_present(struct page *page) { return true; }
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION || CONFIG_INTEL_TXT */
 #endif
 
 extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
include/linux/tboot.h +2 -1
diff -r c878d454dc8b include/linux/tboot.h
@@ -147,7 +147,7 @@ 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_do_suspend_lowlevel(void);
 #else
 
 #define tboot_probe()			do { } while (0)
@@ -156,6 +156,7 @@ 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_do_suspend_lowlevel()	do_suspend_lowlevel()
 
 #endif /* !CONFIG_INTEL_TXT */
 
security/Kconfig +2 -0
diff -r c878d454dc8b security/Kconfig
@@ -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

This patch added verification for userspace memory integrity after S3 resume. Integrity verification for other memory (say kernel itself) has been done by tboot.

arch/x86/kernel/entry_64.S +20 -0
diff -r c878d454dc8b arch/x86/kernel/entry_64.S
@@ -1275,6 +1275,26 @@ ENTRY(call_softirq)
 	CFI_ENDPROC
 END(call_softirq)
 
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)
+	CFI_STARTPROC
+	push %rbp
+	CFI_ADJUST_CFA_OFFSET	8
+	CFI_REL_OFFSET	rbp,0
+	mov %rsp, %rbp
+	CFI_DEF_CFA_REGISTER	rbp
+	mov %rsi, %rsp
+	push %rbp
+	call *%rdi
+	leaveq
+	CFI_DEF_CFA_REGISTER	rsp
+	CFI_ADJUST_CFA_OFFSET	-8
+	ret
+	CFI_ENDPROC
+END(tboot_switch_stack_call)
+#endif
+
 #ifdef CONFIG_XEN
 zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
 
arch/x86/kernel/tboot.c +226 -0

262 lines not on this page · raw message

drivers/acpi/sleep.c +2 -1
diff -r c878d454dc8b drivers/acpi/sleep.c
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <linux/reboot.h>
+#include <linux/tboot.h>
 
 #include <asm/io.h>
 
@@ -244,7 +245,7 @@ static int acpi_suspend_enter(suspend_st
 		break;
 
 	case ACPI_STATE_S3:
-		do_suspend_lowlevel();
+		tboot_do_suspend_lowlevel();
 		break;
 	}
 
include/linux/mm.h +4 -4
diff -r c878d454dc8b include/linux/mm.h
@@ -1263,18 +1263,18 @@ static inline void enable_debug_pageallo
 {
 	debug_pagealloc_enabled = 1;
 }
-#ifdef CONFIG_HIBERNATION
+#if defined(CONFIG_HIBERNATION) || defined(CONFIG_INTEL_TXT)
 extern bool kernel_page_present(struct page *page);
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION || CONFIG_INTEL_TXT */
 #else
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable) {}
 static inline void enable_debug_pagealloc(void)
 {
 }
-#ifdef CONFIG_HIBERNATION
+#if defined(CONFIG_HIBERNATION) || defined(CONFIG_INTEL_TXT)
 static inline bool kernel_page_present(struct page *page) { return true; }
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION || CONFIG_INTEL_TXT */
 #endif
 
 extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
include/linux/tboot.h +2 -1
diff -r c878d454dc8b include/linux/tboot.h
@@ -147,7 +147,7 @@ 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_do_suspend_lowlevel(void);
 #else
 
 #define tboot_probe()			do { } while (0)
@@ -156,6 +156,7 @@ 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_do_suspend_lowlevel()	do_suspend_lowlevel()
 
 #endif /* !CONFIG_INTEL_TXT */
 
security/Kconfig +2 -0
diff -r c878d454dc8b security/Kconfig
@@ -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
#1 lore raw
Quoted 4 lines

This patch added verification for userspace memory integrity after
S3 resume.

It does not work.

Quoted 2 lines

Integrity verification for other memory (say kernel itself) has been done by tboot.

Not true. Kernel uses memory above 4G on x86-64. Including... say console writing functions.

You can patch holes, but without description 'what does this protect against' it is almost impossible to evaluate.

arch/x86/kernel/tboot.c void tboot_sleep(u8 sleep_state, u32 pm1 · line 517

Quoted 13 lines
arch/x86/kernel/tboot.c +13 -0
+void tboot_do_suspend_lowlevel(void)
+{
+	int ret = -1;
+
+	if (!tboot_enabled()) {
+		do_suspend_lowlevel();
+		return;
+	}
+
+	ret = tboot_pre_stack_switch();
+	if (!ret) {
+		tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+					(u64)new_stack_ptr);

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

NAK.
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#2 lore raw
In reply to Shane Wang

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1280

Quoted 10 lines · Shane Wang

diff -r c878d454dc8b arch/x86/kernel/entry_64.S

arch/x86/kernel/entry_64.S +3 -0
@@ -1275,6 +1275,26 @@ ENTRY(call_softirq)
 	CFI_ENDPROC
 END(call_softirq)
 
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)

I would drop the tboot_ prefix, stack switching can be useful for other things too.

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1286

Quoted 6 lines
arch/x86/kernel/entry_64.S +6 -0
+	CFI_STARTPROC
+	push %rbp
+	CFI_ADJUST_CFA_OFFSET	8
+	CFI_REL_OFFSET	rbp,0
+	mov %rsp, %rbp
+	CFI_DEF_CFA_REGISTER	rbp

Did you verify that the dwarf2 really works and gdb can backtrace through it?

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1297

Quoted 11 lines
arch/x86/kernel/entry_64.S +11 -0
+{
+	BUG_ON((new_stack != NULL) || (new_stack_ptr != NULL));
+
+	/*
+	 * as long as thread info is above 4G, then switch stack,
+	 * since tboot can't access >4G stack for MACing
+	 */
+	if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_thread_info())))
+		+ (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+		& 0xffffffff00000000UL))
+		return -1;

All the PFN_*s seem somewhat redundant, it would be easier to keep everything shifted up in the first place.

arch/x86/kernel/entry_64.S ENTRY(call_softirq)

Quoted 4 lines
arch/x86/kernel/entry_64.S +4 -0
+
+	new_stack = (char *)__get_free_pages(GFP_DMA32, IRQ_STACK_ORDER);
+
+	BUG_ON(new_stack == NULL);

GFP_REPEAT at least? BUG_ON is a nasty way to handle out of memory

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+	memset(new_stack, 0, IRQ_STACK_SIZE);

GFP_ZERO

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+	new_stack_ptr = new_stack + IRQ_STACK_SIZE - 64;

Why - 64?

Quoted 14 lines
arch/x86/kernel/entry_64.S +14 -0
+
+	return 0;
+}
+
+static void tboot_post_stack_switch(void)
+{
+	BUG_ON((new_stack == NULL) || (new_stack_ptr == NULL));
+
+	free_pages((unsigned long)new_stack, IRQ_STACK_ORDER);
+	new_stack = NULL;
+	new_stack_ptr = NULL;
+}
+
+extern void tboot_switch_stack_call(void (*target_func)(void), u64 
Quoted 1 line

new_rsp);

Typically those should be in some header.

Quoted 16 lines
arch/x86/kernel/entry_64.S +16 -0
+	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;
+

arch/x86/kernel/entry_64.S

Quoted 10 lines
arch/x86/kernel/entry_64.S +10 -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) {

No locking against memory hotplug? Even if user space is still down doing that would be safer

arch/x86/kernel/entry_64.S

Quoted 9 lines
arch/x86/kernel/entry_64.S +9 -0
+		unsigned long flags;
+
+		pgdat_resize_lock(pgdat, &flags);
+		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;

You probably should consider a faster way to skip holes, doing them piece by piece might well be a performance problem on very holey systems. Especially page_is_ram() is quite slow.

Quoted 16 lines
arch/x86/kernel/entry_64.S +15 -0
+					|| (rend <= paddr))
+					continue;
+				break;
+			}
+
+			if (j == tboot->num_mac_regions) {
+				sg_set_page(sg, page, PAGE_SIZE, 0);
+#ifdef CONFIG_DEBUG_PAGEALLOC
+			/*
+			 * check if the page we are going to MAC is marked as
+			 * present in the kernel page tables.
+			 */
+			if (!kernel_page_present(page)) {
+				kernel_map_pages(page, 1, 1);
+				ret = crypto_hash_update(&desc, sg, 

PAGE_SIZE);

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+				kernel_map_pages(page, 1, 0);

Nasty, might be racy -- better use a separate mapping in this case.

arch/x86/kernel/entry_64.S

Quoted 6 lines
arch/x86/kernel/entry_64.S +3 -0
+#ifdef CONFIG_X86_64
+	/*
+	 * for stack > 4G, we should MAC the stack in the kernel after 

switch,

arch/x86/kernel/entry_64.S +2 -0
+	 * for stack < 4G, the stack is MACed by tboot
+	 */

This special case seems quite ugly, with all its ifdefs and lots of special code.
Can't you just MAC the stack always? Shouldn't be that expensive.

arch/x86/kernel/entry_64.S

Quoted 7 lines
arch/x86/kernel/entry_64.S +7 -0
+	else
+#endif
+		add_mac_region(virt_to_phys(current_thread_info()),
+				THREAD_SIZE); /* < 4G */
+
+	/* MAC userspace memory not handled by tboot */
+	get_random_bytes(tboot->s3_key, sizeof(tboot->s3_key));

That's early in boot isn't it? It's quite doubtful you'll get anything even vaguely random out of get_random_bytes at this point, may be not even the time.

Quoted 8 lines
arch/x86/kernel/entry_64.S +5 -0
 	}
 
 	tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+static void tboot_sx_resume(void)
+{
+	vmac_t mac;

arch/x86/kernel/entry_64.S

Quoted 10 lines
arch/x86/kernel/entry_64.S +10 -0
+
+	if (tboot_gen_mem_integrity(tboot->s3_key, &mac))
+		panic("tboot: vmac generation failed\n");
+	else if (mac != mem_mac)
+#ifdef CONFIG_DEBUG_KERNEL
+		pr_debug("tboot: memory integrity %llx -> %llx\n",
+				mem_mac, mac);
+#else
+		panic("tboot: memory integrity was lost on resume\n");
+#endif

I don't think DEBUG_KERNEL is supposed to be used like this, better probably a separate option if it makes sense.

Typical problem with panics at this point: is anything even visible on the screen?

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1280

Quoted 4 lines
arch/x86/kernel/entry_64.S +3 -0
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)

Hmm, I thought i had seen that earlier already? Is it a copy?

BTW there's no reason all of this has to be in entry*.S, that file is already quite crowded.

The patch is duplicated here?

-Andi

#3 lore raw
In reply to Shane Wang

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1280

Quoted 10 lines · Shane Wang

diff -r c878d454dc8b arch/x86/kernel/entry_64.S

arch/x86/kernel/entry_64.S +3 -0
@@ -1275,6 +1275,26 @@ ENTRY(call_softirq)
 	CFI_ENDPROC
 END(call_softirq)
 
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)

I would drop the tboot_ prefix, stack switching can be useful for other things too.

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1286

Quoted 6 lines
arch/x86/kernel/entry_64.S +6 -0
+	CFI_STARTPROC
+	push %rbp
+	CFI_ADJUST_CFA_OFFSET	8
+	CFI_REL_OFFSET	rbp,0
+	mov %rsp, %rbp
+	CFI_DEF_CFA_REGISTER	rbp

Did you verify that the dwarf2 really works and gdb can backtrace through it?

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1297

Quoted 11 lines
arch/x86/kernel/entry_64.S +11 -0
+{
+	BUG_ON((new_stack != NULL) || (new_stack_ptr != NULL));
+
+	/*
+	 * as long as thread info is above 4G, then switch stack,
+	 * since tboot can't access >4G stack for MACing
+	 */
+	if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_thread_info())))
+		+ (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+		& 0xffffffff00000000UL))
+		return -1;

All the PFN_*s seem somewhat redundant, it would be easier to keep everything shifted up in the first place.

arch/x86/kernel/entry_64.S ENTRY(call_softirq)

Quoted 4 lines
arch/x86/kernel/entry_64.S +4 -0
+
+	new_stack = (char *)__get_free_pages(GFP_DMA32, IRQ_STACK_ORDER);
+
+	BUG_ON(new_stack == NULL);

GFP_REPEAT at least? BUG_ON is a nasty way to handle out of memory

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+	memset(new_stack, 0, IRQ_STACK_SIZE);

GFP_ZERO

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+	new_stack_ptr = new_stack + IRQ_STACK_SIZE - 64;

Why - 64?

Quoted 14 lines
arch/x86/kernel/entry_64.S +14 -0
+
+	return 0;
+}
+
+static void tboot_post_stack_switch(void)
+{
+	BUG_ON((new_stack == NULL) || (new_stack_ptr == NULL));
+
+	free_pages((unsigned long)new_stack, IRQ_STACK_ORDER);
+	new_stack = NULL;
+	new_stack_ptr = NULL;
+}
+
+extern void tboot_switch_stack_call(void (*target_func)(void), u64 
Quoted 1 line

new_rsp);

Typically those should be in some header.

Quoted 16 lines
arch/x86/kernel/entry_64.S +16 -0
+	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;
+

arch/x86/kernel/entry_64.S

Quoted 10 lines
arch/x86/kernel/entry_64.S +10 -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) {

No locking against memory hotplug? Even if user space is still down doing that would be safer

arch/x86/kernel/entry_64.S

Quoted 9 lines
arch/x86/kernel/entry_64.S +9 -0
+		unsigned long flags;
+
+		pgdat_resize_lock(pgdat, &flags);
+		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;

You probably should consider a faster way to skip holes, doing them piece by piece might well be a performance problem on very holey systems. Especially page_is_ram() is quite slow.

Quoted 16 lines
arch/x86/kernel/entry_64.S +15 -0
+					|| (rend <= paddr))
+					continue;
+				break;
+			}
+
+			if (j == tboot->num_mac_regions) {
+				sg_set_page(sg, page, PAGE_SIZE, 0);
+#ifdef CONFIG_DEBUG_PAGEALLOC
+			/*
+			 * check if the page we are going to MAC is marked as
+			 * present in the kernel page tables.
+			 */
+			if (!kernel_page_present(page)) {
+				kernel_map_pages(page, 1, 1);
+				ret = crypto_hash_update(&desc, sg, 

PAGE_SIZE);

arch/x86/kernel/entry_64.S

Quoted 1 line
arch/x86/kernel/entry_64.S +1 -0
+				kernel_map_pages(page, 1, 0);

Nasty, might be racy -- better use a separate mapping in this case.

arch/x86/kernel/entry_64.S

Quoted 6 lines
arch/x86/kernel/entry_64.S +3 -0
+#ifdef CONFIG_X86_64
+	/*
+	 * for stack > 4G, we should MAC the stack in the kernel after 

switch,

arch/x86/kernel/entry_64.S +2 -0
+	 * for stack < 4G, the stack is MACed by tboot
+	 */

This special case seems quite ugly, with all its ifdefs and lots of special code.
Can't you just MAC the stack always? Shouldn't be that expensive.

arch/x86/kernel/entry_64.S

Quoted 7 lines
arch/x86/kernel/entry_64.S +7 -0
+	else
+#endif
+		add_mac_region(virt_to_phys(current_thread_info()),
+				THREAD_SIZE); /* < 4G */
+
+	/* MAC userspace memory not handled by tboot */
+	get_random_bytes(tboot->s3_key, sizeof(tboot->s3_key));

That's early in boot isn't it? It's quite doubtful you'll get anything even vaguely random out of get_random_bytes at this point, may be not even the time.

Quoted 8 lines
arch/x86/kernel/entry_64.S +5 -0
 	}
 
 	tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+static void tboot_sx_resume(void)
+{
+	vmac_t mac;

arch/x86/kernel/entry_64.S

Quoted 10 lines
arch/x86/kernel/entry_64.S +10 -0
+
+	if (tboot_gen_mem_integrity(tboot->s3_key, &mac))
+		panic("tboot: vmac generation failed\n");
+	else if (mac != mem_mac)
+#ifdef CONFIG_DEBUG_KERNEL
+		pr_debug("tboot: memory integrity %llx -> %llx\n",
+				mem_mac, mac);
+#else
+		panic("tboot: memory integrity was lost on resume\n");
+#endif

I don't think DEBUG_KERNEL is supposed to be used like this, better probably a separate option if it makes sense.

Typical problem with panics at this point: is anything even visible on the screen?

arch/x86/kernel/entry_64.S ENTRY(call_softirq) · line 1280

Quoted 4 lines
arch/x86/kernel/entry_64.S +3 -0
+#ifdef CONFIG_INTEL_TXT
+/* void tboot_switch_stack_call(void (*target_func)(void), u64 new_rsp) */
+ENTRY(tboot_switch_stack_call)

Hmm, I thought i had seen that earlier already? Is it a copy?

BTW there's no reason all of this has to be in entry*.S, that file is already quite crowded.

The patch is duplicated here?

-Andi

#4 lore raw
In reply to Shane Wang
Quoted 4 lines

This patch added verification for userspace memory integrity after
S3 resume.

It does not work.

Quoted 2 lines

Integrity verification for other memory (say kernel itself) has been done by tboot.

Not true. Kernel uses memory above 4G on x86-64. Including... say console writing functions.

You can patch holes, but without description 'what does this protect against' it is almost impossible to evaluate.

arch/x86/kernel/tboot.c void tboot_sleep(u8 sleep_state, u32 pm1 · line 517

Quoted 13 lines
arch/x86/kernel/tboot.c +13 -0
+void tboot_do_suspend_lowlevel(void)
+{
+	int ret = -1;
+
+	if (!tboot_enabled()) {
+		do_suspend_lowlevel();
+		return;
+	}
+
+	ret = tboot_pre_stack_switch();
+	if (!ret) {
+		tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+					(u64)new_stack_ptr);

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

NAK.
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#5 lore raw
Quoted 6 lines

From: Pavel Machek [mailto:[email protected]]
Sent: Friday, December 04, 2009 12:29 AM

Quoted 2 lines

This patch added verification for userspace memory integrity after
S3 resume.

Quoted 7 lines

It does not work.

Quoted 2 lines

Integrity verification for other memory (say kernel itself) has been done by tboot.

Not true. Kernel uses memory above 4G on x86-64. Including... say console writing functions.

I've responded to that in your previous email thread, so let's keep the technical discussion of what is MAC'ed to just that one thread.

Quoted 13 lines

You can patch holes, but without description 'what does this protect against' it is almost impossible to evaluate.

Quoted 9 lines
arch/x86/kernel/tboot.c +9 -0
+void tboot_do_suspend_lowlevel(void)
+{
+   int ret = -1;
+
+   if (!tboot_enabled()) {
+           do_suspend_lowlevel();
+           return;
+   }
+
Quoted 8 lines

arch/x86/kernel/tboot.c void tboot_sleep(u8 sleep_state, u32 pm1 · line 517

Quoted 4 lines
arch/x86/kernel/tboot.c +4 -0
+   ret = tboot_pre_stack_switch();
+   if (!ret) {
+           tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+                                   (u64)new_stack_ptr);

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

Really the only requirement is (as discussed in the previous thread) that it only use code and data within [_text, _end - _text]--do you think that this really needs to be called out? do_suspend_lowlevel() is a very simple function that has just the one (resume path) call to another simple function--it doesn't seem likely that it would violate this.

Quoted 7 lines

NAK.
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

#6 lore raw
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
arch/x86/kernel/tboot.c +5 -0
+
+   ret = tboot_pre_stack_switch();
+   if (!ret) {
+           tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+                                   (u64)new_stack_ptr);
Quoted 6 lines
Quoted 3 lines

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

Really the only requirement is (as discussed in the previous thread) that it only use code and data within [_text, _end - _text]--do you think that this really needs to be called out? do_suspend_lowlevel() is a very simple function that has just the one (resume path) call to another simple function--it doesn't seem likely that it would violate this.

Resume code is already pretty tricky, and you add yet another layer of trickery. Yes, it needs to be properly documented.

And... how does it interact with restore_processor_state? I don't think do_suspend_lowlevel is as simple as you think...
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#7 lore raw
In reply to Cihula, Joseph
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
arch/x86/kernel/tboot.c +5 -0
+
+   ret = tboot_pre_stack_switch();
+   if (!ret) {
+           tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+                                   (u64)new_stack_ptr);
Quoted 6 lines
Quoted 3 lines

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

Really the only requirement is (as discussed in the previous thread) that it only use code and data within [_text, _end - _text]--do you think that this really needs to be called out? do_suspend_lowlevel() is a very simple function that has just the one (resume path) call to another simple function--it doesn't seem likely that it would violate this.

Resume code is already pretty tricky, and you add yet another layer of trickery. Yes, it needs to be properly documented.

And... how does it interact with restore_processor_state? I don't think do_suspend_lowlevel is as simple as you think...
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#8 lore raw
In reply to Pavel Machek
Quoted 6 lines

From: Pavel Machek [mailto:[email protected]]
Sent: Friday, December 04, 2009 12:29 AM

Quoted 2 lines

This patch added verification for userspace memory integrity after
S3 resume.

Quoted 7 lines

It does not work.

Quoted 2 lines

Integrity verification for other memory (say kernel itself) has been done by tboot.

Not true. Kernel uses memory above 4G on x86-64. Including... say console writing functions.

I've responded to that in your previous email thread, so let's keep the technical discussion of what is MAC'ed to just that one thread.

Quoted 13 lines

You can patch holes, but without description 'what does this protect against' it is almost impossible to evaluate.

Quoted 9 lines
arch/x86/kernel/tboot.c +9 -0
+void tboot_do_suspend_lowlevel(void)
+{
+   int ret = -1;
+
+   if (!tboot_enabled()) {
+           do_suspend_lowlevel();
+           return;
+   }
+
Quoted 8 lines

arch/x86/kernel/tboot.c void tboot_sleep(u8 sleep_state, u32 pm1 · line 517

Quoted 4 lines
arch/x86/kernel/tboot.c +4 -0
+   ret = tboot_pre_stack_switch();
+   if (!ret) {
+           tboot_switch_stack_call(tboot_do_suspend_lowlevel_call,
+                                   (u64)new_stack_ptr);

...and here you add requirements to suspend_lowlevel that were not there before. ("May not act on unchecksummed memory"), without documenting them.

Really the only requirement is (as discussed in the previous thread) that it only use code and data within [_text, _end - _text]--do you think that this really needs to be called out? do_suspend_lowlevel() is a very simple function that has just the one (resume path) call to another simple function--it doesn't seem likely that it would violate this.

Quoted 7 lines

NAK.
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html