Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Thomas Gleixner:
"An unfortunately larger set of fixes, but a large portion is
selftests:

- Fix the missing clusterid initializaiton for x2apic cluster
management which caused boot failures due to IPIs being sent to the
wrong cluster

- Drop TX_COMPAT when a 64bit executable is exec()'ed from a compat
task

- Wrap access to __supported_pte_mask in __startup_64() where clang
compile fails due to a non PC relative access being generated.

- Two fixes for 5 level paging fallout in the decompressor:

- Handle GOT correctly for paging_prepare() and
cleanup_trampoline()

- Fix the page table handling in cleanup_trampoline() to avoid
page table corruption.

- Stop special casing protection key 0 as this is inconsistent with
the manpage and also inconsistent with the allocation map handling.

- Override the protection key wen moving away from PROT_EXEC to
prevent inaccessible memory.

- Fix and update the protection key selftests to address breakage and
to cover the above issue

- Add a MOV SS self test"

[ Part of the x86 fixes were in the earlier core pull due to dependencies ]

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (21 commits)
x86/mm: Drop TS_COMPAT on 64-bit exec() syscall
x86/apic/x2apic: Initialize cluster ID properly
x86/boot/compressed/64: Fix moving page table out of trampoline memory
x86/boot/compressed/64: Set up GOT for paging_prepare() and cleanup_trampoline()
x86/pkeys: Do not special case protection key 0
x86/pkeys/selftests: Add a test for pkey 0
x86/pkeys/selftests: Save off 'prot' for allocations
x86/pkeys/selftests: Fix pointer math
x86/pkeys: Override pkey when moving away from PROT_EXEC
x86/pkeys/selftests: Fix pkey exhaustion test off-by-one
x86/pkeys/selftests: Add PROT_EXEC test
x86/pkeys/selftests: Factor out "instruction page"
x86/pkeys/selftests: Allow faults on unknown keys
x86/pkeys/selftests: Avoid printf-in-signal deadlocks
x86/pkeys/selftests: Remove dead debugging code, fix dprint_in_signal
x86/pkeys/selftests: Stop using assert()
x86/pkeys/selftests: Give better unexpected fault error messages
x86/selftests: Add mov_to_ss test
x86/mpx/selftests: Adjust the self-test to fresh distros that export the MPX ABI
x86/pkeys/selftests: Adjust the self-test to fresh distros that export the pkeys ABI
...

+585 -129
+66 -13
arch/x86/boot/compressed/head_64.S
··· 306 306 leaq boot_stack_end(%rbx), %rsp 307 307 308 308 /* 309 + * paging_prepare() and cleanup_trampoline() below can have GOT 310 + * references. Adjust the table with address we are running at. 311 + * 312 + * Zero RAX for adjust_got: the GOT was not adjusted before; 313 + * there's no adjustment to undo. 314 + */ 315 + xorq %rax, %rax 316 + 317 + /* 318 + * Calculate the address the binary is loaded at and use it as 319 + * a GOT adjustment. 320 + */ 321 + call 1f 322 + 1: popq %rdi 323 + subq $1b, %rdi 324 + 325 + call adjust_got 326 + 327 + /* 309 328 * At this point we are in long mode with 4-level paging enabled, 310 329 * but we might want to enable 5-level paging or vice versa. 311 330 * ··· 389 370 /* 390 371 * cleanup_trampoline() would restore trampoline memory. 391 372 * 373 + * RDI is address of the page table to use instead of page table 374 + * in trampoline memory (if required). 375 + * 392 376 * RSI holds real mode data and needs to be preserved across 393 377 * this function call. 394 378 */ 395 379 pushq %rsi 380 + leaq top_pgtable(%rbx), %rdi 396 381 call cleanup_trampoline 397 382 popq %rsi 398 383 399 384 /* Zero EFLAGS */ 400 385 pushq $0 401 386 popfq 387 + 388 + /* 389 + * Previously we've adjusted the GOT with address the binary was 390 + * loaded at. Now we need to re-adjust for relocation address. 391 + * 392 + * Calculate the address the binary is loaded at, so that we can 393 + * undo the previous GOT adjustment. 394 + */ 395 + call 1f 396 + 1: popq %rax 397 + subq $1b, %rax 398 + 399 + /* The new adjustment is the relocation address */ 400 + movq %rbx, %rdi 401 + call adjust_got 402 402 403 403 /* 404 404 * Copy the compressed kernel to the end of our buffer ··· 520 482 rep stosq 521 483 522 484 /* 523 - * Adjust our own GOT 524 - */ 525 - leaq _got(%rip), %rdx 526 - leaq _egot(%rip), %rcx 527 - 1: 528 - cmpq %rcx, %rdx 529 - jae 2f 530 - addq %rbx, (%rdx) 531 - addq $8, %rdx 532 - jmp 1b 533 - 2: 534 - 535 - /* 536 485 * Do the extraction, and jump to the new kernel.. 537 486 */ 538 487 pushq %rsi /* Save the real mode argument */ ··· 536 511 * Jump to the decompressed kernel. 537 512 */ 538 513 jmp *%rax 514 + 515 + /* 516 + * Adjust the global offset table 517 + * 518 + * RAX is the previous adjustment of the table to undo (use 0 if it's the 519 + * first time we touch GOT). 520 + * RDI is the new adjustment to apply. 521 + */ 522 + adjust_got: 523 + /* Walk through the GOT adding the address to the entries */ 524 + leaq _got(%rip), %rdx 525 + leaq _egot(%rip), %rcx 526 + 1: 527 + cmpq %rcx, %rdx 528 + jae 2f 529 + subq %rax, (%rdx) /* Undo previous adjustment */ 530 + addq %rdi, (%rdx) /* Apply the new adjustment */ 531 + addq $8, %rdx 532 + jmp 1b 533 + 2: 534 + ret 539 535 540 536 .code32 541 537 /* ··· 695 649 .balign 4096 696 650 pgtable: 697 651 .fill BOOT_PGT_SIZE, 1, 0 652 + 653 + /* 654 + * The page table is going to be used instead of page table in the trampoline 655 + * memory. 656 + */ 657 + top_pgtable: 658 + .fill PAGE_SIZE, 1, 0
+3 -11
arch/x86/boot/compressed/pgtable_64.c
··· 23 23 static char trampoline_save[TRAMPOLINE_32BIT_SIZE]; 24 24 25 25 /* 26 - * The page table is going to be used instead of page table in the trampoline 27 - * memory. 28 - * 29 - * It must not be in BSS as BSS is cleared after cleanup_trampoline(). 30 - */ 31 - static char top_pgtable[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); 32 - 33 - /* 34 26 * Trampoline address will be printed by extract_kernel() for debugging 35 27 * purposes. 36 28 * ··· 126 134 return paging_config; 127 135 } 128 136 129 - void cleanup_trampoline(void) 137 + void cleanup_trampoline(void *pgtable) 130 138 { 131 139 void *trampoline_pgtable; 132 140 ··· 137 145 * if it's there. 138 146 */ 139 147 if ((void *)__native_read_cr3() == trampoline_pgtable) { 140 - memcpy(top_pgtable, trampoline_pgtable, PAGE_SIZE); 141 - native_write_cr3((unsigned long)top_pgtable); 148 + memcpy(pgtable, trampoline_pgtable, PAGE_SIZE); 149 + native_write_cr3((unsigned long)pgtable); 142 150 } 143 151 144 152 /* Restore trampoline memory */
+1 -1
arch/x86/include/asm/mmu_context.h
··· 193 193 194 194 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 195 195 if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { 196 - /* pkey 0 is the default and always allocated */ 196 + /* pkey 0 is the default and allocated implicitly */ 197 197 mm->context.pkey_allocation_map = 0x1; 198 198 /* -1 means unallocated or invalid */ 199 199 mm->context.execute_only_pkey = -1;
+14 -4
arch/x86/include/asm/pkeys.h
··· 2 2 #ifndef _ASM_X86_PKEYS_H 3 3 #define _ASM_X86_PKEYS_H 4 4 5 + #define ARCH_DEFAULT_PKEY 0 6 + 5 7 #define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) 6 8 7 9 extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, ··· 17 15 static inline int execute_only_pkey(struct mm_struct *mm) 18 16 { 19 17 if (!boot_cpu_has(X86_FEATURE_OSPKE)) 20 - return 0; 18 + return ARCH_DEFAULT_PKEY; 21 19 22 20 return __execute_only_pkey(mm); 23 21 } ··· 51 49 { 52 50 /* 53 51 * "Allocated" pkeys are those that have been returned 54 - * from pkey_alloc(). pkey 0 is special, and never 55 - * returned from pkey_alloc(). 52 + * from pkey_alloc() or pkey 0 which is allocated 53 + * implicitly when the mm is created. 56 54 */ 57 - if (pkey <= 0) 55 + if (pkey < 0) 58 56 return false; 59 57 if (pkey >= arch_max_pkey()) 60 58 return false; 59 + /* 60 + * The exec-only pkey is set in the allocation map, but 61 + * is not available to any of the user interfaces like 62 + * mprotect_pkey(). 63 + */ 64 + if (pkey == mm->context.execute_only_pkey) 65 + return false; 66 + 61 67 return mm_pkey_allocation_map(mm) & (1U << pkey); 62 68 } 63 69
+1
arch/x86/kernel/apic/x2apic_cluster.c
··· 116 116 goto update; 117 117 } 118 118 cmsk = cluster_hotplug_mask; 119 + cmsk->clusterid = cluster; 119 120 cluster_hotplug_mask = NULL; 120 121 update: 121 122 this_cpu_write(cluster_masks, cmsk);
+9 -1
arch/x86/kernel/head64.c
··· 104 104 } 105 105 #endif 106 106 107 + /* Code in __startup_64() can be relocated during execution, but the compiler 108 + * doesn't have to generate PC-relative relocations when accessing globals from 109 + * that function. Clang actually does not generate them, which leads to 110 + * boot-time crashes. To work around this problem, every global pointer must 111 + * be adjusted using fixup_pointer(). 112 + */ 107 113 unsigned long __head __startup_64(unsigned long physaddr, 108 114 struct boot_params *bp) 109 115 { ··· 119 113 p4dval_t *p4d; 120 114 pudval_t *pud; 121 115 pmdval_t *pmd, pmd_entry; 116 + pteval_t *mask_ptr; 122 117 bool la57; 123 118 int i; 124 119 unsigned int *next_pgt_ptr; ··· 203 196 204 197 pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL; 205 198 /* Filter out unsupported __PAGE_KERNEL_* bits: */ 206 - pmd_entry &= __supported_pte_mask; 199 + mask_ptr = fixup_pointer(&__supported_pte_mask, physaddr); 200 + pmd_entry &= *mask_ptr; 207 201 pmd_entry += sme_get_me_mask(); 208 202 pmd_entry += physaddr; 209 203
+1
arch/x86/kernel/process_64.c
··· 542 542 clear_thread_flag(TIF_X32); 543 543 /* Pretend that this comes from a 64bit execve */ 544 544 task_pt_regs(current)->orig_ax = __NR_execve; 545 + current_thread_info()->status &= ~TS_COMPAT; 545 546 546 547 /* Ensure the corresponding mm is not marked. */ 547 548 if (current->mm)
+11 -10
arch/x86/mm/pkeys.c
··· 94 94 */ 95 95 if (pkey != -1) 96 96 return pkey; 97 - /* 98 - * Look for a protection-key-drive execute-only mapping 99 - * which is now being given permissions that are not 100 - * execute-only. Move it back to the default pkey. 101 - */ 102 - if (vma_is_pkey_exec_only(vma) && 103 - (prot & (PROT_READ|PROT_WRITE))) { 104 - return 0; 105 - } 97 + 106 98 /* 107 99 * The mapping is execute-only. Go try to get the 108 100 * execute-only protection key. If we fail to do that, 109 101 * fall through as if we do not have execute-only 110 - * support. 102 + * support in this mm. 111 103 */ 112 104 if (prot == PROT_EXEC) { 113 105 pkey = execute_only_pkey(vma->vm_mm); 114 106 if (pkey > 0) 115 107 return pkey; 108 + } else if (vma_is_pkey_exec_only(vma)) { 109 + /* 110 + * Protections are *not* PROT_EXEC, but the mapping 111 + * is using the exec-only pkey. This mapping was 112 + * PROT_EXEC and will no longer be. Move back to 113 + * the default pkey. 114 + */ 115 + return ARCH_DEFAULT_PKEY; 116 116 } 117 + 117 118 /* 118 119 * This is a vanilla, non-pkey mprotect (or we failed to 119 120 * setup execute-only), inherit the pkey from the VMA we
+1 -1
tools/testing/selftests/x86/Makefile
··· 11 11 12 12 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ 13 13 check_initial_reg_state sigreturn iopl mpx-mini-test ioperm \ 14 - protection_keys test_vdso test_vsyscall 14 + protection_keys test_vdso test_vsyscall mov_ss_trap 15 15 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 16 16 test_FCMOV test_FCOMI test_FISTTP \ 17 17 vdso_restorer
+285
tools/testing/selftests/x86/mov_ss_trap.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * mov_ss_trap.c: Exercise the bizarre side effects of a watchpoint on MOV SS 4 + * 5 + * This does MOV SS from a watchpointed address followed by various 6 + * types of kernel entries. A MOV SS that hits a watchpoint will queue 7 + * up a #DB trap but will not actually deliver that trap. The trap 8 + * will be delivered after the next instruction instead. The CPU's logic 9 + * seems to be: 10 + * 11 + * - Any fault: drop the pending #DB trap. 12 + * - INT $N, INT3, INTO, SYSCALL, SYSENTER: enter the kernel and then 13 + * deliver #DB. 14 + * - ICEBP: enter the kernel but do not deliver the watchpoint trap 15 + * - breakpoint: only one #DB is delivered (phew!) 16 + * 17 + * There are plenty of ways for a kernel to handle this incorrectly. This 18 + * test tries to exercise all the cases. 19 + * 20 + * This should mostly cover CVE-2018-1087 and CVE-2018-8897. 21 + */ 22 + #define _GNU_SOURCE 23 + 24 + #include <stdlib.h> 25 + #include <sys/ptrace.h> 26 + #include <sys/types.h> 27 + #include <sys/wait.h> 28 + #include <sys/user.h> 29 + #include <sys/syscall.h> 30 + #include <unistd.h> 31 + #include <errno.h> 32 + #include <stddef.h> 33 + #include <stdio.h> 34 + #include <err.h> 35 + #include <string.h> 36 + #include <setjmp.h> 37 + #include <sys/prctl.h> 38 + 39 + #define X86_EFLAGS_RF (1UL << 16) 40 + 41 + #if __x86_64__ 42 + # define REG_IP REG_RIP 43 + #else 44 + # define REG_IP REG_EIP 45 + #endif 46 + 47 + unsigned short ss; 48 + extern unsigned char breakpoint_insn[]; 49 + sigjmp_buf jmpbuf; 50 + static unsigned char altstack_data[SIGSTKSZ]; 51 + 52 + static void enable_watchpoint(void) 53 + { 54 + pid_t parent = getpid(); 55 + int status; 56 + 57 + pid_t child = fork(); 58 + if (child < 0) 59 + err(1, "fork"); 60 + 61 + if (child) { 62 + if (waitpid(child, &status, 0) != child) 63 + err(1, "waitpid for child"); 64 + } else { 65 + unsigned long dr0, dr1, dr7; 66 + 67 + dr0 = (unsigned long)&ss; 68 + dr1 = (unsigned long)breakpoint_insn; 69 + dr7 = ((1UL << 1) | /* G0 */ 70 + (3UL << 16) | /* RW0 = read or write */ 71 + (1UL << 18) | /* LEN0 = 2 bytes */ 72 + (1UL << 3)); /* G1, RW1 = insn */ 73 + 74 + if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0) 75 + err(1, "PTRACE_ATTACH"); 76 + 77 + if (waitpid(parent, &status, 0) != parent) 78 + err(1, "waitpid for child"); 79 + 80 + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[0]), dr0) != 0) 81 + err(1, "PTRACE_POKEUSER DR0"); 82 + 83 + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[1]), dr1) != 0) 84 + err(1, "PTRACE_POKEUSER DR1"); 85 + 86 + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[7]), dr7) != 0) 87 + err(1, "PTRACE_POKEUSER DR7"); 88 + 89 + printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7); 90 + 91 + if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0) 92 + err(1, "PTRACE_DETACH"); 93 + 94 + exit(0); 95 + } 96 + } 97 + 98 + static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 99 + int flags) 100 + { 101 + struct sigaction sa; 102 + memset(&sa, 0, sizeof(sa)); 103 + sa.sa_sigaction = handler; 104 + sa.sa_flags = SA_SIGINFO | flags; 105 + sigemptyset(&sa.sa_mask); 106 + if (sigaction(sig, &sa, 0)) 107 + err(1, "sigaction"); 108 + } 109 + 110 + static char const * const signames[] = { 111 + [SIGSEGV] = "SIGSEGV", 112 + [SIGBUS] = "SIBGUS", 113 + [SIGTRAP] = "SIGTRAP", 114 + [SIGILL] = "SIGILL", 115 + }; 116 + 117 + static void sigtrap(int sig, siginfo_t *si, void *ctx_void) 118 + { 119 + ucontext_t *ctx = ctx_void; 120 + 121 + printf("\tGot SIGTRAP with RIP=%lx, EFLAGS.RF=%d\n", 122 + (unsigned long)ctx->uc_mcontext.gregs[REG_IP], 123 + !!(ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_RF)); 124 + } 125 + 126 + static void handle_and_return(int sig, siginfo_t *si, void *ctx_void) 127 + { 128 + ucontext_t *ctx = ctx_void; 129 + 130 + printf("\tGot %s with RIP=%lx\n", signames[sig], 131 + (unsigned long)ctx->uc_mcontext.gregs[REG_IP]); 132 + } 133 + 134 + static void handle_and_longjmp(int sig, siginfo_t *si, void *ctx_void) 135 + { 136 + ucontext_t *ctx = ctx_void; 137 + 138 + printf("\tGot %s with RIP=%lx\n", signames[sig], 139 + (unsigned long)ctx->uc_mcontext.gregs[REG_IP]); 140 + 141 + siglongjmp(jmpbuf, 1); 142 + } 143 + 144 + int main() 145 + { 146 + unsigned long nr; 147 + 148 + asm volatile ("mov %%ss, %[ss]" : [ss] "=m" (ss)); 149 + printf("\tSS = 0x%hx, &SS = 0x%p\n", ss, &ss); 150 + 151 + if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == 0) 152 + printf("\tPR_SET_PTRACER_ANY succeeded\n"); 153 + 154 + printf("\tSet up a watchpoint\n"); 155 + sethandler(SIGTRAP, sigtrap, 0); 156 + enable_watchpoint(); 157 + 158 + printf("[RUN]\tRead from watched memory (should get SIGTRAP)\n"); 159 + asm volatile ("mov %[ss], %[tmp]" : [tmp] "=r" (nr) : [ss] "m" (ss)); 160 + 161 + printf("[RUN]\tMOV SS; INT3\n"); 162 + asm volatile ("mov %[ss], %%ss; int3" :: [ss] "m" (ss)); 163 + 164 + printf("[RUN]\tMOV SS; INT 3\n"); 165 + asm volatile ("mov %[ss], %%ss; .byte 0xcd, 0x3" :: [ss] "m" (ss)); 166 + 167 + printf("[RUN]\tMOV SS; CS CS INT3\n"); 168 + asm volatile ("mov %[ss], %%ss; .byte 0x2e, 0x2e; int3" :: [ss] "m" (ss)); 169 + 170 + printf("[RUN]\tMOV SS; CSx14 INT3\n"); 171 + asm volatile ("mov %[ss], %%ss; .fill 14,1,0x2e; int3" :: [ss] "m" (ss)); 172 + 173 + printf("[RUN]\tMOV SS; INT 4\n"); 174 + sethandler(SIGSEGV, handle_and_return, SA_RESETHAND); 175 + asm volatile ("mov %[ss], %%ss; int $4" :: [ss] "m" (ss)); 176 + 177 + #ifdef __i386__ 178 + printf("[RUN]\tMOV SS; INTO\n"); 179 + sethandler(SIGSEGV, handle_and_return, SA_RESETHAND); 180 + nr = -1; 181 + asm volatile ("add $1, %[tmp]; mov %[ss], %%ss; into" 182 + : [tmp] "+r" (nr) : [ss] "m" (ss)); 183 + #endif 184 + 185 + if (sigsetjmp(jmpbuf, 1) == 0) { 186 + printf("[RUN]\tMOV SS; ICEBP\n"); 187 + 188 + /* Some emulators (e.g. QEMU TCG) don't emulate ICEBP. */ 189 + sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND); 190 + 191 + asm volatile ("mov %[ss], %%ss; .byte 0xf1" :: [ss] "m" (ss)); 192 + } 193 + 194 + if (sigsetjmp(jmpbuf, 1) == 0) { 195 + printf("[RUN]\tMOV SS; CLI\n"); 196 + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); 197 + asm volatile ("mov %[ss], %%ss; cli" :: [ss] "m" (ss)); 198 + } 199 + 200 + if (sigsetjmp(jmpbuf, 1) == 0) { 201 + printf("[RUN]\tMOV SS; #PF\n"); 202 + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); 203 + asm volatile ("mov %[ss], %%ss; mov (-1), %[tmp]" 204 + : [tmp] "=r" (nr) : [ss] "m" (ss)); 205 + } 206 + 207 + /* 208 + * INT $1: if #DB has DPL=3 and there isn't special handling, 209 + * then the kernel will die. 210 + */ 211 + if (sigsetjmp(jmpbuf, 1) == 0) { 212 + printf("[RUN]\tMOV SS; INT 1\n"); 213 + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); 214 + asm volatile ("mov %[ss], %%ss; int $1" :: [ss] "m" (ss)); 215 + } 216 + 217 + #ifdef __x86_64__ 218 + /* 219 + * In principle, we should test 32-bit SYSCALL as well, but 220 + * the calling convention is so unpredictable that it's 221 + * not obviously worth the effort. 222 + */ 223 + if (sigsetjmp(jmpbuf, 1) == 0) { 224 + printf("[RUN]\tMOV SS; SYSCALL\n"); 225 + sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND); 226 + nr = SYS_getpid; 227 + /* 228 + * Toggle the high bit of RSP to make it noncanonical to 229 + * strengthen this test on non-SMAP systems. 230 + */ 231 + asm volatile ("btc $63, %%rsp\n\t" 232 + "mov %[ss], %%ss; syscall\n\t" 233 + "btc $63, %%rsp" 234 + : "+a" (nr) : [ss] "m" (ss) 235 + : "rcx" 236 + #ifdef __x86_64__ 237 + , "r11" 238 + #endif 239 + ); 240 + } 241 + #endif 242 + 243 + printf("[RUN]\tMOV SS; breakpointed NOP\n"); 244 + asm volatile ("mov %[ss], %%ss; breakpoint_insn: nop" :: [ss] "m" (ss)); 245 + 246 + /* 247 + * Invoking SYSENTER directly breaks all the rules. Just handle 248 + * the SIGSEGV. 249 + */ 250 + if (sigsetjmp(jmpbuf, 1) == 0) { 251 + printf("[RUN]\tMOV SS; SYSENTER\n"); 252 + stack_t stack = { 253 + .ss_sp = altstack_data, 254 + .ss_size = SIGSTKSZ, 255 + }; 256 + if (sigaltstack(&stack, NULL) != 0) 257 + err(1, "sigaltstack"); 258 + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND | SA_ONSTACK); 259 + nr = SYS_getpid; 260 + asm volatile ("mov %[ss], %%ss; SYSENTER" : "+a" (nr) 261 + : [ss] "m" (ss) : "flags", "rcx" 262 + #ifdef __x86_64__ 263 + , "r11" 264 + #endif 265 + ); 266 + 267 + /* We're unreachable here. SYSENTER forgets RIP. */ 268 + } 269 + 270 + if (sigsetjmp(jmpbuf, 1) == 0) { 271 + printf("[RUN]\tMOV SS; INT $0x80\n"); 272 + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); 273 + nr = 20; /* compat getpid */ 274 + asm volatile ("mov %[ss], %%ss; int $0x80" 275 + : "+a" (nr) : [ss] "m" (ss) 276 + : "flags" 277 + #ifdef __x86_64__ 278 + , "r8", "r9", "r10", "r11" 279 + #endif 280 + ); 281 + } 282 + 283 + printf("[OK]\tI aten't dead\n"); 284 + return 0; 285 + }
+5 -2
tools/testing/selftests/x86/mpx-mini-test.c
··· 368 368 uint64_t shadow_plb[NR_MPX_BOUNDS_REGISTERS][2]; /* shadow MPX bound registers */ 369 369 unsigned long shadow_map[NR_MPX_BOUNDS_REGISTERS]; 370 370 371 + /* Failed address bound checks: */ 372 + #ifndef SEGV_BNDERR 373 + # define SEGV_BNDERR 3 374 + #endif 375 + 371 376 /* 372 377 * The kernel is supposed to provide some information about the bounds 373 378 * exception in the siginfo. It should match what we have in the bounds ··· 423 418 424 419 br_count++; 425 420 dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); 426 - 427 - #define SEGV_BNDERR 3 /* failed address bound checks */ 428 421 429 422 dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", 430 423 status, ip, br_reason);
+8 -12
tools/testing/selftests/x86/pkey-helpers.h
··· 26 26 { 27 27 va_list ap; 28 28 29 - va_start(ap, format); 30 29 if (!dprint_in_signal) { 30 + va_start(ap, format); 31 31 vprintf(format, ap); 32 + va_end(ap); 32 33 } else { 33 34 int ret; 34 - int len = vsnprintf(dprint_in_signal_buffer, 35 - DPRINT_IN_SIGNAL_BUF_SIZE, 36 - format, ap); 37 35 /* 38 - * len is amount that would have been printed, 39 - * but actual write is truncated at BUF_SIZE. 36 + * No printf() functions are signal-safe. 37 + * They deadlock easily. Write the format 38 + * string to get some output, even if 39 + * incomplete. 40 40 */ 41 - if (len > DPRINT_IN_SIGNAL_BUF_SIZE) 42 - len = DPRINT_IN_SIGNAL_BUF_SIZE; 43 - ret = write(1, dprint_in_signal_buffer, len); 41 + ret = write(1, format, strlen(format)); 44 42 if (ret < 0) 45 - abort(); 43 + exit(1); 46 44 } 47 - va_end(ap); 48 45 } 49 46 #define dprintf_level(level, args...) do { \ 50 47 if (level <= DEBUG_LEVEL) \ 51 48 sigsafe_printf(args); \ 52 - fflush(NULL); \ 53 49 } while (0) 54 50 #define dprintf0(args...) dprintf_level(0, args) 55 51 #define dprintf1(args...) dprintf_level(1, args)
+180 -74
tools/testing/selftests/x86/protection_keys.c
··· 72 72 test_nr, iteration_nr); \ 73 73 dprintf0("errno at assert: %d", errno); \ 74 74 abort_hooks(); \ 75 - assert(condition); \ 75 + exit(__LINE__); \ 76 76 } \ 77 77 } while (0) 78 - #define raw_assert(cond) assert(cond) 79 78 80 79 void cat_into_file(char *str, char *file) 81 80 { ··· 86 87 * these need to be raw because they are called under 87 88 * pkey_assert() 88 89 */ 89 - raw_assert(fd >= 0); 90 + if (fd < 0) { 91 + fprintf(stderr, "error opening '%s'\n", str); 92 + perror("error: "); 93 + exit(__LINE__); 94 + } 95 + 90 96 ret = write(fd, str, strlen(str)); 91 97 if (ret != strlen(str)) { 92 98 perror("write to file failed"); 93 99 fprintf(stderr, "filename: '%s' str: '%s'\n", file, str); 94 - raw_assert(0); 100 + exit(__LINE__); 95 101 } 96 102 close(fd); 97 103 } ··· 195 191 #ifdef __i386__ 196 192 197 193 #ifndef SYS_mprotect_key 198 - # define SYS_mprotect_key 380 194 + # define SYS_mprotect_key 380 199 195 #endif 196 + 200 197 #ifndef SYS_pkey_alloc 201 - # define SYS_pkey_alloc 381 202 - # define SYS_pkey_free 382 198 + # define SYS_pkey_alloc 381 199 + # define SYS_pkey_free 382 203 200 #endif 204 - #define REG_IP_IDX REG_EIP 205 - #define si_pkey_offset 0x14 201 + 202 + #define REG_IP_IDX REG_EIP 203 + #define si_pkey_offset 0x14 206 204 207 205 #else 208 206 209 207 #ifndef SYS_mprotect_key 210 - # define SYS_mprotect_key 329 208 + # define SYS_mprotect_key 329 211 209 #endif 210 + 212 211 #ifndef SYS_pkey_alloc 213 - # define SYS_pkey_alloc 330 214 - # define SYS_pkey_free 331 212 + # define SYS_pkey_alloc 330 213 + # define SYS_pkey_free 331 215 214 #endif 216 - #define REG_IP_IDX REG_RIP 217 - #define si_pkey_offset 0x20 215 + 216 + #define REG_IP_IDX REG_RIP 217 + #define si_pkey_offset 0x20 218 218 219 219 #endif 220 220 ··· 233 225 } 234 226 } 235 227 236 - #define SEGV_BNDERR 3 /* failed address bound checks */ 237 - #define SEGV_PKUERR 4 228 + /* Failed address bound checks: */ 229 + #ifndef SEGV_BNDERR 230 + # define SEGV_BNDERR 3 231 + #endif 232 + 233 + #ifndef SEGV_PKUERR 234 + # define SEGV_PKUERR 4 235 + #endif 238 236 239 237 static char *si_code_str(int si_code) 240 238 { ··· 303 289 dump_mem(pkru_ptr - 128, 256); 304 290 pkey_assert(*pkru_ptr); 305 291 306 - si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); 307 - dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); 308 - dump_mem(si_pkey_ptr - 8, 24); 309 - siginfo_pkey = *si_pkey_ptr; 310 - pkey_assert(siginfo_pkey < NR_PKEYS); 311 - last_si_pkey = siginfo_pkey; 312 - 313 292 if ((si->si_code == SEGV_MAPERR) || 314 293 (si->si_code == SEGV_ACCERR) || 315 294 (si->si_code == SEGV_BNDERR)) { 316 295 printf("non-PK si_code, exiting...\n"); 317 296 exit(4); 318 297 } 298 + 299 + si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); 300 + dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); 301 + dump_mem((u8 *)si_pkey_ptr - 8, 24); 302 + siginfo_pkey = *si_pkey_ptr; 303 + pkey_assert(siginfo_pkey < NR_PKEYS); 304 + last_si_pkey = siginfo_pkey; 319 305 320 306 dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); 321 307 /* need __rdpkru() version so we do not do shadow_pkru checking */ ··· 325 311 dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); 326 312 pkru_faults++; 327 313 dprintf1("<<<<==================================================\n"); 328 - return; 329 - if (trapno == 14) { 330 - fprintf(stderr, 331 - "ERROR: In signal handler, page fault, trapno = %d, ip = %016lx\n", 332 - trapno, ip); 333 - fprintf(stderr, "si_addr %p\n", si->si_addr); 334 - fprintf(stderr, "REG_ERR: %lx\n", 335 - (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); 336 - exit(1); 337 - } else { 338 - fprintf(stderr, "unexpected trap %d! at 0x%lx\n", trapno, ip); 339 - fprintf(stderr, "si_addr %p\n", si->si_addr); 340 - fprintf(stderr, "REG_ERR: %lx\n", 341 - (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); 342 - exit(2); 343 - } 344 314 dprint_in_signal = 0; 345 315 } 346 316 ··· 391 393 return forkret; 392 394 } 393 395 394 - #define PKEY_DISABLE_ACCESS 0x1 395 - #define PKEY_DISABLE_WRITE 0x2 396 + #ifndef PKEY_DISABLE_ACCESS 397 + # define PKEY_DISABLE_ACCESS 0x1 398 + #endif 396 399 397 - u32 pkey_get(int pkey, unsigned long flags) 400 + #ifndef PKEY_DISABLE_WRITE 401 + # define PKEY_DISABLE_WRITE 0x2 402 + #endif 403 + 404 + static u32 hw_pkey_get(int pkey, unsigned long flags) 398 405 { 399 406 u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); 400 407 u32 pkru = __rdpkru(); ··· 421 418 return masked_pkru; 422 419 } 423 420 424 - int pkey_set(int pkey, unsigned long rights, unsigned long flags) 421 + static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags) 425 422 { 426 423 u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); 427 424 u32 old_pkru = __rdpkru(); ··· 455 452 pkey, flags); 456 453 pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); 457 454 458 - pkey_rights = pkey_get(pkey, syscall_flags); 455 + pkey_rights = hw_pkey_get(pkey, syscall_flags); 459 456 460 - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, 457 + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 461 458 pkey, pkey, pkey_rights); 462 459 pkey_assert(pkey_rights >= 0); 463 460 464 461 pkey_rights |= flags; 465 462 466 - ret = pkey_set(pkey, pkey_rights, syscall_flags); 463 + ret = hw_pkey_set(pkey, pkey_rights, syscall_flags); 467 464 assert(!ret); 468 465 /*pkru and flags have the same format */ 469 466 shadow_pkru |= flags << (pkey * 2); ··· 471 468 472 469 pkey_assert(ret >= 0); 473 470 474 - pkey_rights = pkey_get(pkey, syscall_flags); 475 - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, 471 + pkey_rights = hw_pkey_get(pkey, syscall_flags); 472 + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 476 473 pkey, pkey, pkey_rights); 477 474 478 475 dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); ··· 486 483 { 487 484 unsigned long syscall_flags = 0; 488 485 int ret; 489 - int pkey_rights = pkey_get(pkey, syscall_flags); 486 + int pkey_rights = hw_pkey_get(pkey, syscall_flags); 490 487 u32 orig_pkru = rdpkru(); 491 488 492 489 pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); 493 490 494 - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, 491 + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 495 492 pkey, pkey, pkey_rights); 496 493 pkey_assert(pkey_rights >= 0); 497 494 498 495 pkey_rights |= flags; 499 496 500 - ret = pkey_set(pkey, pkey_rights, 0); 497 + ret = hw_pkey_set(pkey, pkey_rights, 0); 501 498 /* pkru and flags have the same format */ 502 499 shadow_pkru &= ~(flags << (pkey * 2)); 503 500 pkey_assert(ret >= 0); 504 501 505 - pkey_rights = pkey_get(pkey, syscall_flags); 506 - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, 502 + pkey_rights = hw_pkey_get(pkey, syscall_flags); 503 + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 507 504 pkey, pkey, pkey_rights); 508 505 509 506 dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); ··· 677 674 struct pkey_malloc_record { 678 675 void *ptr; 679 676 long size; 677 + int prot; 680 678 }; 681 679 struct pkey_malloc_record *pkey_malloc_records; 680 + struct pkey_malloc_record *pkey_last_malloc_record; 682 681 long nr_pkey_malloc_records; 683 - void record_pkey_malloc(void *ptr, long size) 682 + void record_pkey_malloc(void *ptr, long size, int prot) 684 683 { 685 684 long i; 686 685 struct pkey_malloc_record *rec = NULL; ··· 714 709 (int)(rec - pkey_malloc_records), rec, ptr, size); 715 710 rec->ptr = ptr; 716 711 rec->size = size; 712 + rec->prot = prot; 713 + pkey_last_malloc_record = rec; 717 714 nr_pkey_malloc_records++; 718 715 } 719 716 ··· 760 753 pkey_assert(ptr != (void *)-1); 761 754 ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey); 762 755 pkey_assert(!ret); 763 - record_pkey_malloc(ptr, size); 756 + record_pkey_malloc(ptr, size, prot); 764 757 rdpkru(); 765 758 766 759 dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr); ··· 781 774 size = ALIGN_UP(size, HPAGE_SIZE * 2); 782 775 ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 783 776 pkey_assert(ptr != (void *)-1); 784 - record_pkey_malloc(ptr, size); 777 + record_pkey_malloc(ptr, size, prot); 785 778 mprotect_pkey(ptr, size, prot, pkey); 786 779 787 780 dprintf1("unaligned ptr: %p\n", ptr); ··· 854 847 pkey_assert(ptr != (void *)-1); 855 848 mprotect_pkey(ptr, size, prot, pkey); 856 849 857 - record_pkey_malloc(ptr, size); 850 + record_pkey_malloc(ptr, size, prot); 858 851 859 852 dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr); 860 853 return ptr; ··· 876 869 877 870 mprotect_pkey(ptr, size, prot, pkey); 878 871 879 - record_pkey_malloc(ptr, size); 872 + record_pkey_malloc(ptr, size, prot); 880 873 881 874 dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr); 882 875 close(fd); ··· 925 918 } 926 919 927 920 int last_pkru_faults; 921 + #define UNKNOWN_PKEY -2 928 922 void expected_pk_fault(int pkey) 929 923 { 930 924 dprintf2("%s(): last_pkru_faults: %d pkru_faults: %d\n", 931 925 __func__, last_pkru_faults, pkru_faults); 932 926 dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey); 933 927 pkey_assert(last_pkru_faults + 1 == pkru_faults); 934 - pkey_assert(last_si_pkey == pkey); 928 + 929 + /* 930 + * For exec-only memory, we do not know the pkey in 931 + * advance, so skip this check. 932 + */ 933 + if (pkey != UNKNOWN_PKEY) 934 + pkey_assert(last_si_pkey == pkey); 935 + 935 936 /* 936 937 * The signal handler shold have cleared out PKRU to let the 937 938 * test program continue. We now have to restore it. ··· 954 939 last_si_pkey = -1; 955 940 } 956 941 957 - void do_not_expect_pk_fault(void) 958 - { 959 - pkey_assert(last_pkru_faults == pkru_faults); 960 - } 942 + #define do_not_expect_pk_fault(msg) do { \ 943 + if (last_pkru_faults != pkru_faults) \ 944 + dprintf0("unexpected PK fault: %s\n", msg); \ 945 + pkey_assert(last_pkru_faults == pkru_faults); \ 946 + } while (0) 961 947 962 948 int test_fds[10] = { -1 }; 963 949 int nr_test_fds; ··· 1167 1151 pkey_assert(i < NR_PKEYS*2); 1168 1152 1169 1153 /* 1170 - * There are 16 pkeys supported in hardware. One is taken 1171 - * up for the default (0) and another can be taken up by 1172 - * an execute-only mapping. Ensure that we can allocate 1173 - * at least 14 (16-2). 1154 + * There are 16 pkeys supported in hardware. Three are 1155 + * allocated by the time we get here: 1156 + * 1. The default key (0) 1157 + * 2. One possibly consumed by an execute-only mapping. 1158 + * 3. One allocated by the test code and passed in via 1159 + * 'pkey' to this function. 1160 + * Ensure that we can allocate at least another 13 (16-3). 1174 1161 */ 1175 - pkey_assert(i >= NR_PKEYS-2); 1162 + pkey_assert(i >= NR_PKEYS-3); 1176 1163 1177 1164 for (i = 0; i < nr_allocated_pkeys; i++) { 1178 1165 err = sys_pkey_free(allocated_pkeys[i]); 1179 1166 pkey_assert(!err); 1180 1167 rdpkru(); /* for shadow checking */ 1181 1168 } 1169 + } 1170 + 1171 + /* 1172 + * pkey 0 is special. It is allocated by default, so you do not 1173 + * have to call pkey_alloc() to use it first. Make sure that it 1174 + * is usable. 1175 + */ 1176 + void test_mprotect_with_pkey_0(int *ptr, u16 pkey) 1177 + { 1178 + long size; 1179 + int prot; 1180 + 1181 + assert(pkey_last_malloc_record); 1182 + size = pkey_last_malloc_record->size; 1183 + /* 1184 + * This is a bit of a hack. But mprotect() requires 1185 + * huge-page-aligned sizes when operating on hugetlbfs. 1186 + * So, make sure that we use something that's a multiple 1187 + * of a huge page when we can. 1188 + */ 1189 + if (size >= HPAGE_SIZE) 1190 + size = HPAGE_SIZE; 1191 + prot = pkey_last_malloc_record->prot; 1192 + 1193 + /* Use pkey 0 */ 1194 + mprotect_pkey(ptr, size, prot, 0); 1195 + 1196 + /* Make sure that we can set it back to the original pkey. */ 1197 + mprotect_pkey(ptr, size, prot, pkey); 1182 1198 } 1183 1199 1184 1200 void test_ptrace_of_child(int *ptr, u16 pkey) ··· 1276 1228 pkey_assert(ret != -1); 1277 1229 /* Now access from the current task, and expect NO exception: */ 1278 1230 peek_result = read_ptr(plain_ptr); 1279 - do_not_expect_pk_fault(); 1231 + do_not_expect_pk_fault("read plain pointer after ptrace"); 1280 1232 1281 1233 ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0); 1282 1234 pkey_assert(ret != -1); ··· 1289 1241 free(plain_ptr_unaligned); 1290 1242 } 1291 1243 1292 - void test_executing_on_unreadable_memory(int *ptr, u16 pkey) 1244 + void *get_pointer_to_instructions(void) 1293 1245 { 1294 1246 void *p1; 1295 - int scratch; 1296 - int ptr_contents; 1297 - int ret; 1298 1247 1299 1248 p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE); 1300 1249 dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write); ··· 1301 1256 /* Point 'p1' at the *second* page of the function: */ 1302 1257 p1 += PAGE_SIZE; 1303 1258 1259 + /* 1260 + * Try to ensure we fault this in on next touch to ensure 1261 + * we get an instruction fault as opposed to a data one 1262 + */ 1304 1263 madvise(p1, PAGE_SIZE, MADV_DONTNEED); 1264 + 1265 + return p1; 1266 + } 1267 + 1268 + void test_executing_on_unreadable_memory(int *ptr, u16 pkey) 1269 + { 1270 + void *p1; 1271 + int scratch; 1272 + int ptr_contents; 1273 + int ret; 1274 + 1275 + p1 = get_pointer_to_instructions(); 1305 1276 lots_o_noops_around_write(&scratch); 1306 1277 ptr_contents = read_ptr(p1); 1307 1278 dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); ··· 1333 1272 */ 1334 1273 madvise(p1, PAGE_SIZE, MADV_DONTNEED); 1335 1274 lots_o_noops_around_write(&scratch); 1336 - do_not_expect_pk_fault(); 1275 + do_not_expect_pk_fault("executing on PROT_EXEC memory"); 1337 1276 ptr_contents = read_ptr(p1); 1338 1277 dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 1339 1278 expected_pk_fault(pkey); 1279 + } 1280 + 1281 + void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey) 1282 + { 1283 + void *p1; 1284 + int scratch; 1285 + int ptr_contents; 1286 + int ret; 1287 + 1288 + dprintf1("%s() start\n", __func__); 1289 + 1290 + p1 = get_pointer_to_instructions(); 1291 + lots_o_noops_around_write(&scratch); 1292 + ptr_contents = read_ptr(p1); 1293 + dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 1294 + 1295 + /* Use a *normal* mprotect(), not mprotect_pkey(): */ 1296 + ret = mprotect(p1, PAGE_SIZE, PROT_EXEC); 1297 + pkey_assert(!ret); 1298 + 1299 + dprintf2("pkru: %x\n", rdpkru()); 1300 + 1301 + /* Make sure this is an *instruction* fault */ 1302 + madvise(p1, PAGE_SIZE, MADV_DONTNEED); 1303 + lots_o_noops_around_write(&scratch); 1304 + do_not_expect_pk_fault("executing on PROT_EXEC memory"); 1305 + ptr_contents = read_ptr(p1); 1306 + dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 1307 + expected_pk_fault(UNKNOWN_PKEY); 1308 + 1309 + /* 1310 + * Put the memory back to non-PROT_EXEC. Should clear the 1311 + * exec-only pkey off the VMA and allow it to be readable 1312 + * again. Go to PROT_NONE first to check for a kernel bug 1313 + * that did not clear the pkey when doing PROT_NONE. 1314 + */ 1315 + ret = mprotect(p1, PAGE_SIZE, PROT_NONE); 1316 + pkey_assert(!ret); 1317 + 1318 + ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC); 1319 + pkey_assert(!ret); 1320 + ptr_contents = read_ptr(p1); 1321 + do_not_expect_pk_fault("plain read on recently PROT_EXEC area"); 1340 1322 } 1341 1323 1342 1324 void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) ··· 1406 1302 test_kernel_gup_of_access_disabled_region, 1407 1303 test_kernel_gup_write_to_write_disabled_region, 1408 1304 test_executing_on_unreadable_memory, 1305 + test_implicit_mprotect_exec_only_memory, 1306 + test_mprotect_with_pkey_0, 1409 1307 test_ptrace_of_child, 1410 1308 test_pkey_syscalls_on_non_allocated_pkey, 1411 1309 test_pkey_syscalls_bad_args,