On Wed, Nov 27, 2019 at 08:19:30AM -0000, tip-bot2 for Andy Lutomirski wrote: > The following commit has been merged into the x86/urgent branch of tip: > > Commit-ID: b09511c253e5c739a60952b97c071a93e92b2e88 > Gitweb: https://git.kernel.org/tip/b09511c253e5c739a60952b97c071a93e92b2e88 > Author: Andy Lutomirski <luto@xxxxxxxxxx> > AuthorDate: Sun, 24 Nov 2019 21:18:04 -08:00 > Committer: Ingo Molnar <mingo@xxxxxxxxxx> > CommitterDate: Tue, 26 Nov 2019 21:53:34 +01:00 > > lkdtm: Add a DOUBLE_FAULT crash type on x86 > > The DOUBLE_FAULT crash does INT $8, which is a decent approximation > of a double fault. This is useful for testing the double fault > handling. Use it like: > > Signed-off-by: Andy Lutomirski <luto@xxxxxxxxxx> > Cc: Kees Cook <keescook@xxxxxxxxxxxx> > Cc: Arnd Bergmann <arnd@xxxxxxxx> > Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > Cc: Borislav Petkov <bp@xxxxxxxxx> > Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> > Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx> > --- > drivers/misc/lkdtm/bugs.c | 39 +++++++++++++++++++++++++++++++++++++- > drivers/misc/lkdtm/core.c | 3 +++- > drivers/misc/lkdtm/lkdtm.h | 3 +++- > 3 files changed, 45 insertions(+) > > diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c > index 7284a22..a4fdad0 100644 > --- a/drivers/misc/lkdtm/bugs.c > +++ b/drivers/misc/lkdtm/bugs.c > @@ -12,6 +12,10 @@ > #include <linux/sched/task_stack.h> > #include <linux/uaccess.h> > > +#ifdef CONFIG_X86_32 > +#include <asm/desc.h> > +#endif > + > struct lkdtm_list { > struct list_head node; > }; > @@ -337,3 +341,38 @@ void lkdtm_UNSET_SMEP(void) > pr_err("FAIL: this test is x86_64-only\n"); > #endif > } > + > +#ifdef CONFIG_X86_32 > +void lkdtm_DOUBLE_FAULT(void) > +{ > + /* > + * Trigger #DF by setting the stack limit to zero. This clobbers > + * a GDT TLS slot, which is okay because the current task will die > + * anyway due to the double fault. > + */ > + struct desc_struct d = { > + .type = 3, /* expand-up, writable, accessed data */ > + .p = 1, /* present */ > + .d = 1, /* 32-bit */ > + .g = 0, /* limit in bytes */ > + .s = 1, /* not system */ > + }; > + > + local_irq_disable(); > + write_gdt_entry(get_cpu_gdt_rw(smp_processor_id()), > + GDT_ENTRY_TLS_MIN, &d, DESCTYPE_S); > + > + /* > + * Put our zero-limit segment in SS and then trigger a fault. The > + * 4-byte access to (%esp) will fault with #SS, and the attempt to > + * deliver the fault will recursively cause #SS and result in #DF. > + * This whole process happens while NMIs and MCEs are blocked by the > + * MOV SS window. This is nice because an NMI with an invalid SS > + * would also double-fault, resulting in the NMI or MCE being lost. > + */ > + asm volatile ("movw %0, %%ss; addl $0, (%%esp)" :: > + "r" ((unsigned short)(GDT_ENTRY_TLS_MIN << 3))); > + > + panic("tried to double fault but didn't die\n"); I'll modify this in some later patches, but I prefer the #ifdef inside the function so that all tests are visible on all architectures/configurations. And it should not panic on a test failure, it should continue (see the others) with something like: pr_err("FAIL: did not double fault!\n"); E.g. an external system monitor would see the double-fault and the panic as both causing a system reboot, but only the double-fault should do that. > +} > +#endif > diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c > index cbc4c90..ee0d6e7 100644 > --- a/drivers/misc/lkdtm/core.c > +++ b/drivers/misc/lkdtm/core.c > @@ -171,6 +171,9 @@ static const struct crashtype crashtypes[] = { > CRASHTYPE(USERCOPY_KERNEL_DS), > CRASHTYPE(STACKLEAK_ERASING), > CRASHTYPE(CFI_FORWARD_PROTO), > +#ifdef CONFIG_X86_32 > + CRASHTYPE(DOUBLE_FAULT), > +#endif And then ifdefs aren't needed here either. > }; > > > diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h > index ab446e0..c56d23e 100644 > --- a/drivers/misc/lkdtm/lkdtm.h > +++ b/drivers/misc/lkdtm/lkdtm.h > @@ -28,6 +28,9 @@ void lkdtm_CORRUPT_USER_DS(void); > void lkdtm_STACK_GUARD_PAGE_LEADING(void); > void lkdtm_STACK_GUARD_PAGE_TRAILING(void); > void lkdtm_UNSET_SMEP(void); > +#ifdef CONFIG_X86_32 > +void lkdtm_DOUBLE_FAULT(void); > +#endif Same. > > /* lkdtm_heap.c */ > void __init lkdtm_heap_init(void); -- Kees Cook