162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Tests Memory Protection Keys (see Documentation/core-api/protection-keys.rst) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * There are examples in here of: 662306a36Sopenharmony_ci * * how to set protection keys on memory 762306a36Sopenharmony_ci * * how to set/clear bits in pkey registers (the rights register) 862306a36Sopenharmony_ci * * how to handle SEGV_PKUERR signals and extract pkey-relevant 962306a36Sopenharmony_ci * information from the siginfo 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Things to add: 1262306a36Sopenharmony_ci * make sure KSM and KSM COW breaking works 1362306a36Sopenharmony_ci * prefault pages in at malloc, or not 1462306a36Sopenharmony_ci * protect MPX bounds tables with protection keys? 1562306a36Sopenharmony_ci * make sure VMA splitting/merging is working correctly 1662306a36Sopenharmony_ci * OOMs can destroy mm->mmap (see exit_mmap()), so make sure it is immune to pkeys 1762306a36Sopenharmony_ci * look for pkey "leaks" where it is still set on a VMA but "freed" back to the kernel 1862306a36Sopenharmony_ci * do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Compile like this: 2162306a36Sopenharmony_ci * gcc -mxsave -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm 2262306a36Sopenharmony_ci * gcc -mxsave -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#define _GNU_SOURCE 2562306a36Sopenharmony_ci#define __SANE_USERSPACE_TYPES__ 2662306a36Sopenharmony_ci#include <errno.h> 2762306a36Sopenharmony_ci#include <linux/elf.h> 2862306a36Sopenharmony_ci#include <linux/futex.h> 2962306a36Sopenharmony_ci#include <time.h> 3062306a36Sopenharmony_ci#include <sys/time.h> 3162306a36Sopenharmony_ci#include <sys/syscall.h> 3262306a36Sopenharmony_ci#include <string.h> 3362306a36Sopenharmony_ci#include <stdio.h> 3462306a36Sopenharmony_ci#include <stdint.h> 3562306a36Sopenharmony_ci#include <stdbool.h> 3662306a36Sopenharmony_ci#include <signal.h> 3762306a36Sopenharmony_ci#include <assert.h> 3862306a36Sopenharmony_ci#include <stdlib.h> 3962306a36Sopenharmony_ci#include <ucontext.h> 4062306a36Sopenharmony_ci#include <sys/mman.h> 4162306a36Sopenharmony_ci#include <sys/types.h> 4262306a36Sopenharmony_ci#include <sys/wait.h> 4362306a36Sopenharmony_ci#include <sys/stat.h> 4462306a36Sopenharmony_ci#include <fcntl.h> 4562306a36Sopenharmony_ci#include <unistd.h> 4662306a36Sopenharmony_ci#include <sys/ptrace.h> 4762306a36Sopenharmony_ci#include <setjmp.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "pkey-helpers.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciint iteration_nr = 1; 5262306a36Sopenharmony_ciint test_nr; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciu64 shadow_pkey_reg; 5562306a36Sopenharmony_ciint dprint_in_signal; 5662306a36Sopenharmony_cichar dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE]; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid cat_into_file(char *str, char *file) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci int fd = open(file, O_RDWR); 6162306a36Sopenharmony_ci int ret; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci dprintf2("%s(): writing '%s' to '%s'\n", __func__, str, file); 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * these need to be raw because they are called under 6662306a36Sopenharmony_ci * pkey_assert() 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci if (fd < 0) { 6962306a36Sopenharmony_ci fprintf(stderr, "error opening '%s'\n", str); 7062306a36Sopenharmony_ci perror("error: "); 7162306a36Sopenharmony_ci exit(__LINE__); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci ret = write(fd, str, strlen(str)); 7562306a36Sopenharmony_ci if (ret != strlen(str)) { 7662306a36Sopenharmony_ci perror("write to file failed"); 7762306a36Sopenharmony_ci fprintf(stderr, "filename: '%s' str: '%s'\n", file, str); 7862306a36Sopenharmony_ci exit(__LINE__); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci close(fd); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#if CONTROL_TRACING > 0 8462306a36Sopenharmony_cistatic int warned_tracing; 8562306a36Sopenharmony_ciint tracing_root_ok(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (geteuid() != 0) { 8862306a36Sopenharmony_ci if (!warned_tracing) 8962306a36Sopenharmony_ci fprintf(stderr, "WARNING: not run as root, " 9062306a36Sopenharmony_ci "can not do tracing control\n"); 9162306a36Sopenharmony_ci warned_tracing = 1; 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci return 1; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid tracing_on(void) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci#if CONTROL_TRACING > 0 10162306a36Sopenharmony_ci#define TRACEDIR "/sys/kernel/tracing" 10262306a36Sopenharmony_ci char pidstr[32]; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!tracing_root_ok()) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci sprintf(pidstr, "%d", getpid()); 10862306a36Sopenharmony_ci cat_into_file("0", TRACEDIR "/tracing_on"); 10962306a36Sopenharmony_ci cat_into_file("\n", TRACEDIR "/trace"); 11062306a36Sopenharmony_ci if (1) { 11162306a36Sopenharmony_ci cat_into_file("function_graph", TRACEDIR "/current_tracer"); 11262306a36Sopenharmony_ci cat_into_file("1", TRACEDIR "/options/funcgraph-proc"); 11362306a36Sopenharmony_ci } else { 11462306a36Sopenharmony_ci cat_into_file("nop", TRACEDIR "/current_tracer"); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci cat_into_file(pidstr, TRACEDIR "/set_ftrace_pid"); 11762306a36Sopenharmony_ci cat_into_file("1", TRACEDIR "/tracing_on"); 11862306a36Sopenharmony_ci dprintf1("enabled tracing\n"); 11962306a36Sopenharmony_ci#endif 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid tracing_off(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci#if CONTROL_TRACING > 0 12562306a36Sopenharmony_ci if (!tracing_root_ok()) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci cat_into_file("0", "/sys/kernel/tracing/tracing_on"); 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_civoid abort_hooks(void) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci fprintf(stderr, "running %s()...\n", __func__); 13462306a36Sopenharmony_ci tracing_off(); 13562306a36Sopenharmony_ci#ifdef SLEEP_ON_ABORT 13662306a36Sopenharmony_ci sleep(SLEEP_ON_ABORT); 13762306a36Sopenharmony_ci#endif 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * This attempts to have roughly a page of instructions followed by a few 14262306a36Sopenharmony_ci * instructions that do a write, and another page of instructions. That 14362306a36Sopenharmony_ci * way, we are pretty sure that the write is in the second page of 14462306a36Sopenharmony_ci * instructions and has at least a page of padding behind it. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * *That* lets us be sure to madvise() away the write instruction, which 14762306a36Sopenharmony_ci * will then fault, which makes sure that the fault code handles 14862306a36Sopenharmony_ci * execute-only memory properly. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci#ifdef __powerpc64__ 15162306a36Sopenharmony_ci/* This way, both 4K and 64K alignment are maintained */ 15262306a36Sopenharmony_ci__attribute__((__aligned__(65536))) 15362306a36Sopenharmony_ci#else 15462306a36Sopenharmony_ci__attribute__((__aligned__(PAGE_SIZE))) 15562306a36Sopenharmony_ci#endif 15662306a36Sopenharmony_civoid lots_o_noops_around_write(int *write_to_me) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci dprintf3("running %s()\n", __func__); 15962306a36Sopenharmony_ci __page_o_noops(); 16062306a36Sopenharmony_ci /* Assume this happens in the second page of instructions: */ 16162306a36Sopenharmony_ci *write_to_me = __LINE__; 16262306a36Sopenharmony_ci /* pad out by another page: */ 16362306a36Sopenharmony_ci __page_o_noops(); 16462306a36Sopenharmony_ci dprintf3("%s() done\n", __func__); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_civoid dump_mem(void *dumpme, int len_bytes) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci char *c = (void *)dumpme; 17062306a36Sopenharmony_ci int i; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (i = 0; i < len_bytes; i += sizeof(u64)) { 17362306a36Sopenharmony_ci u64 *ptr = (u64 *)(c + i); 17462306a36Sopenharmony_ci dprintf1("dump[%03d][@%p]: %016llx\n", i, ptr, *ptr); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic u32 hw_pkey_get(int pkey, unsigned long flags) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci u64 pkey_reg = __read_pkey_reg(); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n", 18362306a36Sopenharmony_ci __func__, pkey, flags, 0, 0); 18462306a36Sopenharmony_ci dprintf2("%s() raw pkey_reg: %016llx\n", __func__, pkey_reg); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return (u32) get_pkey_bits(pkey_reg, pkey); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); 19262306a36Sopenharmony_ci u64 old_pkey_reg = __read_pkey_reg(); 19362306a36Sopenharmony_ci u64 new_pkey_reg; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* make sure that 'rights' only contains the bits we expect: */ 19662306a36Sopenharmony_ci assert(!(rights & ~mask)); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* modify bits accordingly in old pkey_reg and assign it */ 19962306a36Sopenharmony_ci new_pkey_reg = set_pkey_bits(old_pkey_reg, pkey, rights); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci __write_pkey_reg(new_pkey_reg); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x" 20462306a36Sopenharmony_ci " pkey_reg now: %016llx old_pkey_reg: %016llx\n", 20562306a36Sopenharmony_ci __func__, pkey, rights, flags, 0, __read_pkey_reg(), 20662306a36Sopenharmony_ci old_pkey_reg); 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_civoid pkey_disable_set(int pkey, int flags) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci unsigned long syscall_flags = 0; 21362306a36Sopenharmony_ci int ret; 21462306a36Sopenharmony_ci int pkey_rights; 21562306a36Sopenharmony_ci u64 orig_pkey_reg = read_pkey_reg(); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci dprintf1("START->%s(%d, 0x%x)\n", __func__, 21862306a36Sopenharmony_ci pkey, flags); 21962306a36Sopenharmony_ci pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci pkey_rights = hw_pkey_get(pkey, syscall_flags); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 22462306a36Sopenharmony_ci pkey, pkey, pkey_rights); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci pkey_assert(pkey_rights >= 0); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci pkey_rights |= flags; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ret = hw_pkey_set(pkey, pkey_rights, syscall_flags); 23162306a36Sopenharmony_ci assert(!ret); 23262306a36Sopenharmony_ci /* pkey_reg and flags have the same format */ 23362306a36Sopenharmony_ci shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights); 23462306a36Sopenharmony_ci dprintf1("%s(%d) shadow: 0x%016llx\n", 23562306a36Sopenharmony_ci __func__, pkey, shadow_pkey_reg); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pkey_assert(ret >= 0); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci pkey_rights = hw_pkey_get(pkey, syscall_flags); 24062306a36Sopenharmony_ci dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 24162306a36Sopenharmony_ci pkey, pkey, pkey_rights); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dprintf1("%s(%d) pkey_reg: 0x%016llx\n", 24462306a36Sopenharmony_ci __func__, pkey, read_pkey_reg()); 24562306a36Sopenharmony_ci if (flags) 24662306a36Sopenharmony_ci pkey_assert(read_pkey_reg() >= orig_pkey_reg); 24762306a36Sopenharmony_ci dprintf1("END<---%s(%d, 0x%x)\n", __func__, 24862306a36Sopenharmony_ci pkey, flags); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_civoid pkey_disable_clear(int pkey, int flags) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci unsigned long syscall_flags = 0; 25462306a36Sopenharmony_ci int ret; 25562306a36Sopenharmony_ci int pkey_rights = hw_pkey_get(pkey, syscall_flags); 25662306a36Sopenharmony_ci u64 orig_pkey_reg = read_pkey_reg(); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 26162306a36Sopenharmony_ci pkey, pkey, pkey_rights); 26262306a36Sopenharmony_ci pkey_assert(pkey_rights >= 0); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci pkey_rights &= ~flags; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ret = hw_pkey_set(pkey, pkey_rights, 0); 26762306a36Sopenharmony_ci shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights); 26862306a36Sopenharmony_ci pkey_assert(ret >= 0); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci pkey_rights = hw_pkey_get(pkey, syscall_flags); 27162306a36Sopenharmony_ci dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, 27262306a36Sopenharmony_ci pkey, pkey, pkey_rights); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dprintf1("%s(%d) pkey_reg: 0x%016llx\n", __func__, 27562306a36Sopenharmony_ci pkey, read_pkey_reg()); 27662306a36Sopenharmony_ci if (flags) 27762306a36Sopenharmony_ci assert(read_pkey_reg() <= orig_pkey_reg); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid pkey_write_allow(int pkey) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci pkey_disable_clear(pkey, PKEY_DISABLE_WRITE); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_civoid pkey_write_deny(int pkey) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci pkey_disable_set(pkey, PKEY_DISABLE_WRITE); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_civoid pkey_access_allow(int pkey) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci pkey_disable_clear(pkey, PKEY_DISABLE_ACCESS); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_civoid pkey_access_deny(int pkey) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci pkey_disable_set(pkey, PKEY_DISABLE_ACCESS); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic char *si_code_str(int si_code) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci if (si_code == SEGV_MAPERR) 30062306a36Sopenharmony_ci return "SEGV_MAPERR"; 30162306a36Sopenharmony_ci if (si_code == SEGV_ACCERR) 30262306a36Sopenharmony_ci return "SEGV_ACCERR"; 30362306a36Sopenharmony_ci if (si_code == SEGV_BNDERR) 30462306a36Sopenharmony_ci return "SEGV_BNDERR"; 30562306a36Sopenharmony_ci if (si_code == SEGV_PKUERR) 30662306a36Sopenharmony_ci return "SEGV_PKUERR"; 30762306a36Sopenharmony_ci return "UNKNOWN"; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ciint pkey_faults; 31162306a36Sopenharmony_ciint last_si_pkey = -1; 31262306a36Sopenharmony_civoid signal_handler(int signum, siginfo_t *si, void *vucontext) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci ucontext_t *uctxt = vucontext; 31562306a36Sopenharmony_ci int trapno; 31662306a36Sopenharmony_ci unsigned long ip; 31762306a36Sopenharmony_ci char *fpregs; 31862306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) /* arch */ 31962306a36Sopenharmony_ci u32 *pkey_reg_ptr; 32062306a36Sopenharmony_ci int pkey_reg_offset; 32162306a36Sopenharmony_ci#endif /* arch */ 32262306a36Sopenharmony_ci u64 siginfo_pkey; 32362306a36Sopenharmony_ci u32 *si_pkey_ptr; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci dprint_in_signal = 1; 32662306a36Sopenharmony_ci dprintf1(">>>>===============SIGSEGV============================\n"); 32762306a36Sopenharmony_ci dprintf1("%s()::%d, pkey_reg: 0x%016llx shadow: %016llx\n", 32862306a36Sopenharmony_ci __func__, __LINE__, 32962306a36Sopenharmony_ci __read_pkey_reg(), shadow_pkey_reg); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO]; 33262306a36Sopenharmony_ci ip = uctxt->uc_mcontext.gregs[REG_IP_IDX]; 33362306a36Sopenharmony_ci fpregs = (char *) uctxt->uc_mcontext.fpregs; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci dprintf2("%s() trapno: %d ip: 0x%016lx info->si_code: %s/%d\n", 33662306a36Sopenharmony_ci __func__, trapno, ip, si_code_str(si->si_code), 33762306a36Sopenharmony_ci si->si_code); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) /* arch */ 34062306a36Sopenharmony_ci#ifdef __i386__ 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * 32-bit has some extra padding so that userspace can tell whether 34362306a36Sopenharmony_ci * the XSTATE header is present in addition to the "legacy" FPU 34462306a36Sopenharmony_ci * state. We just assume that it is here. 34562306a36Sopenharmony_ci */ 34662306a36Sopenharmony_ci fpregs += 0x70; 34762306a36Sopenharmony_ci#endif /* i386 */ 34862306a36Sopenharmony_ci pkey_reg_offset = pkey_reg_xstate_offset(); 34962306a36Sopenharmony_ci pkey_reg_ptr = (void *)(&fpregs[pkey_reg_offset]); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * If we got a PKEY fault, we *HAVE* to have at least one bit set in 35362306a36Sopenharmony_ci * here. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci dprintf1("pkey_reg_xstate_offset: %d\n", pkey_reg_xstate_offset()); 35662306a36Sopenharmony_ci if (DEBUG_LEVEL > 4) 35762306a36Sopenharmony_ci dump_mem(pkey_reg_ptr - 128, 256); 35862306a36Sopenharmony_ci pkey_assert(*pkey_reg_ptr); 35962306a36Sopenharmony_ci#endif /* arch */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci dprintf1("siginfo: %p\n", si); 36262306a36Sopenharmony_ci dprintf1(" fpregs: %p\n", fpregs); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if ((si->si_code == SEGV_MAPERR) || 36562306a36Sopenharmony_ci (si->si_code == SEGV_ACCERR) || 36662306a36Sopenharmony_ci (si->si_code == SEGV_BNDERR)) { 36762306a36Sopenharmony_ci printf("non-PK si_code, exiting...\n"); 36862306a36Sopenharmony_ci exit(4); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci si_pkey_ptr = siginfo_get_pkey_ptr(si); 37262306a36Sopenharmony_ci dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); 37362306a36Sopenharmony_ci dump_mem((u8 *)si_pkey_ptr - 8, 24); 37462306a36Sopenharmony_ci siginfo_pkey = *si_pkey_ptr; 37562306a36Sopenharmony_ci pkey_assert(siginfo_pkey < NR_PKEYS); 37662306a36Sopenharmony_ci last_si_pkey = siginfo_pkey; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * need __read_pkey_reg() version so we do not do shadow_pkey_reg 38062306a36Sopenharmony_ci * checking 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci dprintf1("signal pkey_reg from pkey_reg: %016llx\n", 38362306a36Sopenharmony_ci __read_pkey_reg()); 38462306a36Sopenharmony_ci dprintf1("pkey from siginfo: %016llx\n", siginfo_pkey); 38562306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) /* arch */ 38662306a36Sopenharmony_ci dprintf1("signal pkey_reg from xsave: %08x\n", *pkey_reg_ptr); 38762306a36Sopenharmony_ci *(u64 *)pkey_reg_ptr = 0x00000000; 38862306a36Sopenharmony_ci dprintf1("WARNING: set PKEY_REG=0 to allow faulting instruction to continue\n"); 38962306a36Sopenharmony_ci#elif defined(__powerpc64__) /* arch */ 39062306a36Sopenharmony_ci /* restore access and let the faulting instruction continue */ 39162306a36Sopenharmony_ci pkey_access_allow(siginfo_pkey); 39262306a36Sopenharmony_ci#endif /* arch */ 39362306a36Sopenharmony_ci pkey_faults++; 39462306a36Sopenharmony_ci dprintf1("<<<<==================================================\n"); 39562306a36Sopenharmony_ci dprint_in_signal = 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ciint wait_all_children(void) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int status; 40162306a36Sopenharmony_ci return waitpid(-1, &status, 0); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_civoid sig_chld(int x) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci dprint_in_signal = 1; 40762306a36Sopenharmony_ci dprintf2("[%d] SIGCHLD: %d\n", getpid(), x); 40862306a36Sopenharmony_ci dprint_in_signal = 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_civoid setup_sigsegv_handler(void) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int r, rs; 41462306a36Sopenharmony_ci struct sigaction newact; 41562306a36Sopenharmony_ci struct sigaction oldact; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* #PF is mapped to sigsegv */ 41862306a36Sopenharmony_ci int signum = SIGSEGV; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci newact.sa_handler = 0; 42162306a36Sopenharmony_ci newact.sa_sigaction = signal_handler; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /*sigset_t - signals to block while in the handler */ 42462306a36Sopenharmony_ci /* get the old signal mask. */ 42562306a36Sopenharmony_ci rs = sigprocmask(SIG_SETMASK, 0, &newact.sa_mask); 42662306a36Sopenharmony_ci pkey_assert(rs == 0); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* call sa_sigaction, not sa_handler*/ 42962306a36Sopenharmony_ci newact.sa_flags = SA_SIGINFO; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci newact.sa_restorer = 0; /* void(*)(), obsolete */ 43262306a36Sopenharmony_ci r = sigaction(signum, &newact, &oldact); 43362306a36Sopenharmony_ci r = sigaction(SIGALRM, &newact, &oldact); 43462306a36Sopenharmony_ci pkey_assert(r == 0); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_civoid setup_handlers(void) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci signal(SIGCHLD, &sig_chld); 44062306a36Sopenharmony_ci setup_sigsegv_handler(); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cipid_t fork_lazy_child(void) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci pid_t forkret; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci forkret = fork(); 44862306a36Sopenharmony_ci pkey_assert(forkret >= 0); 44962306a36Sopenharmony_ci dprintf3("[%d] fork() ret: %d\n", getpid(), forkret); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!forkret) { 45262306a36Sopenharmony_ci /* in the child */ 45362306a36Sopenharmony_ci while (1) { 45462306a36Sopenharmony_ci dprintf1("child sleeping...\n"); 45562306a36Sopenharmony_ci sleep(30); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci return forkret; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ciint sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot, 46262306a36Sopenharmony_ci unsigned long pkey) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci int sret; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci dprintf2("%s(0x%p, %zx, prot=%lx, pkey=%lx)\n", __func__, 46762306a36Sopenharmony_ci ptr, size, orig_prot, pkey); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci errno = 0; 47062306a36Sopenharmony_ci sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey); 47162306a36Sopenharmony_ci if (errno) { 47262306a36Sopenharmony_ci dprintf2("SYS_mprotect_key sret: %d\n", sret); 47362306a36Sopenharmony_ci dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot); 47462306a36Sopenharmony_ci dprintf2("SYS_mprotect_key failed, errno: %d\n", errno); 47562306a36Sopenharmony_ci if (DEBUG_LEVEL >= 2) 47662306a36Sopenharmony_ci perror("SYS_mprotect_pkey"); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci return sret; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ciint sys_pkey_alloc(unsigned long flags, unsigned long init_val) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci int ret = syscall(SYS_pkey_alloc, flags, init_val); 48462306a36Sopenharmony_ci dprintf1("%s(flags=%lx, init_val=%lx) syscall ret: %d errno: %d\n", 48562306a36Sopenharmony_ci __func__, flags, init_val, ret, errno); 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ciint alloc_pkey(void) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci int ret; 49262306a36Sopenharmony_ci unsigned long init_val = 0x0; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci dprintf1("%s()::%d, pkey_reg: 0x%016llx shadow: %016llx\n", 49562306a36Sopenharmony_ci __func__, __LINE__, __read_pkey_reg(), shadow_pkey_reg); 49662306a36Sopenharmony_ci ret = sys_pkey_alloc(0, init_val); 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * pkey_alloc() sets PKEY register, so we need to reflect it in 49962306a36Sopenharmony_ci * shadow_pkey_reg: 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx" 50262306a36Sopenharmony_ci " shadow: 0x%016llx\n", 50362306a36Sopenharmony_ci __func__, __LINE__, ret, __read_pkey_reg(), 50462306a36Sopenharmony_ci shadow_pkey_reg); 50562306a36Sopenharmony_ci if (ret > 0) { 50662306a36Sopenharmony_ci /* clear both the bits: */ 50762306a36Sopenharmony_ci shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret, 50862306a36Sopenharmony_ci ~PKEY_MASK); 50962306a36Sopenharmony_ci dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx" 51062306a36Sopenharmony_ci " shadow: 0x%016llx\n", 51162306a36Sopenharmony_ci __func__, 51262306a36Sopenharmony_ci __LINE__, ret, __read_pkey_reg(), 51362306a36Sopenharmony_ci shadow_pkey_reg); 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * move the new state in from init_val 51662306a36Sopenharmony_ci * (remember, we cheated and init_val == pkey_reg format) 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret, 51962306a36Sopenharmony_ci init_val); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx" 52262306a36Sopenharmony_ci " shadow: 0x%016llx\n", 52362306a36Sopenharmony_ci __func__, __LINE__, ret, __read_pkey_reg(), 52462306a36Sopenharmony_ci shadow_pkey_reg); 52562306a36Sopenharmony_ci dprintf1("%s()::%d errno: %d\n", __func__, __LINE__, errno); 52662306a36Sopenharmony_ci /* for shadow checking: */ 52762306a36Sopenharmony_ci read_pkey_reg(); 52862306a36Sopenharmony_ci dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx" 52962306a36Sopenharmony_ci " shadow: 0x%016llx\n", 53062306a36Sopenharmony_ci __func__, __LINE__, ret, __read_pkey_reg(), 53162306a36Sopenharmony_ci shadow_pkey_reg); 53262306a36Sopenharmony_ci return ret; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciint sys_pkey_free(unsigned long pkey) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci int ret = syscall(SYS_pkey_free, pkey); 53862306a36Sopenharmony_ci dprintf1("%s(pkey=%ld) syscall ret: %d\n", __func__, pkey, ret); 53962306a36Sopenharmony_ci return ret; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * I had a bug where pkey bits could be set by mprotect() but 54462306a36Sopenharmony_ci * not cleared. This ensures we get lots of random bit sets 54562306a36Sopenharmony_ci * and clears on the vma and pte pkey bits. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ciint alloc_random_pkey(void) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci int max_nr_pkey_allocs; 55062306a36Sopenharmony_ci int ret; 55162306a36Sopenharmony_ci int i; 55262306a36Sopenharmony_ci int alloced_pkeys[NR_PKEYS]; 55362306a36Sopenharmony_ci int nr_alloced = 0; 55462306a36Sopenharmony_ci int random_index; 55562306a36Sopenharmony_ci memset(alloced_pkeys, 0, sizeof(alloced_pkeys)); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* allocate every possible key and make a note of which ones we got */ 55862306a36Sopenharmony_ci max_nr_pkey_allocs = NR_PKEYS; 55962306a36Sopenharmony_ci for (i = 0; i < max_nr_pkey_allocs; i++) { 56062306a36Sopenharmony_ci int new_pkey = alloc_pkey(); 56162306a36Sopenharmony_ci if (new_pkey < 0) 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci alloced_pkeys[nr_alloced++] = new_pkey; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci pkey_assert(nr_alloced > 0); 56762306a36Sopenharmony_ci /* select a random one out of the allocated ones */ 56862306a36Sopenharmony_ci random_index = rand() % nr_alloced; 56962306a36Sopenharmony_ci ret = alloced_pkeys[random_index]; 57062306a36Sopenharmony_ci /* now zero it out so we don't free it next */ 57162306a36Sopenharmony_ci alloced_pkeys[random_index] = 0; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* go through the allocated ones that we did not want and free them */ 57462306a36Sopenharmony_ci for (i = 0; i < nr_alloced; i++) { 57562306a36Sopenharmony_ci int free_ret; 57662306a36Sopenharmony_ci if (!alloced_pkeys[i]) 57762306a36Sopenharmony_ci continue; 57862306a36Sopenharmony_ci free_ret = sys_pkey_free(alloced_pkeys[i]); 57962306a36Sopenharmony_ci pkey_assert(!free_ret); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx" 58262306a36Sopenharmony_ci " shadow: 0x%016llx\n", __func__, 58362306a36Sopenharmony_ci __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg); 58462306a36Sopenharmony_ci return ret; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ciint mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot, 58862306a36Sopenharmony_ci unsigned long pkey) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci int nr_iterations = random() % 100; 59162306a36Sopenharmony_ci int ret; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci while (0) { 59462306a36Sopenharmony_ci int rpkey = alloc_random_pkey(); 59562306a36Sopenharmony_ci ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey); 59662306a36Sopenharmony_ci dprintf1("sys_mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n", 59762306a36Sopenharmony_ci ptr, size, orig_prot, pkey, ret); 59862306a36Sopenharmony_ci if (nr_iterations-- < 0) 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx" 60262306a36Sopenharmony_ci " shadow: 0x%016llx\n", 60362306a36Sopenharmony_ci __func__, __LINE__, ret, __read_pkey_reg(), 60462306a36Sopenharmony_ci shadow_pkey_reg); 60562306a36Sopenharmony_ci sys_pkey_free(rpkey); 60662306a36Sopenharmony_ci dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx" 60762306a36Sopenharmony_ci " shadow: 0x%016llx\n", 60862306a36Sopenharmony_ci __func__, __LINE__, ret, __read_pkey_reg(), 60962306a36Sopenharmony_ci shadow_pkey_reg); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci pkey_assert(pkey < NR_PKEYS); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey); 61462306a36Sopenharmony_ci dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n", 61562306a36Sopenharmony_ci ptr, size, orig_prot, pkey, ret); 61662306a36Sopenharmony_ci pkey_assert(!ret); 61762306a36Sopenharmony_ci dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx" 61862306a36Sopenharmony_ci " shadow: 0x%016llx\n", __func__, 61962306a36Sopenharmony_ci __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg); 62062306a36Sopenharmony_ci return ret; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistruct pkey_malloc_record { 62462306a36Sopenharmony_ci void *ptr; 62562306a36Sopenharmony_ci long size; 62662306a36Sopenharmony_ci int prot; 62762306a36Sopenharmony_ci}; 62862306a36Sopenharmony_cistruct pkey_malloc_record *pkey_malloc_records; 62962306a36Sopenharmony_cistruct pkey_malloc_record *pkey_last_malloc_record; 63062306a36Sopenharmony_cilong nr_pkey_malloc_records; 63162306a36Sopenharmony_civoid record_pkey_malloc(void *ptr, long size, int prot) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci long i; 63462306a36Sopenharmony_ci struct pkey_malloc_record *rec = NULL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci for (i = 0; i < nr_pkey_malloc_records; i++) { 63762306a36Sopenharmony_ci rec = &pkey_malloc_records[i]; 63862306a36Sopenharmony_ci /* find a free record */ 63962306a36Sopenharmony_ci if (rec) 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci if (!rec) { 64362306a36Sopenharmony_ci /* every record is full */ 64462306a36Sopenharmony_ci size_t old_nr_records = nr_pkey_malloc_records; 64562306a36Sopenharmony_ci size_t new_nr_records = (nr_pkey_malloc_records * 2 + 1); 64662306a36Sopenharmony_ci size_t new_size = new_nr_records * sizeof(struct pkey_malloc_record); 64762306a36Sopenharmony_ci dprintf2("new_nr_records: %zd\n", new_nr_records); 64862306a36Sopenharmony_ci dprintf2("new_size: %zd\n", new_size); 64962306a36Sopenharmony_ci pkey_malloc_records = realloc(pkey_malloc_records, new_size); 65062306a36Sopenharmony_ci pkey_assert(pkey_malloc_records != NULL); 65162306a36Sopenharmony_ci rec = &pkey_malloc_records[nr_pkey_malloc_records]; 65262306a36Sopenharmony_ci /* 65362306a36Sopenharmony_ci * realloc() does not initialize memory, so zero it from 65462306a36Sopenharmony_ci * the first new record all the way to the end. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci for (i = 0; i < new_nr_records - old_nr_records; i++) 65762306a36Sopenharmony_ci memset(rec + i, 0, sizeof(*rec)); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci dprintf3("filling malloc record[%d/%p]: {%p, %ld}\n", 66062306a36Sopenharmony_ci (int)(rec - pkey_malloc_records), rec, ptr, size); 66162306a36Sopenharmony_ci rec->ptr = ptr; 66262306a36Sopenharmony_ci rec->size = size; 66362306a36Sopenharmony_ci rec->prot = prot; 66462306a36Sopenharmony_ci pkey_last_malloc_record = rec; 66562306a36Sopenharmony_ci nr_pkey_malloc_records++; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_civoid free_pkey_malloc(void *ptr) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci long i; 67162306a36Sopenharmony_ci int ret; 67262306a36Sopenharmony_ci dprintf3("%s(%p)\n", __func__, ptr); 67362306a36Sopenharmony_ci for (i = 0; i < nr_pkey_malloc_records; i++) { 67462306a36Sopenharmony_ci struct pkey_malloc_record *rec = &pkey_malloc_records[i]; 67562306a36Sopenharmony_ci dprintf4("looking for ptr %p at record[%ld/%p]: {%p, %ld}\n", 67662306a36Sopenharmony_ci ptr, i, rec, rec->ptr, rec->size); 67762306a36Sopenharmony_ci if ((ptr < rec->ptr) || 67862306a36Sopenharmony_ci (ptr >= rec->ptr + rec->size)) 67962306a36Sopenharmony_ci continue; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci dprintf3("found ptr %p at record[%ld/%p]: {%p, %ld}\n", 68262306a36Sopenharmony_ci ptr, i, rec, rec->ptr, rec->size); 68362306a36Sopenharmony_ci nr_pkey_malloc_records--; 68462306a36Sopenharmony_ci ret = munmap(rec->ptr, rec->size); 68562306a36Sopenharmony_ci dprintf3("munmap ret: %d\n", ret); 68662306a36Sopenharmony_ci pkey_assert(!ret); 68762306a36Sopenharmony_ci dprintf3("clearing rec->ptr, rec: %p\n", rec); 68862306a36Sopenharmony_ci rec->ptr = NULL; 68962306a36Sopenharmony_ci dprintf3("done clearing rec->ptr, rec: %p\n", rec); 69062306a36Sopenharmony_ci return; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci pkey_assert(false); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_civoid *malloc_pkey_with_mprotect(long size, int prot, u16 pkey) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci void *ptr; 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci read_pkey_reg(); 70262306a36Sopenharmony_ci dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__, 70362306a36Sopenharmony_ci size, prot, pkey); 70462306a36Sopenharmony_ci pkey_assert(pkey < NR_PKEYS); 70562306a36Sopenharmony_ci ptr = mmap(NULL, size, prot, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 70662306a36Sopenharmony_ci pkey_assert(ptr != (void *)-1); 70762306a36Sopenharmony_ci ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey); 70862306a36Sopenharmony_ci pkey_assert(!ret); 70962306a36Sopenharmony_ci record_pkey_malloc(ptr, size, prot); 71062306a36Sopenharmony_ci read_pkey_reg(); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr); 71362306a36Sopenharmony_ci return ptr; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_civoid *malloc_pkey_anon_huge(long size, int prot, u16 pkey) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci void *ptr; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__, 72262306a36Sopenharmony_ci size, prot, pkey); 72362306a36Sopenharmony_ci /* 72462306a36Sopenharmony_ci * Guarantee we can fit at least one huge page in the resulting 72562306a36Sopenharmony_ci * allocation by allocating space for 2: 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci size = ALIGN_UP(size, HPAGE_SIZE * 2); 72862306a36Sopenharmony_ci ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 72962306a36Sopenharmony_ci pkey_assert(ptr != (void *)-1); 73062306a36Sopenharmony_ci record_pkey_malloc(ptr, size, prot); 73162306a36Sopenharmony_ci mprotect_pkey(ptr, size, prot, pkey); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci dprintf1("unaligned ptr: %p\n", ptr); 73462306a36Sopenharmony_ci ptr = ALIGN_PTR_UP(ptr, HPAGE_SIZE); 73562306a36Sopenharmony_ci dprintf1(" aligned ptr: %p\n", ptr); 73662306a36Sopenharmony_ci ret = madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE); 73762306a36Sopenharmony_ci dprintf1("MADV_HUGEPAGE ret: %d\n", ret); 73862306a36Sopenharmony_ci ret = madvise(ptr, HPAGE_SIZE, MADV_WILLNEED); 73962306a36Sopenharmony_ci dprintf1("MADV_WILLNEED ret: %d\n", ret); 74062306a36Sopenharmony_ci memset(ptr, 0, HPAGE_SIZE); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci dprintf1("mmap()'d thp for pkey %d @ %p\n", pkey, ptr); 74362306a36Sopenharmony_ci return ptr; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ciint hugetlb_setup_ok; 74762306a36Sopenharmony_ci#define SYSFS_FMT_NR_HUGE_PAGES "/sys/kernel/mm/hugepages/hugepages-%ldkB/nr_hugepages" 74862306a36Sopenharmony_ci#define GET_NR_HUGE_PAGES 10 74962306a36Sopenharmony_civoid setup_hugetlbfs(void) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci int err; 75262306a36Sopenharmony_ci int fd; 75362306a36Sopenharmony_ci char buf[256]; 75462306a36Sopenharmony_ci long hpagesz_kb; 75562306a36Sopenharmony_ci long hpagesz_mb; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (geteuid() != 0) { 75862306a36Sopenharmony_ci fprintf(stderr, "WARNING: not run as root, can not do hugetlb test\n"); 75962306a36Sopenharmony_ci return; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci cat_into_file(__stringify(GET_NR_HUGE_PAGES), "/proc/sys/vm/nr_hugepages"); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* 76562306a36Sopenharmony_ci * Now go make sure that we got the pages and that they 76662306a36Sopenharmony_ci * are PMD-level pages. Someone might have made PUD-level 76762306a36Sopenharmony_ci * pages the default. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci hpagesz_kb = HPAGE_SIZE / 1024; 77062306a36Sopenharmony_ci hpagesz_mb = hpagesz_kb / 1024; 77162306a36Sopenharmony_ci sprintf(buf, SYSFS_FMT_NR_HUGE_PAGES, hpagesz_kb); 77262306a36Sopenharmony_ci fd = open(buf, O_RDONLY); 77362306a36Sopenharmony_ci if (fd < 0) { 77462306a36Sopenharmony_ci fprintf(stderr, "opening sysfs %ldM hugetlb config: %s\n", 77562306a36Sopenharmony_ci hpagesz_mb, strerror(errno)); 77662306a36Sopenharmony_ci return; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* -1 to guarantee leaving the trailing \0 */ 78062306a36Sopenharmony_ci err = read(fd, buf, sizeof(buf)-1); 78162306a36Sopenharmony_ci close(fd); 78262306a36Sopenharmony_ci if (err <= 0) { 78362306a36Sopenharmony_ci fprintf(stderr, "reading sysfs %ldM hugetlb config: %s\n", 78462306a36Sopenharmony_ci hpagesz_mb, strerror(errno)); 78562306a36Sopenharmony_ci return; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (atoi(buf) != GET_NR_HUGE_PAGES) { 78962306a36Sopenharmony_ci fprintf(stderr, "could not confirm %ldM pages, got: '%s' expected %d\n", 79062306a36Sopenharmony_ci hpagesz_mb, buf, GET_NR_HUGE_PAGES); 79162306a36Sopenharmony_ci return; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci hugetlb_setup_ok = 1; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_civoid *malloc_pkey_hugetlb(long size, int prot, u16 pkey) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci void *ptr; 80062306a36Sopenharmony_ci int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (!hugetlb_setup_ok) 80362306a36Sopenharmony_ci return PTR_ERR_ENOTSUP; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci dprintf1("doing %s(%ld, %x, %x)\n", __func__, size, prot, pkey); 80662306a36Sopenharmony_ci size = ALIGN_UP(size, HPAGE_SIZE * 2); 80762306a36Sopenharmony_ci pkey_assert(pkey < NR_PKEYS); 80862306a36Sopenharmony_ci ptr = mmap(NULL, size, PROT_NONE, flags, -1, 0); 80962306a36Sopenharmony_ci pkey_assert(ptr != (void *)-1); 81062306a36Sopenharmony_ci mprotect_pkey(ptr, size, prot, pkey); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci record_pkey_malloc(ptr, size, prot); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr); 81562306a36Sopenharmony_ci return ptr; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_civoid *malloc_pkey_mmap_dax(long size, int prot, u16 pkey) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci void *ptr; 82162306a36Sopenharmony_ci int fd; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__, 82462306a36Sopenharmony_ci size, prot, pkey); 82562306a36Sopenharmony_ci pkey_assert(pkey < NR_PKEYS); 82662306a36Sopenharmony_ci fd = open("/dax/foo", O_RDWR); 82762306a36Sopenharmony_ci pkey_assert(fd >= 0); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci ptr = mmap(0, size, prot, MAP_SHARED, fd, 0); 83062306a36Sopenharmony_ci pkey_assert(ptr != (void *)-1); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci mprotect_pkey(ptr, size, prot, pkey); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci record_pkey_malloc(ptr, size, prot); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr); 83762306a36Sopenharmony_ci close(fd); 83862306a36Sopenharmony_ci return ptr; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_civoid *(*pkey_malloc[])(long size, int prot, u16 pkey) = { 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci malloc_pkey_with_mprotect, 84462306a36Sopenharmony_ci malloc_pkey_with_mprotect_subpage, 84562306a36Sopenharmony_ci malloc_pkey_anon_huge, 84662306a36Sopenharmony_ci malloc_pkey_hugetlb 84762306a36Sopenharmony_ci/* can not do direct with the pkey_mprotect() API: 84862306a36Sopenharmony_ci malloc_pkey_mmap_direct, 84962306a36Sopenharmony_ci malloc_pkey_mmap_dax, 85062306a36Sopenharmony_ci*/ 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_civoid *malloc_pkey(long size, int prot, u16 pkey) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci void *ret; 85662306a36Sopenharmony_ci static int malloc_type; 85762306a36Sopenharmony_ci int nr_malloc_types = ARRAY_SIZE(pkey_malloc); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci pkey_assert(pkey < NR_PKEYS); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci while (1) { 86262306a36Sopenharmony_ci pkey_assert(malloc_type < nr_malloc_types); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ret = pkey_malloc[malloc_type](size, prot, pkey); 86562306a36Sopenharmony_ci pkey_assert(ret != (void *)-1); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci malloc_type++; 86862306a36Sopenharmony_ci if (malloc_type >= nr_malloc_types) 86962306a36Sopenharmony_ci malloc_type = (random()%nr_malloc_types); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* try again if the malloc_type we tried is unsupported */ 87262306a36Sopenharmony_ci if (ret == PTR_ERR_ENOTSUP) 87362306a36Sopenharmony_ci continue; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci dprintf3("%s(%ld, prot=%x, pkey=%x) returning: %p\n", __func__, 87962306a36Sopenharmony_ci size, prot, pkey, ret); 88062306a36Sopenharmony_ci return ret; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ciint last_pkey_faults; 88462306a36Sopenharmony_ci#define UNKNOWN_PKEY -2 88562306a36Sopenharmony_civoid expected_pkey_fault(int pkey) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci dprintf2("%s(): last_pkey_faults: %d pkey_faults: %d\n", 88862306a36Sopenharmony_ci __func__, last_pkey_faults, pkey_faults); 88962306a36Sopenharmony_ci dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey); 89062306a36Sopenharmony_ci pkey_assert(last_pkey_faults + 1 == pkey_faults); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci /* 89362306a36Sopenharmony_ci * For exec-only memory, we do not know the pkey in 89462306a36Sopenharmony_ci * advance, so skip this check. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci if (pkey != UNKNOWN_PKEY) 89762306a36Sopenharmony_ci pkey_assert(last_si_pkey == pkey); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) /* arch */ 90062306a36Sopenharmony_ci /* 90162306a36Sopenharmony_ci * The signal handler shold have cleared out PKEY register to let the 90262306a36Sopenharmony_ci * test program continue. We now have to restore it. 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_ci if (__read_pkey_reg() != 0) 90562306a36Sopenharmony_ci#else /* arch */ 90662306a36Sopenharmony_ci if (__read_pkey_reg() != shadow_pkey_reg) 90762306a36Sopenharmony_ci#endif /* arch */ 90862306a36Sopenharmony_ci pkey_assert(0); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci __write_pkey_reg(shadow_pkey_reg); 91162306a36Sopenharmony_ci dprintf1("%s() set pkey_reg=%016llx to restore state after signal " 91262306a36Sopenharmony_ci "nuked it\n", __func__, shadow_pkey_reg); 91362306a36Sopenharmony_ci last_pkey_faults = pkey_faults; 91462306a36Sopenharmony_ci last_si_pkey = -1; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci#define do_not_expect_pkey_fault(msg) do { \ 91862306a36Sopenharmony_ci if (last_pkey_faults != pkey_faults) \ 91962306a36Sopenharmony_ci dprintf0("unexpected PKey fault: %s\n", msg); \ 92062306a36Sopenharmony_ci pkey_assert(last_pkey_faults == pkey_faults); \ 92162306a36Sopenharmony_ci} while (0) 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ciint test_fds[10] = { -1 }; 92462306a36Sopenharmony_ciint nr_test_fds; 92562306a36Sopenharmony_civoid __save_test_fd(int fd) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci pkey_assert(fd >= 0); 92862306a36Sopenharmony_ci pkey_assert(nr_test_fds < ARRAY_SIZE(test_fds)); 92962306a36Sopenharmony_ci test_fds[nr_test_fds] = fd; 93062306a36Sopenharmony_ci nr_test_fds++; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ciint get_test_read_fd(void) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci int test_fd = open("/etc/passwd", O_RDONLY); 93662306a36Sopenharmony_ci __save_test_fd(test_fd); 93762306a36Sopenharmony_ci return test_fd; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_civoid close_test_fds(void) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci int i; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci for (i = 0; i < nr_test_fds; i++) { 94562306a36Sopenharmony_ci if (test_fds[i] < 0) 94662306a36Sopenharmony_ci continue; 94762306a36Sopenharmony_ci close(test_fds[i]); 94862306a36Sopenharmony_ci test_fds[i] = -1; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci nr_test_fds = 0; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci#define barrier() __asm__ __volatile__("": : :"memory") 95462306a36Sopenharmony_ci__attribute__((noinline)) int read_ptr(int *ptr) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci /* 95762306a36Sopenharmony_ci * Keep GCC from optimizing this away somehow 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ci barrier(); 96062306a36Sopenharmony_ci return *ptr; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_civoid test_pkey_alloc_free_attach_pkey0(int *ptr, u16 pkey) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci int i, err; 96662306a36Sopenharmony_ci int max_nr_pkey_allocs; 96762306a36Sopenharmony_ci int alloced_pkeys[NR_PKEYS]; 96862306a36Sopenharmony_ci int nr_alloced = 0; 96962306a36Sopenharmony_ci long size; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci pkey_assert(pkey_last_malloc_record); 97262306a36Sopenharmony_ci size = pkey_last_malloc_record->size; 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * This is a bit of a hack. But mprotect() requires 97562306a36Sopenharmony_ci * huge-page-aligned sizes when operating on hugetlbfs. 97662306a36Sopenharmony_ci * So, make sure that we use something that's a multiple 97762306a36Sopenharmony_ci * of a huge page when we can. 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_ci if (size >= HPAGE_SIZE) 98062306a36Sopenharmony_ci size = HPAGE_SIZE; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* allocate every possible key and make sure key-0 never got allocated */ 98362306a36Sopenharmony_ci max_nr_pkey_allocs = NR_PKEYS; 98462306a36Sopenharmony_ci for (i = 0; i < max_nr_pkey_allocs; i++) { 98562306a36Sopenharmony_ci int new_pkey = alloc_pkey(); 98662306a36Sopenharmony_ci pkey_assert(new_pkey != 0); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (new_pkey < 0) 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci alloced_pkeys[nr_alloced++] = new_pkey; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci /* free all the allocated keys */ 99362306a36Sopenharmony_ci for (i = 0; i < nr_alloced; i++) { 99462306a36Sopenharmony_ci int free_ret; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (!alloced_pkeys[i]) 99762306a36Sopenharmony_ci continue; 99862306a36Sopenharmony_ci free_ret = sys_pkey_free(alloced_pkeys[i]); 99962306a36Sopenharmony_ci pkey_assert(!free_ret); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* attach key-0 in various modes */ 100362306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, size, PROT_READ, 0); 100462306a36Sopenharmony_ci pkey_assert(!err); 100562306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, size, PROT_WRITE, 0); 100662306a36Sopenharmony_ci pkey_assert(!err); 100762306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, size, PROT_EXEC, 0); 100862306a36Sopenharmony_ci pkey_assert(!err); 100962306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, size, PROT_READ|PROT_WRITE, 0); 101062306a36Sopenharmony_ci pkey_assert(!err); 101162306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, size, PROT_READ|PROT_WRITE|PROT_EXEC, 0); 101262306a36Sopenharmony_ci pkey_assert(!err); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_civoid test_read_of_write_disabled_region(int *ptr, u16 pkey) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci int ptr_contents; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci dprintf1("disabling write access to PKEY[1], doing read\n"); 102062306a36Sopenharmony_ci pkey_write_deny(pkey); 102162306a36Sopenharmony_ci ptr_contents = read_ptr(ptr); 102262306a36Sopenharmony_ci dprintf1("*ptr: %d\n", ptr_contents); 102362306a36Sopenharmony_ci dprintf1("\n"); 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_civoid test_read_of_access_disabled_region(int *ptr, u16 pkey) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci int ptr_contents; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr); 103062306a36Sopenharmony_ci read_pkey_reg(); 103162306a36Sopenharmony_ci pkey_access_deny(pkey); 103262306a36Sopenharmony_ci ptr_contents = read_ptr(ptr); 103362306a36Sopenharmony_ci dprintf1("*ptr: %d\n", ptr_contents); 103462306a36Sopenharmony_ci expected_pkey_fault(pkey); 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_civoid test_read_of_access_disabled_region_with_page_already_mapped(int *ptr, 103862306a36Sopenharmony_ci u16 pkey) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci int ptr_contents; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", 104362306a36Sopenharmony_ci pkey, ptr); 104462306a36Sopenharmony_ci ptr_contents = read_ptr(ptr); 104562306a36Sopenharmony_ci dprintf1("reading ptr before disabling the read : %d\n", 104662306a36Sopenharmony_ci ptr_contents); 104762306a36Sopenharmony_ci read_pkey_reg(); 104862306a36Sopenharmony_ci pkey_access_deny(pkey); 104962306a36Sopenharmony_ci ptr_contents = read_ptr(ptr); 105062306a36Sopenharmony_ci dprintf1("*ptr: %d\n", ptr_contents); 105162306a36Sopenharmony_ci expected_pkey_fault(pkey); 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_civoid test_write_of_write_disabled_region_with_page_already_mapped(int *ptr, 105562306a36Sopenharmony_ci u16 pkey) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci *ptr = __LINE__; 105862306a36Sopenharmony_ci dprintf1("disabling write access; after accessing the page, " 105962306a36Sopenharmony_ci "to PKEY[%02d], doing write\n", pkey); 106062306a36Sopenharmony_ci pkey_write_deny(pkey); 106162306a36Sopenharmony_ci *ptr = __LINE__; 106262306a36Sopenharmony_ci expected_pkey_fault(pkey); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_civoid test_write_of_write_disabled_region(int *ptr, u16 pkey) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey); 106862306a36Sopenharmony_ci pkey_write_deny(pkey); 106962306a36Sopenharmony_ci *ptr = __LINE__; 107062306a36Sopenharmony_ci expected_pkey_fault(pkey); 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_civoid test_write_of_access_disabled_region(int *ptr, u16 pkey) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci dprintf1("disabling access to PKEY[%02d], doing write\n", pkey); 107562306a36Sopenharmony_ci pkey_access_deny(pkey); 107662306a36Sopenharmony_ci *ptr = __LINE__; 107762306a36Sopenharmony_ci expected_pkey_fault(pkey); 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_civoid test_write_of_access_disabled_region_with_page_already_mapped(int *ptr, 108162306a36Sopenharmony_ci u16 pkey) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci *ptr = __LINE__; 108462306a36Sopenharmony_ci dprintf1("disabling access; after accessing the page, " 108562306a36Sopenharmony_ci " to PKEY[%02d], doing write\n", pkey); 108662306a36Sopenharmony_ci pkey_access_deny(pkey); 108762306a36Sopenharmony_ci *ptr = __LINE__; 108862306a36Sopenharmony_ci expected_pkey_fault(pkey); 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_civoid test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci int ret; 109462306a36Sopenharmony_ci int test_fd = get_test_read_fd(); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci dprintf1("disabling access to PKEY[%02d], " 109762306a36Sopenharmony_ci "having kernel read() to buffer\n", pkey); 109862306a36Sopenharmony_ci pkey_access_deny(pkey); 109962306a36Sopenharmony_ci ret = read(test_fd, ptr, 1); 110062306a36Sopenharmony_ci dprintf1("read ret: %d\n", ret); 110162306a36Sopenharmony_ci pkey_assert(ret); 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_civoid test_kernel_write_of_write_disabled_region(int *ptr, u16 pkey) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci int ret; 110662306a36Sopenharmony_ci int test_fd = get_test_read_fd(); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci pkey_write_deny(pkey); 110962306a36Sopenharmony_ci ret = read(test_fd, ptr, 100); 111062306a36Sopenharmony_ci dprintf1("read ret: %d\n", ret); 111162306a36Sopenharmony_ci if (ret < 0 && (DEBUG_LEVEL > 0)) 111262306a36Sopenharmony_ci perror("verbose read result (OK for this to be bad)"); 111362306a36Sopenharmony_ci pkey_assert(ret); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_civoid test_kernel_gup_of_access_disabled_region(int *ptr, u16 pkey) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci int pipe_ret, vmsplice_ret; 111962306a36Sopenharmony_ci struct iovec iov; 112062306a36Sopenharmony_ci int pipe_fds[2]; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci pipe_ret = pipe(pipe_fds); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci pkey_assert(pipe_ret == 0); 112562306a36Sopenharmony_ci dprintf1("disabling access to PKEY[%02d], " 112662306a36Sopenharmony_ci "having kernel vmsplice from buffer\n", pkey); 112762306a36Sopenharmony_ci pkey_access_deny(pkey); 112862306a36Sopenharmony_ci iov.iov_base = ptr; 112962306a36Sopenharmony_ci iov.iov_len = PAGE_SIZE; 113062306a36Sopenharmony_ci vmsplice_ret = vmsplice(pipe_fds[1], &iov, 1, SPLICE_F_GIFT); 113162306a36Sopenharmony_ci dprintf1("vmsplice() ret: %d\n", vmsplice_ret); 113262306a36Sopenharmony_ci pkey_assert(vmsplice_ret == -1); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci close(pipe_fds[0]); 113562306a36Sopenharmony_ci close(pipe_fds[1]); 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_civoid test_kernel_gup_write_to_write_disabled_region(int *ptr, u16 pkey) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci int ignored = 0xdada; 114162306a36Sopenharmony_ci int futex_ret; 114262306a36Sopenharmony_ci int some_int = __LINE__; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci dprintf1("disabling write to PKEY[%02d], " 114562306a36Sopenharmony_ci "doing futex gunk in buffer\n", pkey); 114662306a36Sopenharmony_ci *ptr = some_int; 114762306a36Sopenharmony_ci pkey_write_deny(pkey); 114862306a36Sopenharmony_ci futex_ret = syscall(SYS_futex, ptr, FUTEX_WAIT, some_int-1, NULL, 114962306a36Sopenharmony_ci &ignored, ignored); 115062306a36Sopenharmony_ci if (DEBUG_LEVEL > 0) 115162306a36Sopenharmony_ci perror("futex"); 115262306a36Sopenharmony_ci dprintf1("futex() ret: %d\n", futex_ret); 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci/* Assumes that all pkeys other than 'pkey' are unallocated */ 115662306a36Sopenharmony_civoid test_pkey_syscalls_on_non_allocated_pkey(int *ptr, u16 pkey) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci int err; 115962306a36Sopenharmony_ci int i; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* Note: 0 is the default pkey, so don't mess with it */ 116262306a36Sopenharmony_ci for (i = 1; i < NR_PKEYS; i++) { 116362306a36Sopenharmony_ci if (pkey == i) 116462306a36Sopenharmony_ci continue; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci dprintf1("trying get/set/free to non-allocated pkey: %2d\n", i); 116762306a36Sopenharmony_ci err = sys_pkey_free(i); 116862306a36Sopenharmony_ci pkey_assert(err); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci err = sys_pkey_free(i); 117162306a36Sopenharmony_ci pkey_assert(err); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, i); 117462306a36Sopenharmony_ci pkey_assert(err); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci/* Assumes that all pkeys other than 'pkey' are unallocated */ 117962306a36Sopenharmony_civoid test_pkey_syscalls_bad_args(int *ptr, u16 pkey) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci int err; 118262306a36Sopenharmony_ci int bad_pkey = NR_PKEYS+99; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* pass a known-invalid pkey in: */ 118562306a36Sopenharmony_ci err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, bad_pkey); 118662306a36Sopenharmony_ci pkey_assert(err); 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_civoid become_child(void) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci pid_t forkret; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci forkret = fork(); 119462306a36Sopenharmony_ci pkey_assert(forkret >= 0); 119562306a36Sopenharmony_ci dprintf3("[%d] fork() ret: %d\n", getpid(), forkret); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (!forkret) { 119862306a36Sopenharmony_ci /* in the child */ 119962306a36Sopenharmony_ci return; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci exit(0); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci/* Assumes that all pkeys other than 'pkey' are unallocated */ 120562306a36Sopenharmony_civoid test_pkey_alloc_exhaust(int *ptr, u16 pkey) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci int err; 120862306a36Sopenharmony_ci int allocated_pkeys[NR_PKEYS] = {0}; 120962306a36Sopenharmony_ci int nr_allocated_pkeys = 0; 121062306a36Sopenharmony_ci int i; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci for (i = 0; i < NR_PKEYS*3; i++) { 121362306a36Sopenharmony_ci int new_pkey; 121462306a36Sopenharmony_ci dprintf1("%s() alloc loop: %d\n", __func__, i); 121562306a36Sopenharmony_ci new_pkey = alloc_pkey(); 121662306a36Sopenharmony_ci dprintf4("%s()::%d, err: %d pkey_reg: 0x%016llx" 121762306a36Sopenharmony_ci " shadow: 0x%016llx\n", 121862306a36Sopenharmony_ci __func__, __LINE__, err, __read_pkey_reg(), 121962306a36Sopenharmony_ci shadow_pkey_reg); 122062306a36Sopenharmony_ci read_pkey_reg(); /* for shadow checking */ 122162306a36Sopenharmony_ci dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC); 122262306a36Sopenharmony_ci if ((new_pkey == -1) && (errno == ENOSPC)) { 122362306a36Sopenharmony_ci dprintf2("%s() failed to allocate pkey after %d tries\n", 122462306a36Sopenharmony_ci __func__, nr_allocated_pkeys); 122562306a36Sopenharmony_ci } else { 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Ensure the number of successes never 122862306a36Sopenharmony_ci * exceeds the number of keys supported 122962306a36Sopenharmony_ci * in the hardware. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_ci pkey_assert(nr_allocated_pkeys < NR_PKEYS); 123262306a36Sopenharmony_ci allocated_pkeys[nr_allocated_pkeys++] = new_pkey; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci * Make sure that allocation state is properly 123762306a36Sopenharmony_ci * preserved across fork(). 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci if (i == NR_PKEYS*2) 124062306a36Sopenharmony_ci become_child(); 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci dprintf3("%s()::%d\n", __func__, __LINE__); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* 124662306a36Sopenharmony_ci * On x86: 124762306a36Sopenharmony_ci * There are 16 pkeys supported in hardware. Three are 124862306a36Sopenharmony_ci * allocated by the time we get here: 124962306a36Sopenharmony_ci * 1. The default key (0) 125062306a36Sopenharmony_ci * 2. One possibly consumed by an execute-only mapping. 125162306a36Sopenharmony_ci * 3. One allocated by the test code and passed in via 125262306a36Sopenharmony_ci * 'pkey' to this function. 125362306a36Sopenharmony_ci * Ensure that we can allocate at least another 13 (16-3). 125462306a36Sopenharmony_ci * 125562306a36Sopenharmony_ci * On powerpc: 125662306a36Sopenharmony_ci * There are either 5, 28, 29 or 32 pkeys supported in 125762306a36Sopenharmony_ci * hardware depending on the page size (4K or 64K) and 125862306a36Sopenharmony_ci * platform (powernv or powervm). Four are allocated by 125962306a36Sopenharmony_ci * the time we get here. These include pkey-0, pkey-1, 126062306a36Sopenharmony_ci * exec-only pkey and the one allocated by the test code. 126162306a36Sopenharmony_ci * Ensure that we can allocate the remaining. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci pkey_assert(i >= (NR_PKEYS - get_arch_reserved_keys() - 1)); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci for (i = 0; i < nr_allocated_pkeys; i++) { 126662306a36Sopenharmony_ci err = sys_pkey_free(allocated_pkeys[i]); 126762306a36Sopenharmony_ci pkey_assert(!err); 126862306a36Sopenharmony_ci read_pkey_reg(); /* for shadow checking */ 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_civoid arch_force_pkey_reg_init(void) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) /* arch */ 127562306a36Sopenharmony_ci u64 *buf; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* 127862306a36Sopenharmony_ci * All keys should be allocated and set to allow reads and 127962306a36Sopenharmony_ci * writes, so the register should be all 0. If not, just 128062306a36Sopenharmony_ci * skip the test. 128162306a36Sopenharmony_ci */ 128262306a36Sopenharmony_ci if (read_pkey_reg()) 128362306a36Sopenharmony_ci return; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* 128662306a36Sopenharmony_ci * Just allocate an absurd about of memory rather than 128762306a36Sopenharmony_ci * doing the XSAVE size enumeration dance. 128862306a36Sopenharmony_ci */ 128962306a36Sopenharmony_ci buf = mmap(NULL, 1*MB, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci /* These __builtins require compiling with -mxsave */ 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci /* XSAVE to build a valid buffer: */ 129462306a36Sopenharmony_ci __builtin_ia32_xsave(buf, XSTATE_PKEY); 129562306a36Sopenharmony_ci /* Clear XSTATE_BV[PKRU]: */ 129662306a36Sopenharmony_ci buf[XSTATE_BV_OFFSET/sizeof(u64)] &= ~XSTATE_PKEY; 129762306a36Sopenharmony_ci /* XRSTOR will likely get PKRU back to the init state: */ 129862306a36Sopenharmony_ci __builtin_ia32_xrstor(buf, XSTATE_PKEY); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci munmap(buf, 1*MB); 130162306a36Sopenharmony_ci#endif 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci/* 130662306a36Sopenharmony_ci * This is mostly useless on ppc for now. But it will not 130762306a36Sopenharmony_ci * hurt anything and should give some better coverage as 130862306a36Sopenharmony_ci * a long-running test that continually checks the pkey 130962306a36Sopenharmony_ci * register. 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_civoid test_pkey_init_state(int *ptr, u16 pkey) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci int err; 131462306a36Sopenharmony_ci int allocated_pkeys[NR_PKEYS] = {0}; 131562306a36Sopenharmony_ci int nr_allocated_pkeys = 0; 131662306a36Sopenharmony_ci int i; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci for (i = 0; i < NR_PKEYS; i++) { 131962306a36Sopenharmony_ci int new_pkey = alloc_pkey(); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (new_pkey < 0) 132262306a36Sopenharmony_ci continue; 132362306a36Sopenharmony_ci allocated_pkeys[nr_allocated_pkeys++] = new_pkey; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci dprintf3("%s()::%d\n", __func__, __LINE__); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci arch_force_pkey_reg_init(); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* 133162306a36Sopenharmony_ci * Loop for a bit, hoping to get exercise the kernel 133262306a36Sopenharmony_ci * context switch code. 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci for (i = 0; i < 1000000; i++) 133562306a36Sopenharmony_ci read_pkey_reg(); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci for (i = 0; i < nr_allocated_pkeys; i++) { 133862306a36Sopenharmony_ci err = sys_pkey_free(allocated_pkeys[i]); 133962306a36Sopenharmony_ci pkey_assert(!err); 134062306a36Sopenharmony_ci read_pkey_reg(); /* for shadow checking */ 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci/* 134562306a36Sopenharmony_ci * pkey 0 is special. It is allocated by default, so you do not 134662306a36Sopenharmony_ci * have to call pkey_alloc() to use it first. Make sure that it 134762306a36Sopenharmony_ci * is usable. 134862306a36Sopenharmony_ci */ 134962306a36Sopenharmony_civoid test_mprotect_with_pkey_0(int *ptr, u16 pkey) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci long size; 135262306a36Sopenharmony_ci int prot; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci assert(pkey_last_malloc_record); 135562306a36Sopenharmony_ci size = pkey_last_malloc_record->size; 135662306a36Sopenharmony_ci /* 135762306a36Sopenharmony_ci * This is a bit of a hack. But mprotect() requires 135862306a36Sopenharmony_ci * huge-page-aligned sizes when operating on hugetlbfs. 135962306a36Sopenharmony_ci * So, make sure that we use something that's a multiple 136062306a36Sopenharmony_ci * of a huge page when we can. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci if (size >= HPAGE_SIZE) 136362306a36Sopenharmony_ci size = HPAGE_SIZE; 136462306a36Sopenharmony_ci prot = pkey_last_malloc_record->prot; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* Use pkey 0 */ 136762306a36Sopenharmony_ci mprotect_pkey(ptr, size, prot, 0); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci /* Make sure that we can set it back to the original pkey. */ 137062306a36Sopenharmony_ci mprotect_pkey(ptr, size, prot, pkey); 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_civoid test_ptrace_of_child(int *ptr, u16 pkey) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci __attribute__((__unused__)) int peek_result; 137662306a36Sopenharmony_ci pid_t child_pid; 137762306a36Sopenharmony_ci void *ignored = 0; 137862306a36Sopenharmony_ci long ret; 137962306a36Sopenharmony_ci int status; 138062306a36Sopenharmony_ci /* 138162306a36Sopenharmony_ci * This is the "control" for our little expermient. Make sure 138262306a36Sopenharmony_ci * we can always access it when ptracing. 138362306a36Sopenharmony_ci */ 138462306a36Sopenharmony_ci int *plain_ptr_unaligned = malloc(HPAGE_SIZE); 138562306a36Sopenharmony_ci int *plain_ptr = ALIGN_PTR_UP(plain_ptr_unaligned, PAGE_SIZE); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* 138862306a36Sopenharmony_ci * Fork a child which is an exact copy of this process, of course. 138962306a36Sopenharmony_ci * That means we can do all of our tests via ptrace() and then plain 139062306a36Sopenharmony_ci * memory access and ensure they work differently. 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_ci child_pid = fork_lazy_child(); 139362306a36Sopenharmony_ci dprintf1("[%d] child pid: %d\n", getpid(), child_pid); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci ret = ptrace(PTRACE_ATTACH, child_pid, ignored, ignored); 139662306a36Sopenharmony_ci if (ret) 139762306a36Sopenharmony_ci perror("attach"); 139862306a36Sopenharmony_ci dprintf1("[%d] attach ret: %ld %d\n", getpid(), ret, __LINE__); 139962306a36Sopenharmony_ci pkey_assert(ret != -1); 140062306a36Sopenharmony_ci ret = waitpid(child_pid, &status, WUNTRACED); 140162306a36Sopenharmony_ci if ((ret != child_pid) || !(WIFSTOPPED(status))) { 140262306a36Sopenharmony_ci fprintf(stderr, "weird waitpid result %ld stat %x\n", 140362306a36Sopenharmony_ci ret, status); 140462306a36Sopenharmony_ci pkey_assert(0); 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci dprintf2("waitpid ret: %ld\n", ret); 140762306a36Sopenharmony_ci dprintf2("waitpid status: %d\n", status); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci pkey_access_deny(pkey); 141062306a36Sopenharmony_ci pkey_write_deny(pkey); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Write access, untested for now: 141362306a36Sopenharmony_ci ret = ptrace(PTRACE_POKEDATA, child_pid, peek_at, data); 141462306a36Sopenharmony_ci pkey_assert(ret != -1); 141562306a36Sopenharmony_ci dprintf1("poke at %p: %ld\n", peek_at, ret); 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* 141962306a36Sopenharmony_ci * Try to access the pkey-protected "ptr" via ptrace: 142062306a36Sopenharmony_ci */ 142162306a36Sopenharmony_ci ret = ptrace(PTRACE_PEEKDATA, child_pid, ptr, ignored); 142262306a36Sopenharmony_ci /* expect it to work, without an error: */ 142362306a36Sopenharmony_ci pkey_assert(ret != -1); 142462306a36Sopenharmony_ci /* Now access from the current task, and expect an exception: */ 142562306a36Sopenharmony_ci peek_result = read_ptr(ptr); 142662306a36Sopenharmony_ci expected_pkey_fault(pkey); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* 142962306a36Sopenharmony_ci * Try to access the NON-pkey-protected "plain_ptr" via ptrace: 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_ci ret = ptrace(PTRACE_PEEKDATA, child_pid, plain_ptr, ignored); 143262306a36Sopenharmony_ci /* expect it to work, without an error: */ 143362306a36Sopenharmony_ci pkey_assert(ret != -1); 143462306a36Sopenharmony_ci /* Now access from the current task, and expect NO exception: */ 143562306a36Sopenharmony_ci peek_result = read_ptr(plain_ptr); 143662306a36Sopenharmony_ci do_not_expect_pkey_fault("read plain pointer after ptrace"); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0); 143962306a36Sopenharmony_ci pkey_assert(ret != -1); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci ret = kill(child_pid, SIGKILL); 144262306a36Sopenharmony_ci pkey_assert(ret != -1); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci wait(&status); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci free(plain_ptr_unaligned); 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_civoid *get_pointer_to_instructions(void) 145062306a36Sopenharmony_ci{ 145162306a36Sopenharmony_ci void *p1; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE); 145462306a36Sopenharmony_ci dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write); 145562306a36Sopenharmony_ci /* lots_o_noops_around_write should be page-aligned already */ 145662306a36Sopenharmony_ci assert(p1 == &lots_o_noops_around_write); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* Point 'p1' at the *second* page of the function: */ 145962306a36Sopenharmony_ci p1 += PAGE_SIZE; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * Try to ensure we fault this in on next touch to ensure 146362306a36Sopenharmony_ci * we get an instruction fault as opposed to a data one 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci madvise(p1, PAGE_SIZE, MADV_DONTNEED); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci return p1; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_civoid test_executing_on_unreadable_memory(int *ptr, u16 pkey) 147162306a36Sopenharmony_ci{ 147262306a36Sopenharmony_ci void *p1; 147362306a36Sopenharmony_ci int scratch; 147462306a36Sopenharmony_ci int ptr_contents; 147562306a36Sopenharmony_ci int ret; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci p1 = get_pointer_to_instructions(); 147862306a36Sopenharmony_ci lots_o_noops_around_write(&scratch); 147962306a36Sopenharmony_ci ptr_contents = read_ptr(p1); 148062306a36Sopenharmony_ci dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci ret = mprotect_pkey(p1, PAGE_SIZE, PROT_EXEC, (u64)pkey); 148362306a36Sopenharmony_ci pkey_assert(!ret); 148462306a36Sopenharmony_ci pkey_access_deny(pkey); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci dprintf2("pkey_reg: %016llx\n", read_pkey_reg()); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci /* 148962306a36Sopenharmony_ci * Make sure this is an *instruction* fault 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_ci madvise(p1, PAGE_SIZE, MADV_DONTNEED); 149262306a36Sopenharmony_ci lots_o_noops_around_write(&scratch); 149362306a36Sopenharmony_ci do_not_expect_pkey_fault("executing on PROT_EXEC memory"); 149462306a36Sopenharmony_ci expect_fault_on_read_execonly_key(p1, pkey); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_civoid test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci void *p1; 150062306a36Sopenharmony_ci int scratch; 150162306a36Sopenharmony_ci int ptr_contents; 150262306a36Sopenharmony_ci int ret; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci dprintf1("%s() start\n", __func__); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci p1 = get_pointer_to_instructions(); 150762306a36Sopenharmony_ci lots_o_noops_around_write(&scratch); 150862306a36Sopenharmony_ci ptr_contents = read_ptr(p1); 150962306a36Sopenharmony_ci dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* Use a *normal* mprotect(), not mprotect_pkey(): */ 151262306a36Sopenharmony_ci ret = mprotect(p1, PAGE_SIZE, PROT_EXEC); 151362306a36Sopenharmony_ci pkey_assert(!ret); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* 151662306a36Sopenharmony_ci * Reset the shadow, assuming that the above mprotect() 151762306a36Sopenharmony_ci * correctly changed PKRU, but to an unknown value since 151862306a36Sopenharmony_ci * the actual allocated pkey is unknown. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci shadow_pkey_reg = __read_pkey_reg(); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci dprintf2("pkey_reg: %016llx\n", read_pkey_reg()); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* Make sure this is an *instruction* fault */ 152562306a36Sopenharmony_ci madvise(p1, PAGE_SIZE, MADV_DONTNEED); 152662306a36Sopenharmony_ci lots_o_noops_around_write(&scratch); 152762306a36Sopenharmony_ci do_not_expect_pkey_fault("executing on PROT_EXEC memory"); 152862306a36Sopenharmony_ci expect_fault_on_read_execonly_key(p1, UNKNOWN_PKEY); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* 153162306a36Sopenharmony_ci * Put the memory back to non-PROT_EXEC. Should clear the 153262306a36Sopenharmony_ci * exec-only pkey off the VMA and allow it to be readable 153362306a36Sopenharmony_ci * again. Go to PROT_NONE first to check for a kernel bug 153462306a36Sopenharmony_ci * that did not clear the pkey when doing PROT_NONE. 153562306a36Sopenharmony_ci */ 153662306a36Sopenharmony_ci ret = mprotect(p1, PAGE_SIZE, PROT_NONE); 153762306a36Sopenharmony_ci pkey_assert(!ret); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC); 154062306a36Sopenharmony_ci pkey_assert(!ret); 154162306a36Sopenharmony_ci ptr_contents = read_ptr(p1); 154262306a36Sopenharmony_ci do_not_expect_pkey_fault("plain read on recently PROT_EXEC area"); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 154662306a36Sopenharmony_civoid test_ptrace_modifies_pkru(int *ptr, u16 pkey) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci u32 new_pkru; 154962306a36Sopenharmony_ci pid_t child; 155062306a36Sopenharmony_ci int status, ret; 155162306a36Sopenharmony_ci int pkey_offset = pkey_reg_xstate_offset(); 155262306a36Sopenharmony_ci size_t xsave_size = cpu_max_xsave_size(); 155362306a36Sopenharmony_ci void *xsave; 155462306a36Sopenharmony_ci u32 *pkey_register; 155562306a36Sopenharmony_ci u64 *xstate_bv; 155662306a36Sopenharmony_ci struct iovec iov; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci new_pkru = ~read_pkey_reg(); 155962306a36Sopenharmony_ci /* Don't make PROT_EXEC mappings inaccessible */ 156062306a36Sopenharmony_ci new_pkru &= ~3; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci child = fork(); 156362306a36Sopenharmony_ci pkey_assert(child >= 0); 156462306a36Sopenharmony_ci dprintf3("[%d] fork() ret: %d\n", getpid(), child); 156562306a36Sopenharmony_ci if (!child) { 156662306a36Sopenharmony_ci ptrace(PTRACE_TRACEME, 0, 0, 0); 156762306a36Sopenharmony_ci /* Stop and allow the tracer to modify PKRU directly */ 156862306a36Sopenharmony_ci raise(SIGSTOP); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* 157162306a36Sopenharmony_ci * need __read_pkey_reg() version so we do not do shadow_pkey_reg 157262306a36Sopenharmony_ci * checking 157362306a36Sopenharmony_ci */ 157462306a36Sopenharmony_ci if (__read_pkey_reg() != new_pkru) 157562306a36Sopenharmony_ci exit(1); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* Stop and allow the tracer to clear XSTATE_BV for PKRU */ 157862306a36Sopenharmony_ci raise(SIGSTOP); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (__read_pkey_reg() != 0) 158162306a36Sopenharmony_ci exit(1); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* Stop and allow the tracer to examine PKRU */ 158462306a36Sopenharmony_ci raise(SIGSTOP); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci exit(0); 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci pkey_assert(child == waitpid(child, &status, 0)); 159062306a36Sopenharmony_ci dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); 159162306a36Sopenharmony_ci pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci xsave = (void *)malloc(xsave_size); 159462306a36Sopenharmony_ci pkey_assert(xsave > 0); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* Modify the PKRU register directly */ 159762306a36Sopenharmony_ci iov.iov_base = xsave; 159862306a36Sopenharmony_ci iov.iov_len = xsave_size; 159962306a36Sopenharmony_ci ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); 160062306a36Sopenharmony_ci pkey_assert(ret == 0); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci pkey_register = (u32 *)(xsave + pkey_offset); 160362306a36Sopenharmony_ci pkey_assert(*pkey_register == read_pkey_reg()); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci *pkey_register = new_pkru; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov); 160862306a36Sopenharmony_ci pkey_assert(ret == 0); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci /* Test that the modification is visible in ptrace before any execution */ 161162306a36Sopenharmony_ci memset(xsave, 0xCC, xsave_size); 161262306a36Sopenharmony_ci ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); 161362306a36Sopenharmony_ci pkey_assert(ret == 0); 161462306a36Sopenharmony_ci pkey_assert(*pkey_register == new_pkru); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci /* Execute the tracee */ 161762306a36Sopenharmony_ci ret = ptrace(PTRACE_CONT, child, 0, 0); 161862306a36Sopenharmony_ci pkey_assert(ret == 0); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci /* Test that the tracee saw the PKRU value change */ 162162306a36Sopenharmony_ci pkey_assert(child == waitpid(child, &status, 0)); 162262306a36Sopenharmony_ci dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); 162362306a36Sopenharmony_ci pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci /* Test that the modification is visible in ptrace after execution */ 162662306a36Sopenharmony_ci memset(xsave, 0xCC, xsave_size); 162762306a36Sopenharmony_ci ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); 162862306a36Sopenharmony_ci pkey_assert(ret == 0); 162962306a36Sopenharmony_ci pkey_assert(*pkey_register == new_pkru); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* Clear the PKRU bit from XSTATE_BV */ 163262306a36Sopenharmony_ci xstate_bv = (u64 *)(xsave + 512); 163362306a36Sopenharmony_ci *xstate_bv &= ~(1 << 9); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov); 163662306a36Sopenharmony_ci pkey_assert(ret == 0); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* Test that the modification is visible in ptrace before any execution */ 163962306a36Sopenharmony_ci memset(xsave, 0xCC, xsave_size); 164062306a36Sopenharmony_ci ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); 164162306a36Sopenharmony_ci pkey_assert(ret == 0); 164262306a36Sopenharmony_ci pkey_assert(*pkey_register == 0); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci ret = ptrace(PTRACE_CONT, child, 0, 0); 164562306a36Sopenharmony_ci pkey_assert(ret == 0); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* Test that the tracee saw the PKRU value go to 0 */ 164862306a36Sopenharmony_ci pkey_assert(child == waitpid(child, &status, 0)); 164962306a36Sopenharmony_ci dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); 165062306a36Sopenharmony_ci pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* Test that the modification is visible in ptrace after execution */ 165362306a36Sopenharmony_ci memset(xsave, 0xCC, xsave_size); 165462306a36Sopenharmony_ci ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); 165562306a36Sopenharmony_ci pkey_assert(ret == 0); 165662306a36Sopenharmony_ci pkey_assert(*pkey_register == 0); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci ret = ptrace(PTRACE_CONT, child, 0, 0); 165962306a36Sopenharmony_ci pkey_assert(ret == 0); 166062306a36Sopenharmony_ci pkey_assert(child == waitpid(child, &status, 0)); 166162306a36Sopenharmony_ci dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); 166262306a36Sopenharmony_ci pkey_assert(WIFEXITED(status)); 166362306a36Sopenharmony_ci pkey_assert(WEXITSTATUS(status) == 0); 166462306a36Sopenharmony_ci free(xsave); 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci#endif 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_civoid test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci int size = PAGE_SIZE; 167162306a36Sopenharmony_ci int sret; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (cpu_has_pkeys()) { 167462306a36Sopenharmony_ci dprintf1("SKIP: %s: no CPU support\n", __func__); 167562306a36Sopenharmony_ci return; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci sret = syscall(__NR_pkey_mprotect, ptr, size, PROT_READ, pkey); 167962306a36Sopenharmony_ci pkey_assert(sret < 0); 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_civoid (*pkey_tests[])(int *ptr, u16 pkey) = { 168362306a36Sopenharmony_ci test_read_of_write_disabled_region, 168462306a36Sopenharmony_ci test_read_of_access_disabled_region, 168562306a36Sopenharmony_ci test_read_of_access_disabled_region_with_page_already_mapped, 168662306a36Sopenharmony_ci test_write_of_write_disabled_region, 168762306a36Sopenharmony_ci test_write_of_write_disabled_region_with_page_already_mapped, 168862306a36Sopenharmony_ci test_write_of_access_disabled_region, 168962306a36Sopenharmony_ci test_write_of_access_disabled_region_with_page_already_mapped, 169062306a36Sopenharmony_ci test_kernel_write_of_access_disabled_region, 169162306a36Sopenharmony_ci test_kernel_write_of_write_disabled_region, 169262306a36Sopenharmony_ci test_kernel_gup_of_access_disabled_region, 169362306a36Sopenharmony_ci test_kernel_gup_write_to_write_disabled_region, 169462306a36Sopenharmony_ci test_executing_on_unreadable_memory, 169562306a36Sopenharmony_ci test_implicit_mprotect_exec_only_memory, 169662306a36Sopenharmony_ci test_mprotect_with_pkey_0, 169762306a36Sopenharmony_ci test_ptrace_of_child, 169862306a36Sopenharmony_ci test_pkey_init_state, 169962306a36Sopenharmony_ci test_pkey_syscalls_on_non_allocated_pkey, 170062306a36Sopenharmony_ci test_pkey_syscalls_bad_args, 170162306a36Sopenharmony_ci test_pkey_alloc_exhaust, 170262306a36Sopenharmony_ci test_pkey_alloc_free_attach_pkey0, 170362306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 170462306a36Sopenharmony_ci test_ptrace_modifies_pkru, 170562306a36Sopenharmony_ci#endif 170662306a36Sopenharmony_ci}; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_civoid run_tests_once(void) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci int *ptr; 171162306a36Sopenharmony_ci int prot = PROT_READ|PROT_WRITE; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) { 171462306a36Sopenharmony_ci int pkey; 171562306a36Sopenharmony_ci int orig_pkey_faults = pkey_faults; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci dprintf1("======================\n"); 171862306a36Sopenharmony_ci dprintf1("test %d preparing...\n", test_nr); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci tracing_on(); 172162306a36Sopenharmony_ci pkey = alloc_random_pkey(); 172262306a36Sopenharmony_ci dprintf1("test %d starting with pkey: %d\n", test_nr, pkey); 172362306a36Sopenharmony_ci ptr = malloc_pkey(PAGE_SIZE, prot, pkey); 172462306a36Sopenharmony_ci dprintf1("test %d starting...\n", test_nr); 172562306a36Sopenharmony_ci pkey_tests[test_nr](ptr, pkey); 172662306a36Sopenharmony_ci dprintf1("freeing test memory: %p\n", ptr); 172762306a36Sopenharmony_ci free_pkey_malloc(ptr); 172862306a36Sopenharmony_ci sys_pkey_free(pkey); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci dprintf1("pkey_faults: %d\n", pkey_faults); 173162306a36Sopenharmony_ci dprintf1("orig_pkey_faults: %d\n", orig_pkey_faults); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci tracing_off(); 173462306a36Sopenharmony_ci close_test_fds(); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci printf("test %2d PASSED (iteration %d)\n", test_nr, iteration_nr); 173762306a36Sopenharmony_ci dprintf1("======================\n\n"); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci iteration_nr++; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_civoid pkey_setup_shadow(void) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci shadow_pkey_reg = __read_pkey_reg(); 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ciint main(void) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci int nr_iterations = 22; 175062306a36Sopenharmony_ci int pkeys_supported = is_pkeys_supported(); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci srand((unsigned int)time(NULL)); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci setup_handlers(); 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci printf("has pkeys: %d\n", pkeys_supported); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (!pkeys_supported) { 175962306a36Sopenharmony_ci int size = PAGE_SIZE; 176062306a36Sopenharmony_ci int *ptr; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci printf("running PKEY tests for unsupported CPU/OS\n"); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 176562306a36Sopenharmony_ci assert(ptr != (void *)-1); 176662306a36Sopenharmony_ci test_mprotect_pkey_on_unsupported_cpu(ptr, 1); 176762306a36Sopenharmony_ci exit(0); 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci pkey_setup_shadow(); 177162306a36Sopenharmony_ci printf("startup pkey_reg: %016llx\n", read_pkey_reg()); 177262306a36Sopenharmony_ci setup_hugetlbfs(); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci while (nr_iterations-- > 0) 177562306a36Sopenharmony_ci run_tests_once(); 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci printf("done (all tests OK)\n"); 177862306a36Sopenharmony_ci return 0; 177962306a36Sopenharmony_ci} 1780