]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/mm: Use generic pkey register manipulation
authorKevin Brodsky <kevin.brodsky@arm.com>
Tue, 29 Oct 2024 14:45:38 +0000 (14:45 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Mon, 4 Nov 2024 16:31:25 +0000 (16:31 +0000)
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>
tools/testing/selftests/mm/pkey-arm64.h
tools/testing/selftests/mm/pkey-x86.h
tools/testing/selftests/mm/pkey_sighandler_tests.c

index 580e1b0bb38e8de8df03a0b5d692b252f9ba5265..d57fbeace38f4e2b5bb585e987717f6bbdf246c5 100644 (file)
@@ -31,6 +31,7 @@
 #define NR_RESERVED_PKEYS      1 /* pkey-0 */
 
 #define PKEY_ALLOW_ALL         0x77777777
+#define PKEY_REG_ALLOW_NONE    0x0
 
 #define PKEY_BITS_PER_PKEY     4
 #define PAGE_SIZE              sysconf(_SC_PAGESIZE)
index 5f28e26a2511d5ec0a55019592b272d48cea1355..ac91777c8917978f35473c5b77e297002c2adac3 100644 (file)
@@ -34,6 +34,8 @@
 #define PAGE_SIZE              4096
 #define MB                     (1<<20)
 
+#define PKEY_REG_ALLOW_NONE    0x55555555
+
 static inline void __page_o_noops(void)
 {
        /* 8-bytes of instruction * 512 bytes = 1 page */
index a8088b645ad6dcb0757486da0d56873d92a34770..501880dbdc3770ce5ac45716204b60a71dc87ac4 100644 (file)
@@ -11,6 +11,7 @@
  */
 #define _GNU_SOURCE
 #define __SANE_USERSPACE_TYPES__
+#include <linux/mman.h>
 #include <errno.h>
 #include <sys/syscall.h>
 #include <string.h>
@@ -65,6 +66,20 @@ long syscall_raw(long n, long a1, long a2, long a3, long a4, long a5, long a6)
        return ret;
 }
 
+/*
+ * Returns the most restrictive pkey register value that can be used by the
+ * tests.
+ */
+static inline u64 pkey_reg_restrictive_default(void)
+{
+       /*
+        * Disallow everything except execution on pkey 0, so that each caller
+        * doesn't need to enable it explicitly (the selftest code runs with
+        * its code mapped with pkey 0).
+        */
+       return set_pkey_bits(PKEY_REG_ALLOW_NONE, 0, PKEY_DISABLE_ACCESS);
+}
+
 static void sigsegv_handler(int signo, siginfo_t *info, void *ucontext)
 {
        pthread_mutex_lock(&mutex);
@@ -113,7 +128,7 @@ static void raise_sigusr2(void)
 static void *thread_segv_with_pkey0_disabled(void *ptr)
 {
        /* Disable MPK 0 (and all others too) */
-       __write_pkey_reg(0x55555555);
+       __write_pkey_reg(pkey_reg_restrictive_default());
 
        /* Segfault (with SEGV_MAPERR) */
        *(int *) (0x1) = 1;
@@ -123,7 +138,7 @@ static void *thread_segv_with_pkey0_disabled(void *ptr)
 static void *thread_segv_pkuerr_stack(void *ptr)
 {
        /* Disable MPK 0 (and all others too) */
-       __write_pkey_reg(0x55555555);
+       __write_pkey_reg(pkey_reg_restrictive_default());
 
        /* After we disable MPK 0, we can't access the stack to return */
        return NULL;
@@ -133,6 +148,7 @@ static void *thread_segv_maperr_ptr(void *ptr)
 {
        stack_t *stack = ptr;
        int *bad = (int *)1;
+       u64 pkey_reg;
 
        /*
         * Setup alternate signal stack, which should be pkey_mprotect()ed by
@@ -142,7 +158,9 @@ static void *thread_segv_maperr_ptr(void *ptr)
        syscall_raw(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
 
        /* Disable MPK 0.  Only MPK 1 is enabled. */
-       __write_pkey_reg(0x55555551);
+       pkey_reg = pkey_reg_restrictive_default();
+       pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
+       __write_pkey_reg(pkey_reg);
 
        /* Segfault */
        *bad = 1;
@@ -240,6 +258,7 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
        int pkey;
        int parent_pid = 0;
        int child_pid = 0;
+       u64 pkey_reg;
 
        sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
 
@@ -257,7 +276,10 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
        assert(stack != MAP_FAILED);
 
        /* Allow access to MPK 0 and MPK 1 */
-       __write_pkey_reg(0x55555550);
+       pkey_reg = pkey_reg_restrictive_default();
+       pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
+       pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
+       __write_pkey_reg(pkey_reg);
 
        /* Protect the new stack with MPK 1 */
        pkey = pkey_alloc(0, 0);
@@ -307,7 +329,13 @@ static void test_sigsegv_handler_with_different_pkey_for_stack(void)
 static void test_pkru_preserved_after_sigusr1(void)
 {
        struct sigaction sa;
-       unsigned long pkru = 0x45454544;
+       u64 pkey_reg;
+
+       /* Allow access to MPK 0 and an arbitrary set of keys */
+       pkey_reg = pkey_reg_restrictive_default();
+       pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
+       pkey_reg = set_pkey_bits(pkey_reg, 3, PKEY_UNRESTRICTED);
+       pkey_reg = set_pkey_bits(pkey_reg, 7, PKEY_UNRESTRICTED);
 
        sa.sa_flags = SA_SIGINFO;
 
@@ -320,7 +348,7 @@ static void test_pkru_preserved_after_sigusr1(void)
 
        memset(&siginfo, 0, sizeof(siginfo));
 
-       __write_pkey_reg(pkru);
+       __write_pkey_reg(pkey_reg);
 
        raise(SIGUSR1);
 
@@ -330,7 +358,7 @@ static void test_pkru_preserved_after_sigusr1(void)
        pthread_mutex_unlock(&mutex);
 
        /* Ensure the pkru value is the same after returning from signal. */
-       ksft_test_result(pkru == __read_pkey_reg() &&
+       ksft_test_result(pkey_reg == __read_pkey_reg() &&
                         siginfo.si_signo == SIGUSR1,
                         "%s\n", __func__);
 }
@@ -347,6 +375,7 @@ static noinline void *thread_sigusr2_self(void *ptr)
                'S', 'I', 'G', 'U', 'S', 'R', '2',
                '.', '.', '.', '\n', '\0'};
        stack_t *stack = ptr;
+       u64 pkey_reg;
 
        /*
         * Setup alternate signal stack, which should be pkey_mprotect()ed by
@@ -356,7 +385,9 @@ static noinline void *thread_sigusr2_self(void *ptr)
        syscall(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
 
        /* Disable MPK 0.  Only MPK 2 is enabled. */
-       __write_pkey_reg(0x55555545);
+       pkey_reg = pkey_reg_restrictive_default();
+       pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
+       __write_pkey_reg(pkey_reg);
 
        raise_sigusr2();
 
@@ -384,6 +415,7 @@ static void test_pkru_sigreturn(void)
        int pkey;
        int parent_pid = 0;
        int child_pid = 0;
+       u64 pkey_reg;
 
        sa.sa_handler = SIG_DFL;
        sa.sa_flags = 0;
@@ -418,7 +450,10 @@ static void test_pkru_sigreturn(void)
         * the current thread's stack is protected by the default MPK 0. Hence
         * both need to be enabled.
         */
-       __write_pkey_reg(0x55555544);
+       pkey_reg = pkey_reg_restrictive_default();
+       pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
+       pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
+       __write_pkey_reg(pkey_reg);
 
        /* Protect the stack with MPK 2 */
        pkey = pkey_alloc(0, 0);