diff options
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/fault.c | 32 | ||||
-rw-r--r-- | arch/x86/mm/kaslr.c | 26 | ||||
-rw-r--r-- | arch/x86/mm/tlb.c | 15 |
3 files changed, 71 insertions, 2 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index dc8023060456..0b92fce3e6c0 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -753,6 +753,38 @@ no_context(struct pt_regs *regs, unsigned long error_code, | |||
753 | return; | 753 | return; |
754 | } | 754 | } |
755 | 755 | ||
756 | #ifdef CONFIG_VMAP_STACK | ||
757 | /* | ||
758 | * Stack overflow? During boot, we can fault near the initial | ||
759 | * stack in the direct map, but that's not an overflow -- check | ||
760 | * that we're in vmalloc space to avoid this. | ||
761 | */ | ||
762 | if (is_vmalloc_addr((void *)address) && | ||
763 | (((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) || | ||
764 | address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) { | ||
765 | register void *__sp asm("rsp"); | ||
766 | unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *); | ||
767 | /* | ||
768 | * We're likely to be running with very little stack space | ||
769 | * left. It's plausible that we'd hit this condition but | ||
770 | * double-fault even before we get this far, in which case | ||
771 | * we're fine: the double-fault handler will deal with it. | ||
772 | * | ||
773 | * We don't want to make it all the way into the oops code | ||
774 | * and then double-fault, though, because we're likely to | ||
775 | * break the console driver and lose most of the stack dump. | ||
776 | */ | ||
777 | asm volatile ("movq %[stack], %%rsp\n\t" | ||
778 | "call handle_stack_overflow\n\t" | ||
779 | "1: jmp 1b" | ||
780 | : "+r" (__sp) | ||
781 | : "D" ("kernel stack overflow (page fault)"), | ||
782 | "S" (regs), "d" (address), | ||
783 | [stack] "rm" (stack)); | ||
784 | unreachable(); | ||
785 | } | ||
786 | #endif | ||
787 | |||
756 | /* | 788 | /* |
757 | * 32-bit: | 789 | * 32-bit: |
758 | * | 790 | * |
diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index bda8d5eef04d..ddd2661c4502 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c | |||
@@ -40,17 +40,26 @@ | |||
40 | * You need to add an if/def entry if you introduce a new memory region | 40 | * You need to add an if/def entry if you introduce a new memory region |
41 | * compatible with KASLR. Your entry must be in logical order with memory | 41 | * compatible with KASLR. Your entry must be in logical order with memory |
42 | * layout. For example, ESPFIX is before EFI because its virtual address is | 42 | * layout. For example, ESPFIX is before EFI because its virtual address is |
43 | * before. You also need to add a BUILD_BUG_ON in kernel_randomize_memory to | 43 | * before. You also need to add a BUILD_BUG_ON() in kernel_randomize_memory() to |
44 | * ensure that this order is correct and won't be changed. | 44 | * ensure that this order is correct and won't be changed. |
45 | */ | 45 | */ |
46 | static const unsigned long vaddr_start = __PAGE_OFFSET_BASE; | 46 | static const unsigned long vaddr_start = __PAGE_OFFSET_BASE; |
47 | static const unsigned long vaddr_end = VMEMMAP_START; | 47 | |
48 | #if defined(CONFIG_X86_ESPFIX64) | ||
49 | static const unsigned long vaddr_end = ESPFIX_BASE_ADDR; | ||
50 | #elif defined(CONFIG_EFI) | ||
51 | static const unsigned long vaddr_end = EFI_VA_START; | ||
52 | #else | ||
53 | static const unsigned long vaddr_end = __START_KERNEL_map; | ||
54 | #endif | ||
48 | 55 | ||
49 | /* Default values */ | 56 | /* Default values */ |
50 | unsigned long page_offset_base = __PAGE_OFFSET_BASE; | 57 | unsigned long page_offset_base = __PAGE_OFFSET_BASE; |
51 | EXPORT_SYMBOL(page_offset_base); | 58 | EXPORT_SYMBOL(page_offset_base); |
52 | unsigned long vmalloc_base = __VMALLOC_BASE; | 59 | unsigned long vmalloc_base = __VMALLOC_BASE; |
53 | EXPORT_SYMBOL(vmalloc_base); | 60 | EXPORT_SYMBOL(vmalloc_base); |
61 | unsigned long vmemmap_base = __VMEMMAP_BASE; | ||
62 | EXPORT_SYMBOL(vmemmap_base); | ||
54 | 63 | ||
55 | /* | 64 | /* |
56 | * Memory regions randomized by KASLR (except modules that use a separate logic | 65 | * Memory regions randomized by KASLR (except modules that use a separate logic |
@@ -63,6 +72,7 @@ static __initdata struct kaslr_memory_region { | |||
63 | } kaslr_regions[] = { | 72 | } kaslr_regions[] = { |
64 | { &page_offset_base, 64/* Maximum */ }, | 73 | { &page_offset_base, 64/* Maximum */ }, |
65 | { &vmalloc_base, VMALLOC_SIZE_TB }, | 74 | { &vmalloc_base, VMALLOC_SIZE_TB }, |
75 | { &vmemmap_base, 1 }, | ||
66 | }; | 76 | }; |
67 | 77 | ||
68 | /* Get size in bytes used by the memory region */ | 78 | /* Get size in bytes used by the memory region */ |
@@ -89,6 +99,18 @@ void __init kernel_randomize_memory(void) | |||
89 | struct rnd_state rand_state; | 99 | struct rnd_state rand_state; |
90 | unsigned long remain_entropy; | 100 | unsigned long remain_entropy; |
91 | 101 | ||
102 | /* | ||
103 | * All these BUILD_BUG_ON checks ensures the memory layout is | ||
104 | * consistent with the vaddr_start/vaddr_end variables. | ||
105 | */ | ||
106 | BUILD_BUG_ON(vaddr_start >= vaddr_end); | ||
107 | BUILD_BUG_ON(config_enabled(CONFIG_X86_ESPFIX64) && | ||
108 | vaddr_end >= EFI_VA_START); | ||
109 | BUILD_BUG_ON((config_enabled(CONFIG_X86_ESPFIX64) || | ||
110 | config_enabled(CONFIG_EFI)) && | ||
111 | vaddr_end >= __START_KERNEL_map); | ||
112 | BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); | ||
113 | |||
92 | if (!kaslr_memory_enabled()) | 114 | if (!kaslr_memory_enabled()) |
93 | return; | 115 | return; |
94 | 116 | ||
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 4dbe65622810..a7655f6caf7d 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
@@ -77,10 +77,25 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, | |||
77 | unsigned cpu = smp_processor_id(); | 77 | unsigned cpu = smp_processor_id(); |
78 | 78 | ||
79 | if (likely(prev != next)) { | 79 | if (likely(prev != next)) { |
80 | if (IS_ENABLED(CONFIG_VMAP_STACK)) { | ||
81 | /* | ||
82 | * If our current stack is in vmalloc space and isn't | ||
83 | * mapped in the new pgd, we'll double-fault. Forcibly | ||
84 | * map it. | ||
85 | */ | ||
86 | unsigned int stack_pgd_index = pgd_index(current_stack_pointer()); | ||
87 | |||
88 | pgd_t *pgd = next->pgd + stack_pgd_index; | ||
89 | |||
90 | if (unlikely(pgd_none(*pgd))) | ||
91 | set_pgd(pgd, init_mm.pgd[stack_pgd_index]); | ||
92 | } | ||
93 | |||
80 | #ifdef CONFIG_SMP | 94 | #ifdef CONFIG_SMP |
81 | this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); | 95 | this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); |
82 | this_cpu_write(cpu_tlbstate.active_mm, next); | 96 | this_cpu_write(cpu_tlbstate.active_mm, next); |
83 | #endif | 97 | #endif |
98 | |||
84 | cpumask_set_cpu(cpu, mm_cpumask(next)); | 99 | cpumask_set_cpu(cpu, mm_cpumask(next)); |
85 | 100 | ||
86 | /* | 101 | /* |