Pull x86 fixes from Ingo Molnar: "Various fixes: - Fix the PAT performance regression that downgraded write-combining device memory regions to uncached. - There's been a number of bugs in 32-bit double fault handling - hopefully all fixed now. - Fix an LDT crash - Fix an FPU over-optimization that broke with GCC9 code optimizations. - Misc cleanups" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mm/pat: Fix off-by-one bugs in interval tree search x86/ioperm: Save an indentation level in tss_update_io_bitmap() x86/fpu: Don't cache access to fpu_fpregs_owner_ctx x86/entry/32: Remove unused 'restore_all_notrace' local label x86/ptrace: Document FSBASE and GSBASE ABI oddities x86/ptrace: Remove set_segment_reg() implementations for current x86/traps: die() instead of panicking on a double fault x86/doublefault/32: Rewrite the x86_32 #DF handler and unify with 64-bit x86/doublefault/32: Move #DF stack and TSS to cpu_entry_area x86/doublefault/32: Rename doublefault.c to doublefault_32.c x86/traps: Disentangle the 32-bit and 64-bit doublefault code lkdtm: Add a DOUBLE_FAULT crash type on x86 selftests/x86/single_step_syscall: Check SYSENTER directly x86/mm/32: Sync only to VMALLOC_END in vmalloc_sync_all()
Unified · Split
| @@ -117,7 +117,7 @@ config DEBUG_WX · 116 unmodified lines | |||
| 117 | 117 | ||
| 118 | config DOUBLEFAULT | 118 | config DOUBLEFAULT |
| 119 | default y | 119 | default y |
| 120 | bool "Enable doublefault exception handler" if EXPERT | 120 | bool "Enable doublefault exception handler" if EXPERT && X86_32 |
| 121 | ---help--- | 121 | ---help--- |
| 122 | This option allows trapping of rare doublefault exceptions that | 122 | This option allows trapping of rare doublefault exceptions that |
| 123 | would otherwise cause a system to silently reboot. Disabling this | 123 | would otherwise cause a system to silently reboot. Disabling this |
| @@ -1090,7 +1090,6 @@ SYM_FUNC_START(entry_INT80_32) · 1089 unmodified lines | |||
| 1090 | restore_all: | 1090 | restore_all: |
| 1091 | TRACE_IRQS_IRET | 1091 | TRACE_IRQS_IRET |
| 1092 | SWITCH_TO_ENTRY_STACK | 1092 | SWITCH_TO_ENTRY_STACK |
| 1093 | .Lrestore_all_notrace: | ||
| 1094 | CHECK_AND_APPLY_ESPFIX | 1093 | CHECK_AND_APPLY_ESPFIX |
| 1095 | .Lrestore_nocheck: | 1094 | .Lrestore_nocheck: |
| 1096 | /* Switch back to user CR3 */ | 1095 | /* Switch back to user CR3 */ |
| @@ -1537,6 +1536,48 @@ SYM_CODE_START(debug) · 440 unmodified lines | |||
| 1537 | jmp common_exception | 1536 | jmp common_exception |
| 1538 | SYM_CODE_END(debug) | 1537 | SYM_CODE_END(debug) |
| 1539 | 1538 | ||
| 1539 | #ifdef CONFIG_DOUBLEFAULT | ||
| 1540 | SYM_CODE_START(double_fault) | ||
| 1541 | 1: | ||
| 1542 | /* | ||
| 1543 | * This is a task gate handler, not an interrupt gate handler. | ||
| 1544 | * The error code is on the stack, but the stack is otherwise | ||
| 1545 | * empty. Interrupts are off. Our state is sane with the following | ||
| 1546 | * exceptions: | ||
| 1547 | * | ||
| 1548 | * - CR0.TS is set. "TS" literally means "task switched". | ||
| 1549 | * - EFLAGS.NT is set because we're a "nested task". | ||
| 1550 | * - The doublefault TSS has back_link set and has been marked busy. | ||
| 1551 | * - TR points to the doublefault TSS and the normal TSS is busy. | ||
| 1552 | * - CR3 is the normal kernel PGD. This would be delightful, except | ||
| 1553 | * that the CPU didn't bother to save the old CR3 anywhere. This | ||
| 1554 | * would make it very awkward to return back to the context we came | ||
| 1555 | * from. | ||
| 1556 | * | ||
| 1557 | * The rest of EFLAGS is sanitized for us, so we don't need to | ||
| 1558 | * worry about AC or DF. | ||
| 1559 | * | ||
| 1560 | * Don't even bother popping the error code. It's always zero, | ||
| 1561 | * and ignoring it makes us a bit more robust against buggy | ||
| 1562 | * hypervisor task gate implementations. | ||
| 1563 | * | ||
| 1564 | * We will manually undo the task switch instead of doing a | ||
| 1565 | * task-switching IRET. | ||
| 1566 | */ | ||
| 1567 | |||
| 1568 | clts /* clear CR0.TS */ | ||
| 1569 | pushl $X86_EFLAGS_FIXED | ||
| 1570 | popfl /* clear EFLAGS.NT */ | ||
| 1571 | |||
| 1572 | call doublefault_shim | ||
| 1573 | |||
| 1574 | /* We don't support returning, so we have no IRET here. */ | ||
| 1575 | 1: | ||
| 1576 | hlt | ||
| 1577 | jmp 1b | ||
| 1578 | SYM_CODE_END(double_fault) | ||
| 1579 | #endif | ||
| 1580 | |||
| 1540 | /* | 1581 | /* |
| 1541 | * NMI is doubly nasty. It can happen on the first instruction of | 1582 | * NMI is doubly nasty. It can happen on the first instruction of |
| 1542 | * entry_SYSENTER_32 (just like #DB), but it can also interrupt the beginning | 1583 | * entry_SYSENTER_32 (just like #DB), but it can also interrupt the beginning |
| @@ -65,6 +65,13 @@ enum exception_stack_ordering { · 64 unmodified lines | |||
| 65 | 65 | ||
| 66 | #endif | 66 | #endif |
| 67 | 67 | ||
| 68 | #ifdef CONFIG_X86_32 | ||
| 69 | struct doublefault_stack { | ||
| 70 | unsigned long stack[(PAGE_SIZE - sizeof(struct x86_hw_tss)) / sizeof(unsigned long)]; | ||
| 71 | struct x86_hw_tss tss; | ||
| 72 | } __aligned(PAGE_SIZE); | ||
| 73 | #endif | ||
| 74 | |||
| 68 | /* | 75 | /* |
| 69 | * cpu_entry_area is a percpu region that contains things needed by the CPU | 76 | * cpu_entry_area is a percpu region that contains things needed by the CPU |
| 70 | * and early entry/exit code. Real types aren't used for all fields here | 77 | * and early entry/exit code. Real types aren't used for all fields here |
| @@ -86,6 +93,11 @@ struct cpu_entry_area { · 15 unmodified lines | |||
| 86 | #endif | 93 | #endif |
| 87 | struct entry_stack_page entry_stack_page; | 94 | struct entry_stack_page entry_stack_page; |
| 88 | 95 | ||
| 96 | #ifdef CONFIG_X86_32 | ||
| 97 | char guard_doublefault_stack[PAGE_SIZE]; | ||
| 98 | struct doublefault_stack doublefault_stack; | ||
| 99 | #endif | ||
| 100 | |||
| 89 | /* | 101 | /* |
| 90 | * On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because | 102 | * On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because |
| 91 | * we need task switches to work, and task switches write to the TSS. | 103 | * we need task switches to work, and task switches write to the TSS. |
| @@ -0,0 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef _ASM_X86_DOUBLEFAULT_H | ||
| 3 | #define _ASM_X86_DOUBLEFAULT_H | ||
| 4 | |||
| 5 | #if defined(CONFIG_X86_32) && defined(CONFIG_DOUBLEFAULT) | ||
| 6 | extern void doublefault_init_cpu_tss(void); | ||
| 7 | #else | ||
| 8 | static inline void doublefault_init_cpu_tss(void) | ||
| 9 | { | ||
| 10 | } | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #endif /* _ASM_X86_DOUBLEFAULT_H */ | ||
| @@ -509,7 +509,7 @@ static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu) · 508 unmodified lines | |||
| 509 | 509 | ||
| 510 | static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu) | 510 | static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu) |
| 511 | { | 511 | { |
| 512 | return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu; | 512 | return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu; |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | /* | 515 | /* |
| @@ -41,10 +41,11 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */ · 40 unmodified lines | |||
| 41 | #endif | 41 | #endif |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * Define this here and validate with BUILD_BUG_ON() in pgtable_32.c | 44 | * This is an upper bound on sizeof(struct cpu_entry_area) / PAGE_SIZE. |
| 45 | * to avoid include recursion hell | 45 | * Define this here and validate with BUILD_BUG_ON() in cpu_entry_area.c |
| 46 | * to avoid include recursion hell. | ||
| 46 | */ | 47 | */ |
| 47 | #define CPU_ENTRY_AREA_PAGES (NR_CPUS * 41) | 48 | #define CPU_ENTRY_AREA_PAGES (NR_CPUS * 43) |
| 48 | 49 | ||
| 49 | /* The +1 is for the readonly IDT page: */ | 50 | /* The +1 is for the readonly IDT page: */ |
| 50 | #define CPU_ENTRY_AREA_BASE \ | 51 | #define CPU_ENTRY_AREA_BASE \ |
| @@ -166,7 +166,6 @@ enum cpuid_regs_idx { · 165 unmodified lines | |||
| 166 | extern struct cpuinfo_x86 boot_cpu_data; | 166 | extern struct cpuinfo_x86 boot_cpu_data; |
| 167 | extern struct cpuinfo_x86 new_cpu_data; | 167 | extern struct cpuinfo_x86 new_cpu_data; |
| 168 | 168 | ||
| 169 | extern struct x86_hw_tss doublefault_tss; | ||
| 170 | extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; | 169 | extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; |
| 171 | extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS]; | 170 | extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS]; |
| 172 | 171 | ||
| @@ -997,7 +996,6 @@ bool xen_set_default_idle(void); · 824 unmodified lines | |||
| 997 | #endif | 996 | #endif |
| 998 | 997 | ||
| 999 | void stop_this_cpu(void *dummy); | 998 | void stop_this_cpu(void *dummy); |
| 1000 | void df_debug(struct pt_regs *regs, long error_code); | ||
| 1001 | void microcode_check(void); | 999 | void microcode_check(void); |
| 1002 | 1000 | ||
| 1003 | enum l1tf_mitigations { | 1001 | enum l1tf_mitigations { |
| @@ -69,6 +69,9 @@ dotraplinkage void do_overflow(struct pt_regs *regs, long error_code); · 68 unmodified lines | |||
| 69 | dotraplinkage void do_bounds(struct pt_regs *regs, long error_code); | 69 | dotraplinkage void do_bounds(struct pt_regs *regs, long error_code); |
| 70 | dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code); | 70 | dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code); |
| 71 | dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code); | 71 | dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code); |
| 72 | #if defined(CONFIG_X86_64) || defined(CONFIG_DOUBLEFAULT) | ||
| 73 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2); | ||
| 74 | #endif | ||
| 72 | dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *regs, long error_code); | 75 | dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *regs, long error_code); |
| 73 | dotraplinkage void do_invalid_TSS(struct pt_regs *regs, long error_code); | 76 | dotraplinkage void do_invalid_TSS(struct pt_regs *regs, long error_code); |
| 74 | dotraplinkage void do_segment_not_present(struct pt_regs *regs, long error_code); | 77 | dotraplinkage void do_segment_not_present(struct pt_regs *regs, long error_code); |
| @@ -100,7 +100,9 @@ obj-$(CONFIG_KEXEC_FILE) += kexec-bzimage64.o · 99 unmodified lines | |||
| 100 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o | 100 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o |
| 101 | obj-y += kprobes/ | 101 | obj-y += kprobes/ |
| 102 | obj-$(CONFIG_MODULES) += module.o | 102 | obj-$(CONFIG_MODULES) += module.o |
| 103 | obj-$(CONFIG_DOUBLEFAULT) += doublefault.o | 103 | ifeq ($(CONFIG_X86_32),y) |
| 104 | obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o | ||
| 105 | endif | ||
| 104 | obj-$(CONFIG_KGDB) += kgdb.o | 106 | obj-$(CONFIG_KGDB) += kgdb.o |
| 105 | obj-$(CONFIG_VM86) += vm86_32.o | 107 | obj-$(CONFIG_VM86) += vm86_32.o |
| 106 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 108 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <asm/stackprotector.h> | 24 | #include <asm/stackprotector.h> |
| 25 | #include <asm/perf_event.h> | 25 | #include <asm/perf_event.h> |
| 26 | #include <asm/mmu_context.h> | 26 | #include <asm/mmu_context.h> |
| 27 | #include <asm/doublefault.h> | ||
| 27 | #include <asm/archrandom.h> | 28 | #include <asm/archrandom.h> |
| 28 | #include <asm/hypervisor.h> | 29 | #include <asm/hypervisor.h> |
| 29 | #include <asm/processor.h> | 30 | #include <asm/processor.h> |
| @@ -1814,8 +1815,6 @@ static inline void tss_setup_ist(struct tss_struct *tss) · 1784 unmodified lines | |||
| 1814 | tss->x86_tss.ist[IST_INDEX_MCE] = __this_cpu_ist_top_va(MCE); | 1815 | tss->x86_tss.ist[IST_INDEX_MCE] = __this_cpu_ist_top_va(MCE); |
| 1815 | } | 1816 | } |
| 1816 | 1817 | ||
| 1817 | static inline void gdt_setup_doublefault_tss(int cpu) { } | ||
| 1818 | |||
| 1819 | #else /* CONFIG_X86_64 */ | 1818 | #else /* CONFIG_X86_64 */ |
| 1820 | 1819 | ||
| 1821 | static inline void setup_getcpu(int cpu) { } | 1820 | static inline void setup_getcpu(int cpu) { } |
| @@ -1827,13 +1826,6 @@ static inline void ucode_cpu_init(int cpu) · 5 unmodified lines | |||
| 1827 | 1826 | ||
| 1828 | static inline void tss_setup_ist(struct tss_struct *tss) { } | 1827 | static inline void tss_setup_ist(struct tss_struct *tss) { } |
| 1829 | 1828 | ||
| 1830 | static inline void gdt_setup_doublefault_tss(int cpu) | ||
| 1831 | { | ||
| 1832 | #ifdef CONFIG_DOUBLEFAULT | ||
| 1833 | /* Set up the doublefault TSS pointer in the GDT */ | ||
| 1834 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); | ||
| 1835 | #endif | ||
| 1836 | } | ||
| 1837 | #endif /* !CONFIG_X86_64 */ | 1829 | #endif /* !CONFIG_X86_64 */ |
| 1838 | 1830 | ||
| 1839 | static inline void tss_setup_io_bitmap(struct tss_struct *tss) | 1831 | static inline void tss_setup_io_bitmap(struct tss_struct *tss) |
| @@ -1923,7 +1915,7 @@ void cpu_init(void) · 83 unmodified lines | |||
| 1923 | clear_all_debug_regs(); | 1915 | clear_all_debug_regs(); |
| 1924 | dbg_restore_debug_regs(); | 1916 | dbg_restore_debug_regs(); |
| 1925 | 1917 | ||
| 1926 | gdt_setup_doublefault_tss(cpu); | 1918 | doublefault_init_cpu_tss(); |
| 1927 | 1919 | ||
| 1928 | fpu__init_cpu(); | 1920 | fpu__init_cpu(); |
| 1929 | 1921 | ||
| @@ -1,86 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/mm.h> | ||
| 3 | #include <linux/sched.h> | ||
| 4 | #include <linux/sched/debug.h> | ||
| 5 | #include <linux/init_task.h> | ||
| 6 | #include <linux/fs.h> | ||
| 7 | |||
| 8 | #include <linux/uaccess.h> | ||
| 9 | #include <asm/pgtable.h> | ||
| 10 | #include <asm/processor.h> | ||
| 11 | #include <asm/desc.h> | ||
| 12 | |||
| 13 | #ifdef CONFIG_X86_32 | ||
| 14 | |||
| 15 | #define DOUBLEFAULT_STACKSIZE (1024) | ||
| 16 | static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; | ||
| 17 | #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) | ||
| 18 | |||
| 19 | #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM) | ||
| 20 | |||
| 21 | static void doublefault_fn(void) | ||
| 22 | { | ||
| 23 | struct desc_ptr gdt_desc = {0, 0}; | ||
| 24 | unsigned long gdt, tss; | ||
| 25 | |||
| 26 | native_store_gdt(&gdt_desc); | ||
| 27 | gdt = gdt_desc.address; | ||
| 28 | |||
| 29 | printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); | ||
| 30 | |||
| 31 | if (ptr_ok(gdt)) { | ||
| 32 | gdt += GDT_ENTRY_TSS << 3; | ||
| 33 | tss = get_desc_base((struct desc_struct *)gdt); | ||
| 34 | printk(KERN_EMERG "double fault, tss at %08lx\n", tss); | ||
| 35 | |||
| 36 | if (ptr_ok(tss)) { | ||
| 37 | struct x86_hw_tss *t = (struct x86_hw_tss *)tss; | ||
| 38 | |||
| 39 | printk(KERN_EMERG "eip = %08lx, esp = %08lx\n", | ||
| 40 | t->ip, t->sp); | ||
| 41 | |||
| 42 | printk(KERN_EMERG "eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", | ||
| 43 | t->ax, t->bx, t->cx, t->dx); | ||
| 44 | printk(KERN_EMERG "esi = %08lx, edi = %08lx\n", | ||
| 45 | t->si, t->di); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | for (;;) | ||
| 50 | cpu_relax(); | ||
| 51 | } | ||
| 52 | |||
| 53 | struct x86_hw_tss doublefault_tss __cacheline_aligned = { | ||
| 54 | .sp0 = STACK_START, | ||
| 55 | .ss0 = __KERNEL_DS, | ||
| 56 | .ldt = 0, | ||
| 57 | .io_bitmap_base = IO_BITMAP_OFFSET_INVALID, | ||
| 58 | |||
| 59 | .ip = (unsigned long) doublefault_fn, | ||
| 60 | /* 0x2 bit is always set */ | ||
| 61 | .flags = X86_EFLAGS_SF | 0x2, | ||
| 62 | .sp = STACK_START, | ||
| 63 | .es = __USER_DS, | ||
| 64 | .cs = __KERNEL_CS, | ||
| 65 | .ss = __KERNEL_DS, | ||
| 66 | .ds = __USER_DS, | ||
| 67 | .fs = __KERNEL_PERCPU, | ||
| 68 | #ifndef CONFIG_X86_32_LAZY_GS | ||
| 69 | .gs = __KERNEL_STACK_CANARY, | ||
| 70 | #endif | ||
| 71 | |||
| 72 | .__cr3 = __pa_nodebug(swapper_pg_dir), | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* dummy for do_double_fault() call */ | ||
| 76 | void df_debug(struct pt_regs *regs, long error_code) {} | ||
| 77 | |||
| 78 | #else /* !CONFIG_X86_32 */ | ||
| 79 | |||
| 80 | void df_debug(struct pt_regs *regs, long error_code) | ||
| 81 | { | ||
| 82 | pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code); | ||
| 83 | show_regs(regs); | ||
| 84 | panic("Machine halted."); | ||
| 85 | } | ||
| 86 | #endif | ||
| @@ -0,0 +1,136 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/mm.h> | ||
| 3 | #include <linux/sched.h> | ||
| 4 | #include <linux/sched/debug.h> | ||
| 5 | #include <linux/init_task.h> | ||
| 6 | #include <linux/fs.h> | ||
| 7 | |||
| 8 | #include <linux/uaccess.h> | ||
| 9 | #include <asm/pgtable.h> | ||
| 10 | #include <asm/processor.h> | ||
| 11 | #include <asm/desc.h> | ||
| 12 | #include <asm/traps.h> | ||
| 13 | |||
| 14 | extern void double_fault(void); | ||
| 15 | #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM) | ||
| 16 | |||
| 17 | #define TSS(x) this_cpu_read(cpu_tss_rw.x86_tss.x) | ||
| 18 | |||
| 19 | static void set_df_gdt_entry(unsigned int cpu); | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Called by double_fault with CR0.TS and EFLAGS.NT cleared. The CPU thinks | ||
| 23 | * we're running the doublefault task. Cannot return. | ||
| 24 | */ | ||
| 25 | asmlinkage notrace void __noreturn doublefault_shim(void) | ||
| 26 | { | ||
| 27 | unsigned long cr2; | ||
| 28 | struct pt_regs regs; | ||
| 29 | |||
| 30 | BUILD_BUG_ON(sizeof(struct doublefault_stack) != PAGE_SIZE); | ||
| 31 | |||
| 32 | cr2 = native_read_cr2(); | ||
| 33 | |||
| 34 | /* Reset back to the normal kernel task. */ | ||
| 35 | force_reload_TR(); | ||
| 36 | set_df_gdt_entry(smp_processor_id()); | ||
| 37 | |||
| 38 | trace_hardirqs_off(); | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Fill in pt_regs. A downside of doing this in C is that the unwinder | ||
| 42 | * won't see it (no ENCODE_FRAME_POINTER), so a nested stack dump | ||
| 43 | * won't successfully unwind to the source of the double fault. | ||
| 44 | * The main dump from do_double_fault() is fine, though, since it | ||
| 45 | * uses these regs directly. | ||
| 46 | * | ||
| 47 | * If anyone ever cares, this could be moved to asm. | ||
| 48 | */ | ||
| 49 | regs.ss = TSS(ss); | ||
| 50 | regs.__ssh = 0; | ||
| 51 | regs.sp = TSS(sp); | ||
| 52 | regs.flags = TSS(flags); | ||
| 53 | regs.cs = TSS(cs); | ||
| 54 | /* We won't go through the entry asm, so we can leave __csh as 0. */ | ||
| 55 | regs.__csh = 0; | ||
| 56 | regs.ip = TSS(ip); | ||
| 57 | regs.orig_ax = 0; | ||
| 58 | regs.gs = TSS(gs); | ||
| 59 | regs.__gsh = 0; | ||
| 60 | regs.fs = TSS(fs); | ||
| 61 | regs.__fsh = 0; | ||
| 62 | regs.es = TSS(es); | ||
| 63 | regs.__esh = 0; | ||
| 64 | regs.ds = TSS(ds); | ||
| 65 | regs.__dsh = 0; | ||
| 66 | regs.ax = TSS(ax); | ||
| 67 | regs.bp = TSS(bp); | ||
| 68 | regs.di = TSS(di); | ||
| 69 | regs.si = TSS(si); | ||
| 70 | regs.dx = TSS(dx); | ||
| 71 | regs.cx = TSS(cx); | ||
| 72 | regs.bx = TSS(bx); | ||
| 73 | |||
| 74 | do_double_fault(®s, 0, cr2); | ||
| 75 | |||
| 76 | /* | ||
| 77 | * x86_32 does not save the original CR3 anywhere on a task switch. | ||
| 78 | * This means that, even if we wanted to return, we would need to find | ||
| 79 | * some way to reconstruct CR3. We could make a credible guess based | ||
| 80 | * on cpu_tlbstate, but that would be racy and would not account for | ||
| 81 | * PTI. | ||
| 82 | * | ||
| 83 | * Instead, don't bother. We can return through | ||
| 84 | * rewind_stack_do_exit() instead. | ||
| 85 | */ | ||
| 86 | panic("cannot return from double fault\n"); | ||
| 87 | } | ||
| 88 | NOKPROBE_SYMBOL(doublefault_shim); | ||
| 89 | |||
| 90 | DEFINE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack) = { | ||
| 91 | .tss = { | ||
| 92 | /* | ||
| 93 | * No sp0 or ss0 -- we never run CPL != 0 with this TSS | ||
| 94 | * active. sp is filled in later. | ||
| 95 | */ | ||
| 96 | .ldt = 0, | ||
| 97 | .io_bitmap_base = IO_BITMAP_OFFSET_INVALID, | ||
| 98 | |||
| 99 | .ip = (unsigned long) double_fault, | ||
| 100 | .flags = X86_EFLAGS_FIXED, | ||
| 101 | .es = __USER_DS, | ||
| 102 | .cs = __KERNEL_CS, | ||
| 103 | .ss = __KERNEL_DS, | ||
| 104 | .ds = __USER_DS, | ||
| 105 | .fs = __KERNEL_PERCPU, | ||
| 106 | #ifndef CONFIG_X86_32_LAZY_GS | ||
| 107 | .gs = __KERNEL_STACK_CANARY, | ||
| 108 | #endif | ||
| 109 | |||
| 110 | .__cr3 = __pa_nodebug(swapper_pg_dir), | ||
| 111 | }, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static void set_df_gdt_entry(unsigned int cpu) | ||
| 115 | { | ||
| 116 | /* Set up doublefault TSS pointer in the GDT */ | ||
| 117 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, | ||
| 118 | &get_cpu_entry_area(cpu)->doublefault_stack.tss); | ||
| 119 | |||
| 120 | } | ||
| 121 | |||
| 122 | void doublefault_init_cpu_tss(void) | ||
| 123 | { | ||
| 124 | unsigned int cpu = smp_processor_id(); | ||
| 125 | struct cpu_entry_area *cea = get_cpu_entry_area(cpu); | ||
| 126 | |||
| 127 | /* | ||
| 128 | * The linker isn't smart enough to initialize percpu variables that | ||
| 129 | * point to other places in percpu space. | ||
| 130 | */ | ||
| 131 | this_cpu_write(doublefault_stack.tss.sp, | ||
| 132 | (unsigned long)&cea->doublefault_stack.stack + | ||
| 133 | sizeof(doublefault_stack.stack)); | ||
| 134 | |||
| 135 | set_df_gdt_entry(cpu); | ||
| 136 | } | ||
| @@ -29,6 +29,9 @@ const char *stack_type_name(enum stack_type type) · 28 unmodified lines | |||
| 29 | if (type == STACK_TYPE_ENTRY) | 29 | if (type == STACK_TYPE_ENTRY) |
| 30 | return "ENTRY_TRAMPOLINE"; | 30 | return "ENTRY_TRAMPOLINE"; |
| 31 | 31 | ||
| 32 | if (type == STACK_TYPE_EXCEPTION) | ||
| 33 | return "#DF"; | ||
| 34 | |||
| 32 | return NULL; | 35 | return NULL; |
| 33 | } | 36 | } |
| 34 | 37 | ||
| @@ -82,6 +85,30 @@ static bool in_softirq_stack(unsigned long *stack, struct stack_info *info) · 47 unmodified lines | |||
| 82 | return true; | 85 | return true; |
| 83 | } | 86 | } |
| 84 | 87 | ||
| 88 | static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info) | ||
| 89 | { | ||
| 90 | #ifdef CONFIG_DOUBLEFAULT | ||
| 91 | struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id()); | ||
| 92 | struct doublefault_stack *ss = &cea->doublefault_stack; | ||
| 93 | |||
| 94 | void *begin = ss->stack; | ||
| 95 | void *end = begin + sizeof(ss->stack); | ||
| 96 | |||
| 97 | if ((void *)stack < begin || (void *)stack >= end) | ||
| 98 | return false; | ||
| 99 | |||
| 100 | info->type = STACK_TYPE_EXCEPTION; | ||
| 101 | info->begin = begin; | ||
| 102 | info->end = end; | ||
| 103 | info->next_sp = (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp); | ||
| 104 | |||
| 105 | return true; | ||
| 106 | #else | ||
| 107 | return false; | ||
| 108 | #endif | ||
| 109 | } | ||
| 110 | |||
| 111 | |||
| 85 | int get_stack_info(unsigned long *stack, struct task_struct *task, | 112 | int get_stack_info(unsigned long *stack, struct task_struct *task, |
| 86 | struct stack_info *info, unsigned long *visit_mask) | 113 | struct stack_info *info, unsigned long *visit_mask) |
| 87 | { | 114 | { |
| @@ -105,6 +132,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, · 17 unmodified lines | |||
| 105 | if (in_softirq_stack(stack, info)) | 132 | if (in_softirq_stack(stack, info)) |
| 106 | goto recursion_check; | 133 | goto recursion_check; |
| 107 | 134 | ||
| 135 | if (in_doublefault_stack(stack, info)) | ||
| 136 | goto recursion_check; | ||
| 137 | |||
| 108 | goto unknown; | 138 | goto unknown; |
| 109 | 139 | ||
| 110 | recursion_check: | 140 | recursion_check: |
| @@ -377,37 +377,37 @@ static void tss_copy_io_bitmap(struct tss_struct *tss, struct io_bitmap *iobm) · 376 unmodified lines | |||
| 377 | void tss_update_io_bitmap(void) | 377 | void tss_update_io_bitmap(void) |
| 378 | { | 378 | { |
| 379 | struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw); | 379 | struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw); |
| 380 | struct thread_struct *t = ¤t->thread; | ||
| 380 | u16 *base = &tss->x86_tss.io_bitmap_base; | 381 | u16 *base = &tss->x86_tss.io_bitmap_base; |
| 381 | 382 | ||
| 382 | if (test_thread_flag(TIF_IO_BITMAP)) { | 383 | if (!test_thread_flag(TIF_IO_BITMAP)) { |
| 383 | struct thread_struct *t = ¤t->thread; | 384 | tss_invalidate_io_bitmap(tss); |
| 384 | 385 | return; | |
| 385 | if (IS_ENABLED(CONFIG_X86_IOPL_IOPERM) && t->iopl_emul == 3) { | 386 | } |
| 386 | *base = IO_BITMAP_OFFSET_VALID_ALL; | 387 | |
| 387 | } else { | 388 | if (IS_ENABLED(CONFIG_X86_IOPL_IOPERM) && t->iopl_emul == 3) { |
| 388 | struct io_bitmap *iobm = t->io_bitmap; | 389 | *base = IO_BITMAP_OFFSET_VALID_ALL; |
| 389 | /* | 390 | } else { |
| 390 | * Only copy bitmap data when the sequence number | 391 | struct io_bitmap *iobm = t->io_bitmap; |
| 391 | * differs. The update time is accounted to the | 392 | |
| 392 | * incoming task. | ||
| 393 | */ | ||
| 394 | if (tss->io_bitmap.prev_sequence != iobm->sequence) | ||
| 395 | tss_copy_io_bitmap(tss, iobm); | ||
| 396 | |||
| 397 | /* Enable the bitmap */ | ||
| 398 | *base = IO_BITMAP_OFFSET_VALID_MAP; | ||
| 399 | } | ||
| 400 | /* | 393 | /* |
| 401 | * Make sure that the TSS limit is covering the io bitmap. | 394 | * Only copy bitmap data when the sequence number differs. The |
| 402 | * It might have been cut down by a VMEXIT to 0x67 which | 395 | * update time is accounted to the incoming task. |
| 403 | * would cause a subsequent I/O access from user space to | ||
| 404 | * trigger a #GP because tbe bitmap is outside the TSS | ||
| 405 | * limit. | ||
| 406 | */ | 396 | */ |
| 407 | refresh_tss_limit(); | 397 | if (tss->io_bitmap.prev_sequence != iobm->sequence) |
| 408 | } else { | 398 | tss_copy_io_bitmap(tss, iobm); |
| 409 | tss_invalidate_io_bitmap(tss); | 399 | |
| 400 | /* Enable the bitmap */ | ||
| 401 | *base = IO_BITMAP_OFFSET_VALID_MAP; | ||
| 410 | } | 402 | } |
| 403 | |||
| 404 | /* | ||
| 405 | * Make sure that the TSS limit is covering the IO bitmap. It might have | ||
| 406 | * been cut down by a VMEXIT to 0x67 which would cause a subsequent I/O | ||
| 407 | * access from user space to trigger a #GP because tbe bitmap is outside | ||
| 408 | * the TSS limit. | ||
| 409 | */ | ||
| 410 | refresh_tss_limit(); | ||
| 411 | } | 411 | } |
| 412 | #else /* CONFIG_X86_IOPL_IOPERM */ | 412 | #else /* CONFIG_X86_IOPL_IOPERM */ |
| 413 | static inline void switch_to_bitmap(unsigned long tifp) { } | 413 | static inline void switch_to_bitmap(unsigned long tifp) { } |
| @@ -182,6 +182,9 @@ static u16 get_segment_reg(struct task_struct *task, unsigned long offset) · 181 unmodified lines | |||
| 182 | static int set_segment_reg(struct task_struct *task, | 182 | static int set_segment_reg(struct task_struct *task, |
| 183 | unsigned long offset, u16 value) | 183 | unsigned long offset, u16 value) |
| 184 | { | 184 | { |
| 185 | if (WARN_ON_ONCE(task == current)) | ||
| 186 | return -EIO; | ||
| 187 | |||
| 185 | /* | 188 | /* |
| 186 | * The value argument was already truncated to 16 bits. | 189 | * The value argument was already truncated to 16 bits. |
| 187 | */ | 190 | */ |
| @@ -209,10 +212,7 @@ static int set_segment_reg(struct task_struct *task, · 21 unmodified lines | |||
| 209 | break; | 212 | break; |
| 210 | 213 | ||
| 211 | case offsetof(struct user_regs_struct, gs): | 214 | case offsetof(struct user_regs_struct, gs): |
| 212 | if (task == current) | 215 | task_user_gs(task) = value; |
| 213 | set_user_gs(task_pt_regs(task), value); | ||
| 214 | else | ||
| 215 | task_user_gs(task) = value; | ||
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | return 0; | 218 | return 0; |
| @@ -272,32 +272,41 @@ static u16 get_segment_reg(struct task_struct *task, unsigned long offset) · 53 unmodified lines | |||
| 272 | static int set_segment_reg(struct task_struct *task, | 272 | static int set_segment_reg(struct task_struct *task, |
| 273 | unsigned long offset, u16 value) | 273 | unsigned long offset, u16 value) |
| 274 | { | 274 | { |
| 275 | if (WARN_ON_ONCE(task == current)) | ||
| 276 | return -EIO; | ||
| 277 | |||
| 275 | /* | 278 | /* |
| 276 | * The value argument was already truncated to 16 bits. | 279 | * The value argument was already truncated to 16 bits. |
| 277 | */ | 280 | */ |
| 278 | if (invalid_selector(value)) | 281 | if (invalid_selector(value)) |
| 279 | return -EIO; | 282 | return -EIO; |
| 280 | 283 | ||
| 284 | /* | ||
| 285 | * This function has some ABI oddities. | ||
| 286 | * | ||
| 287 | * A 32-bit ptracer probably expects that writing FS or GS will change | ||
| 288 | * FSBASE or GSBASE respectively. In the absence of FSGSBASE support, | ||
| 289 | * this code indeed has that effect. When FSGSBASE is added, this | ||
| 290 | * will require a special case. | ||
| 291 | * | ||
| 292 | * For existing 64-bit ptracers, writing FS or GS *also* currently | ||
| 293 | * changes the base if the selector is nonzero the next time the task | ||
| 294 | * is run. This behavior may not be needed, and trying to preserve it | ||
| 295 | * when FSGSBASE is added would be complicated at best. | ||
| 296 | */ | ||
| 297 | |||
| 281 | switch (offset) { | 298 | switch (offset) { |
| 282 | case offsetof(struct user_regs_struct,fs): | 299 | case offsetof(struct user_regs_struct,fs): |
| 283 | task->thread.fsindex = value; | 300 | task->thread.fsindex = value; |
| 284 | if (task == current) | ||
| 285 | loadsegment(fs, task->thread.fsindex); | ||
| 286 | break; | 301 | break; |
| 287 | case offsetof(struct user_regs_struct,gs): | 302 | case offsetof(struct user_regs_struct,gs): |
| 288 | task->thread.gsindex = value; | 303 | task->thread.gsindex = value; |
| 289 | if (task == current) | ||
| 290 | load_gs_index(task->thread.gsindex); | ||
| 291 | break; | 304 | break; |
| 292 | case offsetof(struct user_regs_struct,ds): | 305 | case offsetof(struct user_regs_struct,ds): |
| 293 | task->thread.ds = value; | 306 | task->thread.ds = value; |
| 294 | if (task == current) | ||
| 295 | loadsegment(ds, task->thread.ds); | ||
| 296 | break; | 307 | break; |
| 297 | case offsetof(struct user_regs_struct,es): | 308 | case offsetof(struct user_regs_struct,es): |
| 298 | task->thread.es = value; | 309 | task->thread.es = value; |
| 299 | if (task == current) | ||
| 300 | loadsegment(es, task->thread.es); | ||
| 301 | break; | 310 | break; |
| 302 | 311 | ||
| 303 | /* | 312 | /* |
| @@ -375,6 +384,9 @@ static int putreg(struct task_struct *child, · 71 unmodified lines | |||
| 375 | * When changing the FS base, use do_arch_prctl_64() | 384 | * When changing the FS base, use do_arch_prctl_64() |
| 376 | * to set the index to zero and to set the base | 385 | * to set the index to zero and to set the base |
| 377 | * as requested. | 386 | * as requested. |
| 387 | * | ||
| 388 | * NB: This behavior is nonsensical and likely needs to | ||
| 389 | * change when FSGSBASE support is added. | ||
| 378 | */ | 390 | */ |
| 379 | if (child->thread.fsbase != value) | 391 | if (child->thread.fsbase != value) |
| 380 | return do_arch_prctl_64(child, ARCH_SET_FS, value); | 392 | return do_arch_prctl_64(child, ARCH_SET_FS, value); |
| @@ -306,8 +306,23 @@ __visible void __noreturn handle_stack_overflow(const char *message, · 305 unmodified lines | |||
| 306 | } | 306 | } |
| 307 | #endif | 307 | #endif |
| 308 | 308 | ||
| 309 | #ifdef CONFIG_X86_64 | 309 | #if defined(CONFIG_X86_64) || defined(CONFIG_DOUBLEFAULT) |
| 310 | /* Runs on IST stack */ | 310 | /* |
| 311 | * Runs on an IST stack for x86_64 and on a special task stack for x86_32. | ||
| 312 | * | ||
| 313 | * On x86_64, this is more or less a normal kernel entry. Notwithstanding the | ||
| 314 | * SDM's warnings about double faults being unrecoverable, returning works as | ||
| 315 | * expected. Presumably what the SDM actually means is that the CPU may get | ||
| 316 | * the register state wrong on entry, so returning could be a bad idea. | ||
| 317 | * | ||
| 318 | * Various CPU engineers have promised that double faults due to an IRET fault | ||
| 319 | * while the stack is read-only are, in fact, recoverable. | ||
| 320 | * | ||
| 321 | * On x86_32, this is entered through a task gate, and regs are synthesized | ||
| 322 | * from the TSS. Returning is, in principle, okay, but changes to regs will | ||
| 323 | * be lost. If, for some reason, we need to return to a context with modified | ||
| 324 | * regs, the shim code could be adjusted to synchronize the registers. | ||
| 325 | */ | ||
| 311 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2) | 326 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2) |
| 312 | { | 327 | { |
| 313 | static const char str[] = "double fault"; | 328 | static const char str[] = "double fault"; |
| @@ -411,15 +426,9 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsign · 97 unmodified lines | |||
| 411 | handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2); | 426 | handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2); |
| 412 | #endif | 427 | #endif |
| 413 | 428 | ||
| 414 | #ifdef CONFIG_DOUBLEFAULT | 429 | pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code); |
| 415 | df_debug(regs, error_code); | 430 | die("double fault", regs, error_code); |
| 416 | #endif | 431 | panic("Machine halted."); |
| 417 | /* | ||
| 418 | * This is always a kernel trap and never fixable (and thus must | ||
| 419 | * never return). | ||
| 420 | */ | ||
| 421 | for (;;) | ||
| 422 | die(str, regs, error_code); | ||
| 423 | } | 432 | } |
| 424 | #endif | 433 | #endif |
| 425 | 434 | ||
| @@ -17,6 +17,10 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(struct exception_stacks, exception_stacks); · 16 unmodified lines | |||
| 17 | DEFINE_PER_CPU(struct cea_exception_stacks*, cea_exception_stacks); | 17 | DEFINE_PER_CPU(struct cea_exception_stacks*, cea_exception_stacks); |
| 18 | #endif | 18 | #endif |
| 19 | 19 | ||
| 20 | #if defined(CONFIG_X86_32) && defined(CONFIG_DOUBLEFAULT) | ||
| 21 | DECLARE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack); | ||
| 22 | #endif | ||
| 23 | |||
| 20 | struct cpu_entry_area *get_cpu_entry_area(int cpu) | 24 | struct cpu_entry_area *get_cpu_entry_area(int cpu) |
| 21 | { | 25 | { |
| 22 | unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE; | 26 | unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE; |
| @@ -108,7 +112,15 @@ static void __init percpu_setup_exception_stacks(unsigned int cpu) · 85 unmodified lines | |||
| 108 | cea_map_stack(MCE); | 112 | cea_map_stack(MCE); |
| 109 | } | 113 | } |
| 110 | #else | 114 | #else |
| 111 | static inline void percpu_setup_exception_stacks(unsigned int cpu) {} | 115 | static inline void percpu_setup_exception_stacks(unsigned int cpu) |
| 116 | { | ||
| 117 | #ifdef CONFIG_DOUBLEFAULT | ||
| 118 | struct cpu_entry_area *cea = get_cpu_entry_area(cpu); | ||
| 119 | |||
| 120 | cea_map_percpu_pages(&cea->doublefault_stack, | ||
| 121 | &per_cpu(doublefault_stack, cpu), 1, PAGE_KERNEL); | ||
| 122 | #endif | ||
| 123 | } | ||
| 112 | #endif | 124 | #endif |
| 113 | 125 | ||
| 114 | /* Setup the fixmap mappings only once per-processor */ | 126 | /* Setup the fixmap mappings only once per-processor */ |
| @@ -197,7 +197,7 @@ void vmalloc_sync_all(void) · 196 unmodified lines | |||
| 197 | return; | 197 | return; |
| 198 | 198 | ||
| 199 | for (address = VMALLOC_START & PMD_MASK; | 199 | for (address = VMALLOC_START & PMD_MASK; |
| 200 | address >= TASK_SIZE_MAX && address < FIXADDR_TOP; | 200 | address >= TASK_SIZE_MAX && address < VMALLOC_END; |
| 201 | address += PMD_SIZE) { | 201 | address += PMD_SIZE) { |
| 202 | struct page *page; | 202 | struct page *page; |
| 203 | 203 | ||
| @@ -56,7 +56,7 @@ static struct memtype *memtype_match(u64 start, u64 end, int match_type) · 55 unmodified lines | |||
| 56 | { | 56 | { |
| 57 | struct memtype *match; | 57 | struct memtype *match; |
| 58 | 58 | ||
| 59 | match = memtype_interval_iter_first(&memtype_rbroot, start, end); | 59 | match = memtype_interval_iter_first(&memtype_rbroot, start, end-1); |
| 60 | while (match != NULL && match->start < end) { | 60 | while (match != NULL && match->start < end) { |
| 61 | if ((match_type == MEMTYPE_EXACT_MATCH) && | 61 | if ((match_type == MEMTYPE_EXACT_MATCH) && |
| 62 | (match->start == start) && (match->end == end)) | 62 | (match->start == start) && (match->end == end)) |
| @@ -66,7 +66,7 @@ static struct memtype *memtype_match(u64 start, u64 end, int match_type) · 3 unmodified lines | |||
| 66 | (match->start < start) && (match->end == end)) | 66 | (match->start < start) && (match->end == end)) |
| 67 | return match; | 67 | return match; |
| 68 | 68 | ||
| 69 | match = memtype_interval_iter_next(match, start, end); | 69 | match = memtype_interval_iter_next(match, start, end-1); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | return NULL; /* Returns NULL if there is no match */ | 72 | return NULL; /* Returns NULL if there is no match */ |
| @@ -79,7 +79,7 @@ static int memtype_check_conflict(u64 start, u64 end, · 6 unmodified lines | |||
| 79 | struct memtype *match; | 79 | struct memtype *match; |
| 80 | enum page_cache_mode found_type = reqtype; | 80 | enum page_cache_mode found_type = reqtype; |
| 81 | 81 | ||
| 82 | match = memtype_interval_iter_first(&memtype_rbroot, start, end); | 82 | match = memtype_interval_iter_first(&memtype_rbroot, start, end-1); |
| 83 | if (match == NULL) | 83 | if (match == NULL) |
| 84 | goto success; | 84 | goto success; |
| 85 | 85 | ||
| @@ -89,12 +89,12 @@ static int memtype_check_conflict(u64 start, u64 end, · 3 unmodified lines | |||
| 89 | dprintk("Overlap at 0x%Lx-0x%Lx\n", match->start, match->end); | 89 | dprintk("Overlap at 0x%Lx-0x%Lx\n", match->start, match->end); |
| 90 | found_type = match->type; | 90 | found_type = match->type; |
| 91 | 91 | ||
| 92 | match = memtype_interval_iter_next(match, start, end); | 92 | match = memtype_interval_iter_next(match, start, end-1); |
| 93 | while (match) { | 93 | while (match) { |
| 94 | if (match->type != found_type) | 94 | if (match->type != found_type) |
| 95 | goto failure; | 95 | goto failure; |
| 96 | 96 | ||
| 97 | match = memtype_interval_iter_next(match, start, end); | 97 | match = memtype_interval_iter_next(match, start, end-1); |
| 98 | } | 98 | } |
| 99 | success: | 99 | success: |
| 100 | if (newtype) | 100 | if (newtype) |
| @@ -160,7 +160,7 @@ struct memtype *memtype_erase(u64 start, u64 end) · 59 unmodified lines | |||
| 160 | struct memtype *memtype_lookup(u64 addr) | 160 | struct memtype *memtype_lookup(u64 addr) |
| 161 | { | 161 | { |
| 162 | return memtype_interval_iter_first(&memtype_rbroot, addr, | 162 | return memtype_interval_iter_first(&memtype_rbroot, addr, |
| 163 | addr + PAGE_SIZE); | 163 | addr + PAGE_SIZE-1); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | #if defined(CONFIG_DEBUG_FS) | 166 | #if defined(CONFIG_DEBUG_FS) |
| @@ -12,6 +12,10 @@ · 11 unmodified lines | |||
| 12 | #include <linux/sched/task_stack.h> | 12 | #include <linux/sched/task_stack.h> |
| 13 | #include <linux/uaccess.h> | 13 | #include <linux/uaccess.h> |
| 14 | 14 | ||
| 15 | #ifdef CONFIG_X86_32 | ||
| 16 | #include <asm/desc.h> | ||
| 17 | #endif | ||
| 18 | |||
| 15 | struct lkdtm_list { | 19 | struct lkdtm_list { |
| 16 | struct list_head node; | 20 | struct list_head node; |
| 17 | }; | 21 | }; |
| @@ -337,3 +341,38 @@ void lkdtm_UNSET_SMEP(void) · 319 unmodified lines | |||
| 337 | pr_err("FAIL: this test is x86_64-only\n"); | 341 | pr_err("FAIL: this test is x86_64-only\n"); |
| 338 | #endif | 342 | #endif |
| 339 | } | 343 | } |
| 344 | |||
| 345 | #ifdef CONFIG_X86_32 | ||
| 346 | void lkdtm_DOUBLE_FAULT(void) | ||
| 347 | { | ||
| 348 | /* | ||
| 349 | * Trigger #DF by setting the stack limit to zero. This clobbers | ||
| 350 | * a GDT TLS slot, which is okay because the current task will die | ||
| 351 | * anyway due to the double fault. | ||
| 352 | */ | ||
| 353 | struct desc_struct d = { | ||
| 354 | .type = 3, /* expand-up, writable, accessed data */ | ||
| 355 | .p = 1, /* present */ | ||
| 356 | .d = 1, /* 32-bit */ | ||
| 357 | .g = 0, /* limit in bytes */ | ||
| 358 | .s = 1, /* not system */ | ||
| 359 | }; | ||
| 360 | |||
| 361 | local_irq_disable(); | ||
| 362 | write_gdt_entry(get_cpu_gdt_rw(smp_processor_id()), | ||
| 363 | GDT_ENTRY_TLS_MIN, &d, DESCTYPE_S); | ||
| 364 | |||
| 365 | /* | ||
| 366 | * Put our zero-limit segment in SS and then trigger a fault. The | ||
| 367 | * 4-byte access to (%esp) will fault with #SS, and the attempt to | ||
| 368 | * deliver the fault will recursively cause #SS and result in #DF. | ||
| 369 | * This whole process happens while NMIs and MCEs are blocked by the | ||
| 370 | * MOV SS window. This is nice because an NMI with an invalid SS | ||
| 371 | * would also double-fault, resulting in the NMI or MCE being lost. | ||
| 372 | */ | ||
| 373 | asm volatile ("movw %0, %%ss; addl $0, (%%esp)" :: | ||
| 374 | "r" ((unsigned short)(GDT_ENTRY_TLS_MIN << 3))); | ||
| 375 | |||
| 376 | panic("tried to double fault but didn't die\n"); | ||
| 377 | } | ||
| 378 | #endif | ||
| @@ -171,6 +171,9 @@ static const struct crashtype crashtypes[] = { · 170 unmodified lines | |||
| 171 | CRASHTYPE(USERCOPY_KERNEL_DS), | 171 | CRASHTYPE(USERCOPY_KERNEL_DS), |
| 172 | CRASHTYPE(STACKLEAK_ERASING), | 172 | CRASHTYPE(STACKLEAK_ERASING), |
| 173 | CRASHTYPE(CFI_FORWARD_PROTO), | 173 | CRASHTYPE(CFI_FORWARD_PROTO), |
| 174 | #ifdef CONFIG_X86_32 | ||
| 175 | CRASHTYPE(DOUBLE_FAULT), | ||
| 176 | #endif | ||
| 174 | }; | 177 | }; |
| 175 | 178 | ||
| 176 | 179 | ||
| @@ -28,6 +28,9 @@ void lkdtm_CORRUPT_USER_DS(void); · 27 unmodified lines | |||
| 28 | void lkdtm_STACK_GUARD_PAGE_LEADING(void); | 28 | void lkdtm_STACK_GUARD_PAGE_LEADING(void); |
| 29 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void); | 29 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void); |
| 30 | void lkdtm_UNSET_SMEP(void); | 30 | void lkdtm_UNSET_SMEP(void); |
| 31 | #ifdef CONFIG_X86_32 | ||
| 32 | void lkdtm_DOUBLE_FAULT(void); | ||
| 33 | #endif | ||
| 31 | 34 | ||
| 32 | /* lkdtm_heap.c */ | 35 | /* lkdtm_heap.c */ |
| 33 | void __init lkdtm_heap_init(void); | 36 | void __init lkdtm_heap_init(void); |
| @@ -43,7 +43,19 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), · 42 unmodified lines | |||
| 43 | err(1, "sigaction"); | 43 | err(1, "sigaction"); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static volatile sig_atomic_t sig_traps; | 46 | static void clearhandler(int sig) |
| 47 | { | ||
| 48 | struct sigaction sa; | ||
| 49 | memset(&sa, 0, sizeof(sa)); | ||
| 50 | sa.sa_handler = SIG_DFL; | ||
| 51 | sigemptyset(&sa.sa_mask); | ||
| 52 | if (sigaction(sig, &sa, 0)) | ||
| 53 | err(1, "sigaction"); | ||
| 54 | } | ||
| 55 | |||
| 56 | static volatile sig_atomic_t sig_traps, sig_eflags; | ||
| 57 | sigjmp_buf jmpbuf; | ||
| 58 | static unsigned char altstack_data[SIGSTKSZ]; | ||
| 47 | 59 | ||
| 48 | #ifdef __x86_64__ | 60 | #ifdef __x86_64__ |
| 49 | # define REG_IP REG_RIP | 61 | # define REG_IP REG_RIP |
| @@ -90,6 +102,25 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void) · 40 unmodified lines | |||
| 90 | } | 102 | } |
| 91 | } | 103 | } |
| 92 | 104 | ||
| 105 | static char const * const signames[] = { | ||
| 106 | [SIGSEGV] = "SIGSEGV", | ||
| 107 | [SIGBUS] = "SIBGUS", | ||
| 108 | [SIGTRAP] = "SIGTRAP", | ||
| 109 | [SIGILL] = "SIGILL", | ||
| 110 | }; | ||
| 111 | |||
| 112 | static void print_and_longjmp(int sig, siginfo_t *si, void *ctx_void) | ||
| 113 | { | ||
| 114 | ucontext_t *ctx = ctx_void; | ||
| 115 | |||
| 116 | printf("\tGot %s with RIP=%lx, TF=%ld\n", signames[sig], | ||
| 117 | (unsigned long)ctx->uc_mcontext.gregs[REG_IP], | ||
| 118 | (unsigned long)ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_TF); | ||
| 119 | |||
| 120 | sig_eflags = (unsigned long)ctx->uc_mcontext.gregs[REG_EFL]; | ||
| 121 | siglongjmp(jmpbuf, 1); | ||
| 122 | } | ||
| 123 | |||
| 93 | static void check_result(void) | 124 | static void check_result(void) |
| 94 | { | 125 | { |
| 95 | unsigned long new_eflags = get_eflags(); | 126 | unsigned long new_eflags = get_eflags(); |
| @@ -109,6 +140,22 @@ static void check_result(void) · 13 unmodified lines | |||
| 109 | sig_traps = 0; | 140 | sig_traps = 0; |
| 110 | } | 141 | } |
| 111 | 142 | ||
| 143 | static void fast_syscall_no_tf(void) | ||
| 144 | { | ||
| 145 | sig_traps = 0; | ||
| 146 | printf("[RUN]\tFast syscall with TF cleared\n"); | ||
| 147 | fflush(stdout); /* Force a syscall */ | ||
| 148 | if (get_eflags() & X86_EFLAGS_TF) { | ||
| 149 | printf("[FAIL]\tTF is now set\n"); | ||
| 150 | exit(1); | ||
| 151 | } | ||
| 152 | if (sig_traps) { | ||
| 153 | printf("[FAIL]\tGot SIGTRAP\n"); | ||
| 154 | exit(1); | ||
| 155 | } | ||
| 156 | printf("[OK]\tNothing unexpected happened\n"); | ||
| 157 | } | ||
| 158 | |||
| 112 | int main() | 159 | int main() |
| 113 | { | 160 | { |
| 114 | #ifdef CAN_BUILD_32 | 161 | #ifdef CAN_BUILD_32 |
| @@ -163,17 +210,46 @@ int main() · 48 unmodified lines | |||
| 163 | check_result(); | 210 | check_result(); |
| 164 | 211 | ||
| 165 | /* Now make sure that another fast syscall doesn't set TF again. */ | 212 | /* Now make sure that another fast syscall doesn't set TF again. */ |
| 166 | printf("[RUN]\tFast syscall with TF cleared\n"); | 213 | fast_syscall_no_tf(); |
| 167 | fflush(stdout); /* Force a syscall */ | 214 | |
| 168 | if (get_eflags() & X86_EFLAGS_TF) { | 215 | /* |
| 169 | printf("[FAIL]\tTF is now set\n"); | 216 | * And do a forced SYSENTER to make sure that this works even if |
| 170 | exit(1); | 217 | * fast syscalls don't use SYSENTER. |
| 218 | * | ||
| 219 | * Invoking SYSENTER directly breaks all the rules. Just handle | ||
| 220 | * the SIGSEGV. | ||
| 221 | */ | ||
| 222 | if (sigsetjmp(jmpbuf, 1) == 0) { | ||
| 223 | unsigned long nr = SYS_getpid; | ||
| 224 | printf("[RUN]\tSet TF and check SYSENTER\n"); | ||
| 225 | stack_t stack = { | ||
| 226 | .ss_sp = altstack_data, | ||
| 227 | .ss_size = SIGSTKSZ, | ||
| 228 | }; | ||
| 229 | if (sigaltstack(&stack, NULL) != 0) | ||
| 230 | err(1, "sigaltstack"); | ||
| 231 | sethandler(SIGSEGV, print_and_longjmp, | ||
| 232 | SA_RESETHAND | SA_ONSTACK); | ||
| 233 | sethandler(SIGILL, print_and_longjmp, SA_RESETHAND); | ||
| 234 | set_eflags(get_eflags() | X86_EFLAGS_TF); | ||
| 235 | /* Clear EBP first to make sure we segfault cleanly. */ | ||
| 236 | asm volatile ("xorl %%ebp, %%ebp; SYSENTER" : "+a" (nr) :: "flags", "rcx" | ||
| 237 | #ifdef __x86_64__ | ||
| 238 | , "r11" | ||
| 239 | #endif | ||
| 240 | ); | ||
| 241 | |||
| 242 | /* We're unreachable here. SYSENTER forgets RIP. */ | ||
| 171 | } | 243 | } |
| 172 | if (sig_traps) { | 244 | clearhandler(SIGSEGV); |
| 173 | printf("[FAIL]\tGot SIGTRAP\n"); | 245 | clearhandler(SIGILL); |
| 246 | if (!(sig_eflags & X86_EFLAGS_TF)) { | ||
| 247 | printf("[FAIL]\tTF was cleared\n"); | ||
| 174 | exit(1); | 248 | exit(1); |
| 175 | } | 249 | } |
| 176 | printf("[OK]\tNothing unexpected happened\n"); | 250 | |
| 251 | /* Now make sure that another fast syscall doesn't set TF again. */ | ||
| 252 | fast_syscall_no_tf(); | ||
| 177 | 253 | ||
| 178 | return 0; | 254 | return 0; |
| 179 | } | 255 | } |