diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-30 14:42:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-30 14:42:14 -0400 |
commit | 0fbc4aeabc91f2e39e0dffebe8f81a0eb3648d97 (patch) | |
tree | 4ffb5ea64600b09df6331083a9c68ae589096f76 | |
parent | d7d5388679312b7a7b6377e38e2b8fb06a82d84e (diff) | |
parent | d79d0d8ad0cb3d782b41631dfeac8eb05e414bcd (diff) |
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar:
"The biggest diffstat comes from self-test updates, plus there's entry
code fixes, 5-level paging related fixes, console debug output fixes,
and misc fixes"
* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/mm: Clean up the printk()s in show_fault_oops()
x86/mm: Drop unneeded __always_inline for p4d page table helpers
x86/efi: Fix efi_call_phys_epilog() with CONFIG_X86_5LEVEL=y
selftests/x86/sigreturn: Do minor cleanups
selftests/x86/sigreturn/64: Fix spurious failures on AMD CPUs
x86/entry/64/compat: Fix "x86/entry/64/compat: Preserve r8-r11 in int $0x80"
x86/mm: Don't free P4D table when it is folded at runtime
x86/entry/32: Add explicit 'l' instruction suffix
x86/mm: Get rid of KERN_CONT in show_fault_oops()
-rw-r--r-- | arch/x86/entry/entry_32.S | 2 | ||||
-rw-r--r-- | arch/x86/entry/entry_64_compat.S | 16 | ||||
-rw-r--r-- | arch/x86/include/asm/pgalloc.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/pgtable.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/pgtable_64.h | 4 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 21 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_64.c | 4 | ||||
-rw-r--r-- | tools/testing/selftests/x86/sigreturn.c | 59 |
8 files changed, 60 insertions, 51 deletions
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 2582881d19ce..c371bfee137a 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S | |||
@@ -477,7 +477,7 @@ ENTRY(entry_SYSENTER_32) | |||
477 | * whereas POPF does not.) | 477 | * whereas POPF does not.) |
478 | */ | 478 | */ |
479 | addl $PT_EFLAGS-PT_DS, %esp /* point esp at pt_regs->flags */ | 479 | addl $PT_EFLAGS-PT_DS, %esp /* point esp at pt_regs->flags */ |
480 | btr $X86_EFLAGS_IF_BIT, (%esp) | 480 | btrl $X86_EFLAGS_IF_BIT, (%esp) |
481 | popfl | 481 | popfl |
482 | 482 | ||
483 | /* | 483 | /* |
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index 9de7f1e1dede..7d0df78db727 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S | |||
@@ -84,13 +84,13 @@ ENTRY(entry_SYSENTER_compat) | |||
84 | pushq %rdx /* pt_regs->dx */ | 84 | pushq %rdx /* pt_regs->dx */ |
85 | pushq %rcx /* pt_regs->cx */ | 85 | pushq %rcx /* pt_regs->cx */ |
86 | pushq $-ENOSYS /* pt_regs->ax */ | 86 | pushq $-ENOSYS /* pt_regs->ax */ |
87 | pushq %r8 /* pt_regs->r8 */ | 87 | pushq $0 /* pt_regs->r8 = 0 */ |
88 | xorl %r8d, %r8d /* nospec r8 */ | 88 | xorl %r8d, %r8d /* nospec r8 */ |
89 | pushq %r9 /* pt_regs->r9 */ | 89 | pushq $0 /* pt_regs->r9 = 0 */ |
90 | xorl %r9d, %r9d /* nospec r9 */ | 90 | xorl %r9d, %r9d /* nospec r9 */ |
91 | pushq %r10 /* pt_regs->r10 */ | 91 | pushq $0 /* pt_regs->r10 = 0 */ |
92 | xorl %r10d, %r10d /* nospec r10 */ | 92 | xorl %r10d, %r10d /* nospec r10 */ |
93 | pushq %r11 /* pt_regs->r11 */ | 93 | pushq $0 /* pt_regs->r11 = 0 */ |
94 | xorl %r11d, %r11d /* nospec r11 */ | 94 | xorl %r11d, %r11d /* nospec r11 */ |
95 | pushq %rbx /* pt_regs->rbx */ | 95 | pushq %rbx /* pt_regs->rbx */ |
96 | xorl %ebx, %ebx /* nospec rbx */ | 96 | xorl %ebx, %ebx /* nospec rbx */ |
@@ -374,13 +374,13 @@ ENTRY(entry_INT80_compat) | |||
374 | pushq %rcx /* pt_regs->cx */ | 374 | pushq %rcx /* pt_regs->cx */ |
375 | xorl %ecx, %ecx /* nospec cx */ | 375 | xorl %ecx, %ecx /* nospec cx */ |
376 | pushq $-ENOSYS /* pt_regs->ax */ | 376 | pushq $-ENOSYS /* pt_regs->ax */ |
377 | pushq $0 /* pt_regs->r8 = 0 */ | 377 | pushq %r8 /* pt_regs->r8 */ |
378 | xorl %r8d, %r8d /* nospec r8 */ | 378 | xorl %r8d, %r8d /* nospec r8 */ |
379 | pushq $0 /* pt_regs->r9 = 0 */ | 379 | pushq %r9 /* pt_regs->r9 */ |
380 | xorl %r9d, %r9d /* nospec r9 */ | 380 | xorl %r9d, %r9d /* nospec r9 */ |
381 | pushq $0 /* pt_regs->r10 = 0 */ | 381 | pushq %r10 /* pt_regs->r10*/ |
382 | xorl %r10d, %r10d /* nospec r10 */ | 382 | xorl %r10d, %r10d /* nospec r10 */ |
383 | pushq $0 /* pt_regs->r11 = 0 */ | 383 | pushq %r11 /* pt_regs->r11 */ |
384 | xorl %r11d, %r11d /* nospec r11 */ | 384 | xorl %r11d, %r11d /* nospec r11 */ |
385 | pushq %rbx /* pt_regs->rbx */ | 385 | pushq %rbx /* pt_regs->rbx */ |
386 | xorl %ebx, %ebx /* nospec rbx */ | 386 | xorl %ebx, %ebx /* nospec rbx */ |
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h index ada6410fd2ec..fbd578daa66e 100644 --- a/arch/x86/include/asm/pgalloc.h +++ b/arch/x86/include/asm/pgalloc.h | |||
@@ -184,6 +184,9 @@ static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr) | |||
184 | 184 | ||
185 | static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d) | 185 | static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d) |
186 | { | 186 | { |
187 | if (!pgtable_l5_enabled()) | ||
188 | return; | ||
189 | |||
187 | BUG_ON((unsigned long)p4d & (PAGE_SIZE-1)); | 190 | BUG_ON((unsigned long)p4d & (PAGE_SIZE-1)); |
188 | free_page((unsigned long)p4d); | 191 | free_page((unsigned long)p4d); |
189 | } | 192 | } |
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 99ecde23c3ec..5715647fc4fe 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h | |||
@@ -898,7 +898,7 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd) | |||
898 | #define pgd_page(pgd) pfn_to_page(pgd_pfn(pgd)) | 898 | #define pgd_page(pgd) pfn_to_page(pgd_pfn(pgd)) |
899 | 899 | ||
900 | /* to find an entry in a page-table-directory. */ | 900 | /* to find an entry in a page-table-directory. */ |
901 | static __always_inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) | 901 | static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) |
902 | { | 902 | { |
903 | if (!pgtable_l5_enabled()) | 903 | if (!pgtable_l5_enabled()) |
904 | return (p4d_t *)pgd; | 904 | return (p4d_t *)pgd; |
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 0fdcd21dadbd..3c5385f9a88f 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h | |||
@@ -216,7 +216,7 @@ static inline pgd_t pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd) | |||
216 | } | 216 | } |
217 | #endif | 217 | #endif |
218 | 218 | ||
219 | static __always_inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) | 219 | static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) |
220 | { | 220 | { |
221 | pgd_t pgd; | 221 | pgd_t pgd; |
222 | 222 | ||
@@ -230,7 +230,7 @@ static __always_inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) | |||
230 | *p4dp = native_make_p4d(native_pgd_val(pgd)); | 230 | *p4dp = native_make_p4d(native_pgd_val(pgd)); |
231 | } | 231 | } |
232 | 232 | ||
233 | static __always_inline void native_p4d_clear(p4d_t *p4d) | 233 | static inline void native_p4d_clear(p4d_t *p4d) |
234 | { | 234 | { |
235 | native_set_p4d(p4d, native_make_p4d(0)); | 235 | native_set_p4d(p4d, native_make_p4d(0)); |
236 | } | 236 | } |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9a84a0d08727..2aafa6ab6103 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -641,11 +641,6 @@ static int is_f00f_bug(struct pt_regs *regs, unsigned long address) | |||
641 | return 0; | 641 | return 0; |
642 | } | 642 | } |
643 | 643 | ||
644 | static const char nx_warning[] = KERN_CRIT | ||
645 | "kernel tried to execute NX-protected page - exploit attempt? (uid: %d)\n"; | ||
646 | static const char smep_warning[] = KERN_CRIT | ||
647 | "unable to execute userspace code (SMEP?) (uid: %d)\n"; | ||
648 | |||
649 | static void | 644 | static void |
650 | show_fault_oops(struct pt_regs *regs, unsigned long error_code, | 645 | show_fault_oops(struct pt_regs *regs, unsigned long error_code, |
651 | unsigned long address) | 646 | unsigned long address) |
@@ -664,20 +659,18 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, | |||
664 | pte = lookup_address_in_pgd(pgd, address, &level); | 659 | pte = lookup_address_in_pgd(pgd, address, &level); |
665 | 660 | ||
666 | if (pte && pte_present(*pte) && !pte_exec(*pte)) | 661 | if (pte && pte_present(*pte) && !pte_exec(*pte)) |
667 | printk(nx_warning, from_kuid(&init_user_ns, current_uid())); | 662 | pr_crit("kernel tried to execute NX-protected page - exploit attempt? (uid: %d)\n", |
663 | from_kuid(&init_user_ns, current_uid())); | ||
668 | if (pte && pte_present(*pte) && pte_exec(*pte) && | 664 | if (pte && pte_present(*pte) && pte_exec(*pte) && |
669 | (pgd_flags(*pgd) & _PAGE_USER) && | 665 | (pgd_flags(*pgd) & _PAGE_USER) && |
670 | (__read_cr4() & X86_CR4_SMEP)) | 666 | (__read_cr4() & X86_CR4_SMEP)) |
671 | printk(smep_warning, from_kuid(&init_user_ns, current_uid())); | 667 | pr_crit("unable to execute userspace code (SMEP?) (uid: %d)\n", |
668 | from_kuid(&init_user_ns, current_uid())); | ||
672 | } | 669 | } |
673 | 670 | ||
674 | printk(KERN_ALERT "BUG: unable to handle kernel "); | 671 | pr_alert("BUG: unable to handle kernel %s at %px\n", |
675 | if (address < PAGE_SIZE) | 672 | address < PAGE_SIZE ? "NULL pointer dereference" : "paging request", |
676 | printk(KERN_CONT "NULL pointer dereference"); | 673 | (void *)address); |
677 | else | ||
678 | printk(KERN_CONT "paging request"); | ||
679 | |||
680 | printk(KERN_CONT " at %px\n", (void *) address); | ||
681 | 674 | ||
682 | dump_pagetable(address); | 675 | dump_pagetable(address); |
683 | } | 676 | } |
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index e01f7ceb9e7a..77873ce700ae 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
@@ -166,14 +166,14 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd) | |||
166 | pgd = pgd_offset_k(pgd_idx * PGDIR_SIZE); | 166 | pgd = pgd_offset_k(pgd_idx * PGDIR_SIZE); |
167 | set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]); | 167 | set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]); |
168 | 168 | ||
169 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) | 169 | if (!pgd_present(*pgd)) |
170 | continue; | 170 | continue; |
171 | 171 | ||
172 | for (i = 0; i < PTRS_PER_P4D; i++) { | 172 | for (i = 0; i < PTRS_PER_P4D; i++) { |
173 | p4d = p4d_offset(pgd, | 173 | p4d = p4d_offset(pgd, |
174 | pgd_idx * PGDIR_SIZE + i * P4D_SIZE); | 174 | pgd_idx * PGDIR_SIZE + i * P4D_SIZE); |
175 | 175 | ||
176 | if (!(p4d_val(*p4d) & _PAGE_PRESENT)) | 176 | if (!p4d_present(*p4d)) |
177 | continue; | 177 | continue; |
178 | 178 | ||
179 | pud = (pud_t *)p4d_page_vaddr(*p4d); | 179 | pud = (pud_t *)p4d_page_vaddr(*p4d); |
diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c index 246145b84a12..4d9dc3f2fd70 100644 --- a/tools/testing/selftests/x86/sigreturn.c +++ b/tools/testing/selftests/x86/sigreturn.c | |||
@@ -610,21 +610,41 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) | |||
610 | */ | 610 | */ |
611 | for (int i = 0; i < NGREG; i++) { | 611 | for (int i = 0; i < NGREG; i++) { |
612 | greg_t req = requested_regs[i], res = resulting_regs[i]; | 612 | greg_t req = requested_regs[i], res = resulting_regs[i]; |
613 | |||
613 | if (i == REG_TRAPNO || i == REG_IP) | 614 | if (i == REG_TRAPNO || i == REG_IP) |
614 | continue; /* don't care */ | 615 | continue; /* don't care */ |
615 | if (i == REG_SP) { | ||
616 | printf("\tSP: %llx -> %llx\n", (unsigned long long)req, | ||
617 | (unsigned long long)res); | ||
618 | 616 | ||
617 | if (i == REG_SP) { | ||
619 | /* | 618 | /* |
620 | * In many circumstances, the high 32 bits of rsp | 619 | * If we were using a 16-bit stack segment, then |
621 | * are zeroed. For example, we could be a real | 620 | * the kernel is a bit stuck: IRET only restores |
622 | * 32-bit program, or we could hit any of a number | 621 | * the low 16 bits of ESP/RSP if SS is 16-bit. |
623 | * of poorly-documented IRET or segmented ESP | 622 | * The kernel uses a hack to restore bits 31:16, |
624 | * oddities. If this happens, it's okay. | 623 | * but that hack doesn't help with bits 63:32. |
624 | * On Intel CPUs, bits 63:32 end up zeroed, and, on | ||
625 | * AMD CPUs, they leak the high bits of the kernel | ||
626 | * espfix64 stack pointer. There's very little that | ||
627 | * the kernel can do about it. | ||
628 | * | ||
629 | * Similarly, if we are returning to a 32-bit context, | ||
630 | * the CPU will often lose the high 32 bits of RSP. | ||
625 | */ | 631 | */ |
626 | if (res == (req & 0xFFFFFFFF)) | 632 | |
627 | continue; /* OK; not expected to work */ | 633 | if (res == req) |
634 | continue; | ||
635 | |||
636 | if (cs_bits != 64 && ((res ^ req) & 0xFFFFFFFF) == 0) { | ||
637 | printf("[NOTE]\tSP: %llx -> %llx\n", | ||
638 | (unsigned long long)req, | ||
639 | (unsigned long long)res); | ||
640 | continue; | ||
641 | } | ||
642 | |||
643 | printf("[FAIL]\tSP mismatch: requested 0x%llx; got 0x%llx\n", | ||
644 | (unsigned long long)requested_regs[i], | ||
645 | (unsigned long long)resulting_regs[i]); | ||
646 | nerrs++; | ||
647 | continue; | ||
628 | } | 648 | } |
629 | 649 | ||
630 | bool ignore_reg = false; | 650 | bool ignore_reg = false; |
@@ -654,25 +674,18 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) | |||
654 | #endif | 674 | #endif |
655 | 675 | ||
656 | /* Sanity check on the kernel */ | 676 | /* Sanity check on the kernel */ |
657 | if (i == REG_CX && requested_regs[i] != resulting_regs[i]) { | 677 | if (i == REG_CX && req != res) { |
658 | printf("[FAIL]\tCX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n", | 678 | printf("[FAIL]\tCX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n", |
659 | (unsigned long long)requested_regs[i], | 679 | (unsigned long long)req, |
660 | (unsigned long long)resulting_regs[i]); | 680 | (unsigned long long)res); |
661 | nerrs++; | 681 | nerrs++; |
662 | continue; | 682 | continue; |
663 | } | 683 | } |
664 | 684 | ||
665 | if (requested_regs[i] != resulting_regs[i] && !ignore_reg) { | 685 | if (req != res && !ignore_reg) { |
666 | /* | ||
667 | * SP is particularly interesting here. The | ||
668 | * usual cause of failures is that we hit the | ||
669 | * nasty IRET case of returning to a 16-bit SS, | ||
670 | * in which case bits 16:31 of the *kernel* | ||
671 | * stack pointer persist in ESP. | ||
672 | */ | ||
673 | printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n", | 686 | printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n", |
674 | i, (unsigned long long)requested_regs[i], | 687 | i, (unsigned long long)req, |
675 | (unsigned long long)resulting_regs[i]); | 688 | (unsigned long long)res); |
676 | nerrs++; | 689 | nerrs++; |
677 | } | 690 | } |
678 | } | 691 | } |