selftests/vm/pkeys: rename all references to pkru to a generic name

This renames PKRU references to "pkey_reg" or "pkey" based on
the usage.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: Sandipan Das <sandipan@linux.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Dave Hansen <dave.hansen@intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: "Desnes A. Nunes do Rosario" <desnesn@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Suchanek <msuchanek@suse.de>
Cc: Shuah Khan <shuah@kernel.org>
Link: http://lkml.kernel.org/r/2c6970bc6d2e99796cd5cc1101bd2ecf7eccb937.1585646528.git.sandipan@linux.ibm.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Ram Pai 2020-06-04 16:51:37 -07:00 committed by Linus Torvalds
parent 804eb64615
commit c4273c7f0e
2 changed files with 170 additions and 155 deletions

View file

@ -14,7 +14,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#define NR_PKEYS 16 #define NR_PKEYS 16
#define PKRU_BITS_PER_PKEY 2 #define PKEY_BITS_PER_PKEY 2
#ifndef DEBUG_LEVEL #ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 0 #define DEBUG_LEVEL 0
@ -53,85 +53,88 @@ static inline void sigsafe_printf(const char *format, ...)
#define dprintf3(args...) dprintf_level(3, args) #define dprintf3(args...) dprintf_level(3, args)
#define dprintf4(args...) dprintf_level(4, args) #define dprintf4(args...) dprintf_level(4, args)
extern unsigned int shadow_pkru; extern unsigned int shadow_pkey_reg;
static inline unsigned int __rdpkru(void) static inline unsigned int __read_pkey_reg(void)
{ {
unsigned int eax, edx; unsigned int eax, edx;
unsigned int ecx = 0; unsigned int ecx = 0;
unsigned int pkru; unsigned int pkey_reg;
asm volatile(".byte 0x0f,0x01,0xee\n\t" asm volatile(".byte 0x0f,0x01,0xee\n\t"
: "=a" (eax), "=d" (edx) : "=a" (eax), "=d" (edx)
: "c" (ecx)); : "c" (ecx));
pkru = eax; pkey_reg = eax;
return pkru; return pkey_reg;
} }
static inline unsigned int _rdpkru(int line) static inline unsigned int _read_pkey_reg(int line)
{ {
unsigned int pkru = __rdpkru(); unsigned int pkey_reg = __read_pkey_reg();
dprintf4("rdpkru(line=%d) pkru: %x shadow: %x\n", dprintf4("read_pkey_reg(line=%d) pkey_reg: %x shadow: %x\n",
line, pkru, shadow_pkru); line, pkey_reg, shadow_pkey_reg);
assert(pkru == shadow_pkru); assert(pkey_reg == shadow_pkey_reg);
return pkru; return pkey_reg;
} }
#define rdpkru() _rdpkru(__LINE__) #define read_pkey_reg() _read_pkey_reg(__LINE__)
static inline void __wrpkru(unsigned int pkru) static inline void __write_pkey_reg(unsigned int pkey_reg)
{ {
unsigned int eax = pkru; unsigned int eax = pkey_reg;
unsigned int ecx = 0; unsigned int ecx = 0;
unsigned int edx = 0; unsigned int edx = 0;
dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru); dprintf4("%s() changing %08x to %08x\n", __func__,
__read_pkey_reg(), pkey_reg);
asm volatile(".byte 0x0f,0x01,0xef\n\t" asm volatile(".byte 0x0f,0x01,0xef\n\t"
: : "a" (eax), "c" (ecx), "d" (edx)); : : "a" (eax), "c" (ecx), "d" (edx));
assert(pkru == __rdpkru()); assert(pkey_reg == __read_pkey_reg());
} }
static inline void wrpkru(unsigned int pkru) static inline void write_pkey_reg(unsigned int pkey_reg)
{ {
dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru); dprintf4("%s() changing %08x to %08x\n", __func__,
__read_pkey_reg(), pkey_reg);
/* will do the shadow check for us: */ /* will do the shadow check for us: */
rdpkru(); read_pkey_reg();
__wrpkru(pkru); __write_pkey_reg(pkey_reg);
shadow_pkru = pkru; shadow_pkey_reg = pkey_reg;
dprintf4("%s(%08x) pkru: %08x\n", __func__, pkru, __rdpkru()); dprintf4("%s(%08x) pkey_reg: %08x\n", __func__,
pkey_reg, __read_pkey_reg());
} }
/* /*
* These are technically racy. since something could * These are technically racy. since something could
* change PKRU between the read and the write. * change PKEY register between the read and the write.
*/ */
static inline void __pkey_access_allow(int pkey, int do_allow) static inline void __pkey_access_allow(int pkey, int do_allow)
{ {
unsigned int pkru = rdpkru(); unsigned int pkey_reg = read_pkey_reg();
int bit = pkey * 2; int bit = pkey * 2;
if (do_allow) if (do_allow)
pkru &= (1<<bit); pkey_reg &= (1<<bit);
else else
pkru |= (1<<bit); pkey_reg |= (1<<bit);
dprintf4("pkru now: %08x\n", rdpkru()); dprintf4("pkey_reg now: %08x\n", read_pkey_reg());
wrpkru(pkru); write_pkey_reg(pkey_reg);
} }
static inline void __pkey_write_allow(int pkey, int do_allow_write) static inline void __pkey_write_allow(int pkey, int do_allow_write)
{ {
long pkru = rdpkru(); long pkey_reg = read_pkey_reg();
int bit = pkey * 2 + 1; int bit = pkey * 2 + 1;
if (do_allow_write) if (do_allow_write)
pkru &= (1<<bit); pkey_reg &= (1<<bit);
else else
pkru |= (1<<bit); pkey_reg |= (1<<bit);
wrpkru(pkru); write_pkey_reg(pkey_reg);
dprintf4("pkru now: %08x\n", rdpkru()); dprintf4("pkey_reg now: %08x\n", read_pkey_reg());
} }
#define PROT_PKEY0 0x10 /* protection key value (bit 0) */ #define PROT_PKEY0 0x10 /* protection key value (bit 0) */
@ -181,10 +184,10 @@ static inline int cpu_has_pku(void)
return 1; return 1;
} }
#define XSTATE_PKRU_BIT (9) #define XSTATE_PKEY_BIT (9)
#define XSTATE_PKRU 0x200 #define XSTATE_PKEY 0x200
int pkru_xstate_offset(void) int pkey_reg_xstate_offset(void)
{ {
unsigned int eax; unsigned int eax;
unsigned int ebx; unsigned int ebx;
@ -195,21 +198,21 @@ int pkru_xstate_offset(void)
unsigned long XSTATE_CPUID = 0xd; unsigned long XSTATE_CPUID = 0xd;
int leaf; int leaf;
/* assume that XSTATE_PKRU is set in XCR0 */ /* assume that XSTATE_PKEY is set in XCR0 */
leaf = XSTATE_PKRU_BIT; leaf = XSTATE_PKEY_BIT;
{ {
eax = XSTATE_CPUID; eax = XSTATE_CPUID;
ecx = leaf; ecx = leaf;
__cpuid(&eax, &ebx, &ecx, &edx); __cpuid(&eax, &ebx, &ecx, &edx);
if (leaf == XSTATE_PKRU_BIT) { if (leaf == XSTATE_PKEY_BIT) {
xstate_offset = ebx; xstate_offset = ebx;
xstate_size = eax; xstate_size = eax;
} }
} }
if (xstate_size == 0) { if (xstate_size == 0) {
printf("could not find size/offset of PKRU in xsave state\n"); printf("could not find size/offset of PKEY in xsave state\n");
return 0; return 0;
} }

View file

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Tests x86 Memory Protection Keys (see Documentation/core-api/protection-keys.rst) * Tests Memory Protection Keys (see Documentation/vm/protection-keys.txt)
* *
* There are examples in here of: * There are examples in here of:
* * how to set protection keys on memory * * how to set protection keys on memory
* * how to set/clear bits in PKRU (the rights register) * * how to set/clear bits in pkey registers (the rights register)
* * how to handle SEGV_PKRU signals and extract pkey-relevant * * how to handle SEGV_PKUERR signals and extract pkey-relevant
* information from the siginfo * information from the siginfo
* *
* Things to add: * Things to add:
@ -48,7 +48,7 @@
int iteration_nr = 1; int iteration_nr = 1;
int test_nr; int test_nr;
unsigned int shadow_pkru; unsigned int shadow_pkey_reg;
#define HPAGE_SIZE (1UL<<21) #define HPAGE_SIZE (1UL<<21)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
@ -255,7 +255,7 @@ static char *si_code_str(int si_code)
return "UNKNOWN"; return "UNKNOWN";
} }
int pkru_faults; int pkey_faults;
int last_si_pkey = -1; int last_si_pkey = -1;
void signal_handler(int signum, siginfo_t *si, void *vucontext) void signal_handler(int signum, siginfo_t *si, void *vucontext)
{ {
@ -263,16 +263,16 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
int trapno; int trapno;
unsigned long ip; unsigned long ip;
char *fpregs; char *fpregs;
u32 *pkru_ptr; u32 *pkey_reg_ptr;
u64 siginfo_pkey; u64 siginfo_pkey;
u32 *si_pkey_ptr; u32 *si_pkey_ptr;
int pkru_offset; int pkey_reg_offset;
fpregset_t fpregset; fpregset_t fpregset;
dprint_in_signal = 1; dprint_in_signal = 1;
dprintf1(">>>>===============SIGSEGV============================\n"); dprintf1(">>>>===============SIGSEGV============================\n");
dprintf1("%s()::%d, pkru: 0x%x shadow: %x\n", __func__, __LINE__, dprintf1("%s()::%d, pkey_reg: 0x%x shadow: %x\n", __func__, __LINE__,
__rdpkru(), shadow_pkru); __read_pkey_reg(), shadow_pkey_reg);
trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO]; trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
ip = uctxt->uc_mcontext.gregs[REG_IP_IDX]; ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
@ -289,19 +289,19 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
*/ */
fpregs += 0x70; fpregs += 0x70;
#endif #endif
pkru_offset = pkru_xstate_offset(); pkey_reg_offset = pkey_reg_xstate_offset();
pkru_ptr = (void *)(&fpregs[pkru_offset]); pkey_reg_ptr = (void *)(&fpregs[pkey_reg_offset]);
dprintf1("siginfo: %p\n", si); dprintf1("siginfo: %p\n", si);
dprintf1(" fpregs: %p\n", fpregs); dprintf1(" fpregs: %p\n", fpregs);
/* /*
* If we got a PKRU fault, we *HAVE* to have at least one bit set in * If we got a PKEY fault, we *HAVE* to have at least one bit set in
* here. * here.
*/ */
dprintf1("pkru_xstate_offset: %d\n", pkru_xstate_offset()); dprintf1("pkey_reg_xstate_offset: %d\n", pkey_reg_xstate_offset());
if (DEBUG_LEVEL > 4) if (DEBUG_LEVEL > 4)
dump_mem(pkru_ptr - 128, 256); dump_mem(pkey_reg_ptr - 128, 256);
pkey_assert(*pkru_ptr); pkey_assert(*pkey_reg_ptr);
if ((si->si_code == SEGV_MAPERR) || if ((si->si_code == SEGV_MAPERR) ||
(si->si_code == SEGV_ACCERR) || (si->si_code == SEGV_ACCERR) ||
@ -317,13 +317,16 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
pkey_assert(siginfo_pkey < NR_PKEYS); pkey_assert(siginfo_pkey < NR_PKEYS);
last_si_pkey = siginfo_pkey; last_si_pkey = siginfo_pkey;
dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); dprintf1("signal pkey_reg from xsave: %08x\n", *pkey_reg_ptr);
/* need __rdpkru() version so we do not do shadow_pkru checking */ /*
dprintf1("signal pkru from pkru: %08x\n", __rdpkru()); * need __read_pkey_reg() version so we do not do shadow_pkey_reg
* checking
*/
dprintf1("signal pkey_reg from pkey_reg: %08x\n", __read_pkey_reg());
dprintf1("pkey from siginfo: %jx\n", siginfo_pkey); dprintf1("pkey from siginfo: %jx\n", siginfo_pkey);
*(u64 *)pkru_ptr = 0x00000000; *(u64 *)pkey_reg_ptr = 0x00000000;
dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); dprintf1("WARNING: set PKEY_REG=0 to allow faulting instruction to continue\n");
pkru_faults++; pkey_faults++;
dprintf1("<<<<==================================================\n"); dprintf1("<<<<==================================================\n");
dprint_in_signal = 0; dprint_in_signal = 0;
} }
@ -402,45 +405,47 @@ pid_t fork_lazy_child(void)
static u32 hw_pkey_get(int pkey, unsigned long flags) static u32 hw_pkey_get(int pkey, unsigned long flags)
{ {
u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
u32 pkru = __rdpkru(); u32 pkey_reg = __read_pkey_reg();
u32 shifted_pkru; u32 shifted_pkey_reg;
u32 masked_pkru; u32 masked_pkey_reg;
dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n", dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
__func__, pkey, flags, 0, 0); __func__, pkey, flags, 0, 0);
dprintf2("%s() raw pkru: %x\n", __func__, pkru); dprintf2("%s() raw pkey_reg: %x\n", __func__, pkey_reg);
shifted_pkru = (pkru >> (pkey * PKRU_BITS_PER_PKEY)); shifted_pkey_reg = (pkey_reg >> (pkey * PKEY_BITS_PER_PKEY));
dprintf2("%s() shifted_pkru: %x\n", __func__, shifted_pkru); dprintf2("%s() shifted_pkey_reg: %x\n", __func__, shifted_pkey_reg);
masked_pkru = shifted_pkru & mask; masked_pkey_reg = shifted_pkey_reg & mask;
dprintf2("%s() masked pkru: %x\n", __func__, masked_pkru); dprintf2("%s() masked pkey_reg: %x\n", __func__, masked_pkey_reg);
/* /*
* shift down the relevant bits to the lowest two, then * shift down the relevant bits to the lowest two, then
* mask off all the other high bits. * mask off all the other high bits.
*/ */
return masked_pkru; return masked_pkey_reg;
} }
static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags) static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags)
{ {
u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
u32 old_pkru = __rdpkru(); u32 old_pkey_reg = __read_pkey_reg();
u32 new_pkru; u32 new_pkey_reg;
/* make sure that 'rights' only contains the bits we expect: */ /* make sure that 'rights' only contains the bits we expect: */
assert(!(rights & ~mask)); assert(!(rights & ~mask));
/* copy old pkru */ /* copy old pkey_reg */
new_pkru = old_pkru; new_pkey_reg = old_pkey_reg;
/* mask out bits from pkey in old value: */ /* mask out bits from pkey in old value: */
new_pkru &= ~(mask << (pkey * PKRU_BITS_PER_PKEY)); new_pkey_reg &= ~(mask << (pkey * PKEY_BITS_PER_PKEY));
/* OR in new bits for pkey: */ /* OR in new bits for pkey: */
new_pkru |= (rights << (pkey * PKRU_BITS_PER_PKEY)); new_pkey_reg |= (rights << (pkey * PKEY_BITS_PER_PKEY));
__wrpkru(new_pkru); __write_pkey_reg(new_pkey_reg);
dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x pkru now: %x old_pkru: %x\n", dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x"
__func__, pkey, rights, flags, 0, __rdpkru(), old_pkru); " pkey_reg now: %x old_pkey_reg: %x\n",
__func__, pkey, rights, flags, 0, __read_pkey_reg(),
old_pkey_reg);
return 0; return 0;
} }
@ -449,7 +454,7 @@ void pkey_disable_set(int pkey, int flags)
unsigned long syscall_flags = 0; unsigned long syscall_flags = 0;
int ret; int ret;
int pkey_rights; int pkey_rights;
u32 orig_pkru = rdpkru(); u32 orig_pkey_reg = read_pkey_reg();
dprintf1("START->%s(%d, 0x%x)\n", __func__, dprintf1("START->%s(%d, 0x%x)\n", __func__,
pkey, flags); pkey, flags);
@ -465,9 +470,9 @@ void pkey_disable_set(int pkey, int flags)
ret = hw_pkey_set(pkey, pkey_rights, syscall_flags); ret = hw_pkey_set(pkey, pkey_rights, syscall_flags);
assert(!ret); assert(!ret);
/*pkru and flags have the same format */ /* pkey_reg and flags have the same format */
shadow_pkru |= flags << (pkey * 2); shadow_pkey_reg |= flags << (pkey * 2);
dprintf1("%s(%d) shadow: 0x%x\n", __func__, pkey, shadow_pkru); dprintf1("%s(%d) shadow: 0x%x\n", __func__, pkey, shadow_pkey_reg);
pkey_assert(ret >= 0); pkey_assert(ret >= 0);
@ -475,9 +480,9 @@ void pkey_disable_set(int pkey, int flags)
dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
pkey, pkey, pkey_rights); pkey, pkey, pkey_rights);
dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); dprintf1("%s(%d) pkey_reg: 0x%x\n", __func__, pkey, read_pkey_reg());
if (flags) if (flags)
pkey_assert(rdpkru() > orig_pkru); pkey_assert(read_pkey_reg() > orig_pkey_reg);
dprintf1("END<---%s(%d, 0x%x)\n", __func__, dprintf1("END<---%s(%d, 0x%x)\n", __func__,
pkey, flags); pkey, flags);
} }
@ -487,7 +492,7 @@ void pkey_disable_clear(int pkey, int flags)
unsigned long syscall_flags = 0; unsigned long syscall_flags = 0;
int ret; int ret;
int pkey_rights = hw_pkey_get(pkey, syscall_flags); int pkey_rights = hw_pkey_get(pkey, syscall_flags);
u32 orig_pkru = rdpkru(); u32 orig_pkey_reg = read_pkey_reg();
pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
@ -498,17 +503,16 @@ void pkey_disable_clear(int pkey, int flags)
pkey_rights |= flags; pkey_rights |= flags;
ret = hw_pkey_set(pkey, pkey_rights, 0); ret = hw_pkey_set(pkey, pkey_rights, 0);
/* pkru and flags have the same format */ shadow_pkey_reg &= ~(flags << (pkey * 2));
shadow_pkru &= ~(flags << (pkey * 2));
pkey_assert(ret >= 0); pkey_assert(ret >= 0);
pkey_rights = hw_pkey_get(pkey, syscall_flags); pkey_rights = hw_pkey_get(pkey, syscall_flags);
dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
pkey, pkey, pkey_rights); pkey, pkey, pkey_rights);
dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); dprintf1("%s(%d) pkey_reg: 0x%x\n", __func__, pkey, read_pkey_reg());
if (flags) if (flags)
assert(rdpkru() > orig_pkru); assert(read_pkey_reg() > orig_pkey_reg);
} }
void pkey_write_allow(int pkey) void pkey_write_allow(int pkey)
@ -561,33 +565,38 @@ int alloc_pkey(void)
int ret; int ret;
unsigned long init_val = 0x0; unsigned long init_val = 0x0;
dprintf1("alloc_pkey()::%d, pkru: 0x%x shadow: %x\n", dprintf1("%s()::%d, pkey_reg: 0x%x shadow: %x\n", __func__,
__LINE__, __rdpkru(), shadow_pkru); __LINE__, __read_pkey_reg(), shadow_pkey_reg);
ret = sys_pkey_alloc(0, init_val); ret = sys_pkey_alloc(0, init_val);
/* /*
* pkey_alloc() sets PKRU, so we need to reflect it in * pkey_alloc() sets PKEY register, so we need to reflect it in
* shadow_pkru: * shadow_pkey_reg:
*/ */
dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__, __LINE__, ret, __read_pkey_reg(),
shadow_pkey_reg);
if (ret) { if (ret) {
/* clear both the bits: */ /* clear both the bits: */
shadow_pkru &= ~(0x3 << (ret * 2)); shadow_pkey_reg &= ~(0x3 << (ret * 2));
dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__,
__LINE__, ret, __read_pkey_reg(),
shadow_pkey_reg);
/* /*
* move the new state in from init_val * move the new state in from init_val
* (remember, we cheated and init_val == pkru format) * (remember, we cheated and init_val == pkey_reg format)
*/ */
shadow_pkru |= (init_val << (ret * 2)); shadow_pkey_reg |= (init_val << (ret * 2));
} }
dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__, __LINE__, ret, __read_pkey_reg(),
dprintf1("alloc_pkey()::%d errno: %d\n", __LINE__, errno); shadow_pkey_reg);
dprintf1("%s()::%d errno: %d\n", __func__, __LINE__, errno);
/* for shadow checking: */ /* for shadow checking: */
rdpkru(); read_pkey_reg();
dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__, __LINE__, ret, __read_pkey_reg(),
shadow_pkey_reg);
return ret; return ret;
} }
@ -638,8 +647,8 @@ int alloc_random_pkey(void)
free_ret = sys_pkey_free(alloced_pkeys[i]); free_ret = sys_pkey_free(alloced_pkeys[i]);
pkey_assert(!free_ret); pkey_assert(!free_ret);
} }
dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__, dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n", __func__,
__LINE__, ret, __rdpkru(), shadow_pkru); __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg);
return ret; return ret;
} }
@ -657,11 +666,13 @@ int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
if (nr_iterations-- < 0) if (nr_iterations-- < 0)
break; break;
dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__, dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__, __LINE__, ret, __read_pkey_reg(),
shadow_pkey_reg);
sys_pkey_free(rpkey); sys_pkey_free(rpkey);
dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__, dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, ret, __rdpkru(), shadow_pkru); __func__, __LINE__, ret, __read_pkey_reg(),
shadow_pkey_reg);
} }
pkey_assert(pkey < NR_PKEYS); pkey_assert(pkey < NR_PKEYS);
@ -669,8 +680,8 @@ int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n", dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
ptr, size, orig_prot, pkey, ret); ptr, size, orig_prot, pkey, ret);
pkey_assert(!ret); pkey_assert(!ret);
dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__, dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n", __func__,
__LINE__, ret, __rdpkru(), shadow_pkru); __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg);
return ret; return ret;
} }
@ -752,7 +763,7 @@ void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey)
void *ptr; void *ptr;
int ret; int ret;
rdpkru(); read_pkey_reg();
dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__, dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
size, prot, pkey); size, prot, pkey);
pkey_assert(pkey < NR_PKEYS); pkey_assert(pkey < NR_PKEYS);
@ -761,7 +772,7 @@ void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey)
ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey); ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey);
pkey_assert(!ret); pkey_assert(!ret);
record_pkey_malloc(ptr, size, prot); record_pkey_malloc(ptr, size, prot);
rdpkru(); read_pkey_reg();
dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr); dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr);
return ptr; return ptr;
@ -924,14 +935,14 @@ void *malloc_pkey(long size, int prot, u16 pkey)
return ret; return ret;
} }
int last_pkru_faults; int last_pkey_faults;
#define UNKNOWN_PKEY -2 #define UNKNOWN_PKEY -2
void expected_pk_fault(int pkey) void expected_pkey_fault(int pkey)
{ {
dprintf2("%s(): last_pkru_faults: %d pkru_faults: %d\n", dprintf2("%s(): last_pkey_faults: %d pkey_faults: %d\n",
__func__, last_pkru_faults, pkru_faults); __func__, last_pkey_faults, pkey_faults);
dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey); dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey);
pkey_assert(last_pkru_faults + 1 == pkru_faults); pkey_assert(last_pkey_faults + 1 == pkey_faults);
/* /*
* For exec-only memory, we do not know the pkey in * For exec-only memory, we do not know the pkey in
@ -941,23 +952,23 @@ void expected_pk_fault(int pkey)
pkey_assert(last_si_pkey == pkey); pkey_assert(last_si_pkey == pkey);
/* /*
* The signal handler shold have cleared out PKRU to let the * The signal handler shold have cleared out PKEY register to let the
* test program continue. We now have to restore it. * test program continue. We now have to restore it.
*/ */
if (__rdpkru() != 0) if (__read_pkey_reg() != 0)
pkey_assert(0); pkey_assert(0);
__wrpkru(shadow_pkru); __write_pkey_reg(shadow_pkey_reg);
dprintf1("%s() set PKRU=%x to restore state after signal nuked it\n", dprintf1("%s() set pkey_reg=%x to restore state after signal "
__func__, shadow_pkru); "nuked it\n", __func__, shadow_pkey_reg);
last_pkru_faults = pkru_faults; last_pkey_faults = pkey_faults;
last_si_pkey = -1; last_si_pkey = -1;
} }
#define do_not_expect_pk_fault(msg) do { \ #define do_not_expect_pkey_fault(msg) do { \
if (last_pkru_faults != pkru_faults) \ if (last_pkey_faults != pkey_faults) \
dprintf0("unexpected PK fault: %s\n", msg); \ dprintf0("unexpected PKey fault: %s\n", msg); \
pkey_assert(last_pkru_faults == pkru_faults); \ pkey_assert(last_pkey_faults == pkey_faults); \
} while (0) } while (0)
int test_fds[10] = { -1 }; int test_fds[10] = { -1 };
@ -1015,25 +1026,25 @@ void test_read_of_access_disabled_region(int *ptr, u16 pkey)
int ptr_contents; int ptr_contents;
dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr); dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr);
rdpkru(); read_pkey_reg();
pkey_access_deny(pkey); pkey_access_deny(pkey);
ptr_contents = read_ptr(ptr); ptr_contents = read_ptr(ptr);
dprintf1("*ptr: %d\n", ptr_contents); dprintf1("*ptr: %d\n", ptr_contents);
expected_pk_fault(pkey); expected_pkey_fault(pkey);
} }
void test_write_of_write_disabled_region(int *ptr, u16 pkey) void test_write_of_write_disabled_region(int *ptr, u16 pkey)
{ {
dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey); dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey);
pkey_write_deny(pkey); pkey_write_deny(pkey);
*ptr = __LINE__; *ptr = __LINE__;
expected_pk_fault(pkey); expected_pkey_fault(pkey);
} }
void test_write_of_access_disabled_region(int *ptr, u16 pkey) void test_write_of_access_disabled_region(int *ptr, u16 pkey)
{ {
dprintf1("disabling access to PKEY[%02d], doing write\n", pkey); dprintf1("disabling access to PKEY[%02d], doing write\n", pkey);
pkey_access_deny(pkey); pkey_access_deny(pkey);
*ptr = __LINE__; *ptr = __LINE__;
expected_pk_fault(pkey); expected_pkey_fault(pkey);
} }
void test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey) void test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey)
{ {
@ -1160,9 +1171,10 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
int new_pkey; int new_pkey;
dprintf1("%s() alloc loop: %d\n", __func__, i); dprintf1("%s() alloc loop: %d\n", __func__, i);
new_pkey = alloc_pkey(); new_pkey = alloc_pkey();
dprintf4("%s()::%d, err: %d pkru: 0x%x shadow: 0x%x\n", __func__, dprintf4("%s()::%d, err: %d pkey_reg: 0x%x shadow: 0x%x\n",
__LINE__, err, __rdpkru(), shadow_pkru); __func__, __LINE__, err, __read_pkey_reg(),
rdpkru(); /* for shadow checking */ shadow_pkey_reg);
read_pkey_reg(); /* for shadow checking */
dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC); dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC);
if ((new_pkey == -1) && (errno == ENOSPC)) { if ((new_pkey == -1) && (errno == ENOSPC)) {
dprintf2("%s() failed to allocate pkey after %d tries\n", dprintf2("%s() failed to allocate pkey after %d tries\n",
@ -1201,7 +1213,7 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
for (i = 0; i < nr_allocated_pkeys; i++) { for (i = 0; i < nr_allocated_pkeys; i++) {
err = sys_pkey_free(allocated_pkeys[i]); err = sys_pkey_free(allocated_pkeys[i]);
pkey_assert(!err); pkey_assert(!err);
rdpkru(); /* for shadow checking */ read_pkey_reg(); /* for shadow checking */
} }
} }
@ -1287,7 +1299,7 @@ void test_ptrace_of_child(int *ptr, u16 pkey)
pkey_assert(ret != -1); pkey_assert(ret != -1);
/* Now access from the current task, and expect an exception: */ /* Now access from the current task, and expect an exception: */
peek_result = read_ptr(ptr); peek_result = read_ptr(ptr);
expected_pk_fault(pkey); expected_pkey_fault(pkey);
/* /*
* Try to access the NON-pkey-protected "plain_ptr" via ptrace: * Try to access the NON-pkey-protected "plain_ptr" via ptrace:
@ -1297,7 +1309,7 @@ void test_ptrace_of_child(int *ptr, u16 pkey)
pkey_assert(ret != -1); pkey_assert(ret != -1);
/* Now access from the current task, and expect NO exception: */ /* Now access from the current task, and expect NO exception: */
peek_result = read_ptr(plain_ptr); peek_result = read_ptr(plain_ptr);
do_not_expect_pk_fault("read plain pointer after ptrace"); do_not_expect_pkey_fault("read plain pointer after ptrace");
ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0); ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0);
pkey_assert(ret != -1); pkey_assert(ret != -1);
@ -1347,17 +1359,17 @@ void test_executing_on_unreadable_memory(int *ptr, u16 pkey)
pkey_assert(!ret); pkey_assert(!ret);
pkey_access_deny(pkey); pkey_access_deny(pkey);
dprintf2("pkru: %x\n", rdpkru()); dprintf2("pkey_reg: %x\n", read_pkey_reg());
/* /*
* Make sure this is an *instruction* fault * Make sure this is an *instruction* fault
*/ */
madvise(p1, PAGE_SIZE, MADV_DONTNEED); madvise(p1, PAGE_SIZE, MADV_DONTNEED);
lots_o_noops_around_write(&scratch); lots_o_noops_around_write(&scratch);
do_not_expect_pk_fault("executing on PROT_EXEC memory"); do_not_expect_pkey_fault("executing on PROT_EXEC memory");
ptr_contents = read_ptr(p1); ptr_contents = read_ptr(p1);
dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
expected_pk_fault(pkey); expected_pkey_fault(pkey);
} }
void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey) void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
@ -1378,15 +1390,15 @@ void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
ret = mprotect(p1, PAGE_SIZE, PROT_EXEC); ret = mprotect(p1, PAGE_SIZE, PROT_EXEC);
pkey_assert(!ret); pkey_assert(!ret);
dprintf2("pkru: %x\n", rdpkru()); dprintf2("pkru: %x\n", read_pkey_reg());
/* Make sure this is an *instruction* fault */ /* Make sure this is an *instruction* fault */
madvise(p1, PAGE_SIZE, MADV_DONTNEED); madvise(p1, PAGE_SIZE, MADV_DONTNEED);
lots_o_noops_around_write(&scratch); lots_o_noops_around_write(&scratch);
do_not_expect_pk_fault("executing on PROT_EXEC memory"); do_not_expect_pkey_fault("executing on PROT_EXEC memory");
ptr_contents = read_ptr(p1); ptr_contents = read_ptr(p1);
dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
expected_pk_fault(UNKNOWN_PKEY); expected_pkey_fault(UNKNOWN_PKEY);
/* /*
* Put the memory back to non-PROT_EXEC. Should clear the * Put the memory back to non-PROT_EXEC. Should clear the
@ -1400,7 +1412,7 @@ void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC); ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC);
pkey_assert(!ret); pkey_assert(!ret);
ptr_contents = read_ptr(p1); ptr_contents = read_ptr(p1);
do_not_expect_pk_fault("plain read on recently PROT_EXEC area"); do_not_expect_pkey_fault("plain read on recently PROT_EXEC area");
} }
void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
@ -1442,7 +1454,7 @@ void run_tests_once(void)
for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) { for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) {
int pkey; int pkey;
int orig_pkru_faults = pkru_faults; int orig_pkey_faults = pkey_faults;
dprintf1("======================\n"); dprintf1("======================\n");
dprintf1("test %d preparing...\n", test_nr); dprintf1("test %d preparing...\n", test_nr);
@ -1457,8 +1469,8 @@ void run_tests_once(void)
free_pkey_malloc(ptr); free_pkey_malloc(ptr);
sys_pkey_free(pkey); sys_pkey_free(pkey);
dprintf1("pkru_faults: %d\n", pkru_faults); dprintf1("pkey_faults: %d\n", pkey_faults);
dprintf1("orig_pkru_faults: %d\n", orig_pkru_faults); dprintf1("orig_pkey_faults: %d\n", orig_pkey_faults);
tracing_off(); tracing_off();
close_test_fds(); close_test_fds();
@ -1471,7 +1483,7 @@ void run_tests_once(void)
void pkey_setup_shadow(void) void pkey_setup_shadow(void)
{ {
shadow_pkru = __rdpkru(); shadow_pkey_reg = __read_pkey_reg();
} }
int main(void) int main(void)
@ -1495,7 +1507,7 @@ int main(void)
} }
pkey_setup_shadow(); pkey_setup_shadow();
printf("startup pkru: %x\n", rdpkru()); printf("startup pkey_reg: %x\n", read_pkey_reg());
setup_hugetlbfs(); setup_hugetlbfs();
while (nr_iterations-- > 0) while (nr_iterations-- > 0)