Skip to content

Commit 6e182dc

Browse files
kevin-brodsky-armctmarinas
authored andcommitted
selftests/mm: Use generic pkey register manipulation
pkey_sighandler_tests.c currently hardcodes x86 PKRU encodings. The first step towards running those tests on arm64 is to abstract away the pkey register values. Since those tests want to deny access to all keys except a few, we have each arch define PKEY_REG_ALLOW_NONE, the pkey register value denying access to all keys. We then use the existing set_pkey_bits() helper to grant access to specific keys. Because pkeys may also remove the execute permission on arm64, we need to be a little careful: all code is mapped with pkey 0, and we need it to remain executable. pkey_reg_restrictive_default() is introduced for that purpose: the value it returns prevents RW access to all pkeys, but retains X permission for pkey 0. test_pkru_preserved_after_sigusr1() only checks that the pkey register value remains unchanged after a signal is delivered, so the particular value is irrelevant. We enable pkey 0 and a few more arbitrary keys in the smallest range available on all architectures (8 keys on arm64). Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com> Acked-by: Dave Hansen <dave.hansen@linux.intel.com> Link: https://lore.kernel.org/r/20241029144539.111155-5-kevin.brodsky@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 8edbbfc commit 6e182dc

File tree

3 files changed

+47
-9
lines changed

3 files changed

+47
-9
lines changed

tools/testing/selftests/mm/pkey-arm64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define NR_RESERVED_PKEYS 1 /* pkey-0 */
3232

3333
#define PKEY_ALLOW_ALL 0x77777777
34+
#define PKEY_REG_ALLOW_NONE 0x0
3435

3536
#define PKEY_BITS_PER_PKEY 4
3637
#define PAGE_SIZE sysconf(_SC_PAGESIZE)

tools/testing/selftests/mm/pkey-x86.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define PAGE_SIZE 4096
3535
#define MB (1<<20)
3636

37+
#define PKEY_REG_ALLOW_NONE 0x55555555
38+
3739
static inline void __page_o_noops(void)
3840
{
3941
/* 8-bytes of instruction * 512 bytes = 1 page */

tools/testing/selftests/mm/pkey_sighandler_tests.c

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
#define _GNU_SOURCE
1313
#define __SANE_USERSPACE_TYPES__
14+
#include <linux/mman.h>
1415
#include <errno.h>
1516
#include <sys/syscall.h>
1617
#include <string.h>
@@ -65,6 +66,20 @@ long syscall_raw(long n, long a1, long a2, long a3, long a4, long a5, long a6)
6566
return ret;
6667
}
6768

69+
/*
70+
* Returns the most restrictive pkey register value that can be used by the
71+
* tests.
72+
*/
73+
static inline u64 pkey_reg_restrictive_default(void)
74+
{
75+
/*
76+
* Disallow everything except execution on pkey 0, so that each caller
77+
* doesn't need to enable it explicitly (the selftest code runs with
78+
* its code mapped with pkey 0).
79+
*/
80+
return set_pkey_bits(PKEY_REG_ALLOW_NONE, 0, PKEY_DISABLE_ACCESS);
81+
}
82+
6883
static void sigsegv_handler(int signo, siginfo_t *info, void *ucontext)
6984
{
7085
pthread_mutex_lock(&mutex);
@@ -113,7 +128,7 @@ static void raise_sigusr2(void)
113128
static void *thread_segv_with_pkey0_disabled(void *ptr)
114129
{
115130
/* Disable MPK 0 (and all others too) */
116-
__write_pkey_reg(0x55555555);
131+
__write_pkey_reg(pkey_reg_restrictive_default());
117132

118133
/* Segfault (with SEGV_MAPERR) */
119134
*(int *) (0x1) = 1;
@@ -123,7 +138,7 @@ static void *thread_segv_with_pkey0_disabled(void *ptr)
123138
static void *thread_segv_pkuerr_stack(void *ptr)
124139
{
125140
/* Disable MPK 0 (and all others too) */
126-
__write_pkey_reg(0x55555555);
141+
__write_pkey_reg(pkey_reg_restrictive_default());
127142

128143
/* After we disable MPK 0, we can't access the stack to return */
129144
return NULL;
@@ -133,6 +148,7 @@ static void *thread_segv_maperr_ptr(void *ptr)
133148
{
134149
stack_t *stack = ptr;
135150
int *bad = (int *)1;
151+
u64 pkey_reg;
136152

137153
/*
138154
* Setup alternate signal stack, which should be pkey_mprotect()ed by
@@ -142,7 +158,9 @@ static void *thread_segv_maperr_ptr(void *ptr)
142158
syscall_raw(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
143159

144160
/* Disable MPK 0. Only MPK 1 is enabled. */
145-
__write_pkey_reg(0x55555551);
161+
pkey_reg = pkey_reg_restrictive_default();
162+
pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
163+
__write_pkey_reg(pkey_reg);
146164

147165
/* Segfault */
148166
*bad = 1;
@@ -240,6 +258,7 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
240258
int pkey;
241259
int parent_pid = 0;
242260
int child_pid = 0;
261+
u64 pkey_reg;
243262

244263
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
245264

@@ -257,7 +276,10 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
257276
assert(stack != MAP_FAILED);
258277

259278
/* Allow access to MPK 0 and MPK 1 */
260-
__write_pkey_reg(0x55555550);
279+
pkey_reg = pkey_reg_restrictive_default();
280+
pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
281+
pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
282+
__write_pkey_reg(pkey_reg);
261283

262284
/* Protect the new stack with MPK 1 */
263285
pkey = pkey_alloc(0, 0);
@@ -307,7 +329,13 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
307329
static void test_pkru_preserved_after_sigusr1(void)
308330
{
309331
struct sigaction sa;
310-
unsigned long pkru = 0x45454544;
332+
u64 pkey_reg;
333+
334+
/* Allow access to MPK 0 and an arbitrary set of keys */
335+
pkey_reg = pkey_reg_restrictive_default();
336+
pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
337+
pkey_reg = set_pkey_bits(pkey_reg, 3, PKEY_UNRESTRICTED);
338+
pkey_reg = set_pkey_bits(pkey_reg, 7, PKEY_UNRESTRICTED);
311339

312340
sa.sa_flags = SA_SIGINFO;
313341

@@ -320,7 +348,7 @@ static void test_pkru_preserved_after_sigusr1(void)
320348

321349
memset(&siginfo, 0, sizeof(siginfo));
322350

323-
__write_pkey_reg(pkru);
351+
__write_pkey_reg(pkey_reg);
324352

325353
raise(SIGUSR1);
326354

@@ -330,7 +358,7 @@ static void test_pkru_preserved_after_sigusr1(void)
330358
pthread_mutex_unlock(&mutex);
331359

332360
/* Ensure the pkru value is the same after returning from signal. */
333-
ksft_test_result(pkru == __read_pkey_reg() &&
361+
ksft_test_result(pkey_reg == __read_pkey_reg() &&
334362
siginfo.si_signo == SIGUSR1,
335363
"%s\n", __func__);
336364
}
@@ -347,6 +375,7 @@ static noinline void *thread_sigusr2_self(void *ptr)
347375
'S', 'I', 'G', 'U', 'S', 'R', '2',
348376
'.', '.', '.', '\n', '\0'};
349377
stack_t *stack = ptr;
378+
u64 pkey_reg;
350379

351380
/*
352381
* Setup alternate signal stack, which should be pkey_mprotect()ed by
@@ -356,7 +385,9 @@ static noinline void *thread_sigusr2_self(void *ptr)
356385
syscall(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
357386

358387
/* Disable MPK 0. Only MPK 2 is enabled. */
359-
__write_pkey_reg(0x55555545);
388+
pkey_reg = pkey_reg_restrictive_default();
389+
pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
390+
__write_pkey_reg(pkey_reg);
360391

361392
raise_sigusr2();
362393

@@ -384,6 +415,7 @@ static void test_pkru_sigreturn(void)
384415
int pkey;
385416
int parent_pid = 0;
386417
int child_pid = 0;
418+
u64 pkey_reg;
387419

388420
sa.sa_handler = SIG_DFL;
389421
sa.sa_flags = 0;
@@ -418,7 +450,10 @@ static void test_pkru_sigreturn(void)
418450
* the current thread's stack is protected by the default MPK 0. Hence
419451
* both need to be enabled.
420452
*/
421-
__write_pkey_reg(0x55555544);
453+
pkey_reg = pkey_reg_restrictive_default();
454+
pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
455+
pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
456+
__write_pkey_reg(pkey_reg);
422457

423458
/* Protect the stack with MPK 2 */
424459
pkey = pkey_alloc(0, 0);

0 commit comments

Comments
 (0)