| From: Swarup Laxman Kotiaklapudi <swarupkotikalapudi@gmail.com> |
| Subject: proc: test ProtectionKey in proc-empty-vm test |
| Date: Fri, 27 Oct 2023 17:26:24 +0300 |
| |
| Check ProtectionKey field in /proc/*/smaps output, if system supports |
| protection keys feature. |
| |
| [adobriyan@gmail.com: test support in the beginning of the program, use syscall, not glibc pkey_alloc(3) which may not compile] |
| |
| Link: https://lkml.kernel.org/r/ac05efa7-d2a0-48ad-b704-ffdd5450582e@p183 |
| Signed-off-by: Swarup Laxman Kotiaklapudi <swarupkotikalapudi@gmail.com> |
| Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> |
| Reviewed-by: Swarup Laxman Kotikalapudi<swarupkotikalapudi@gmail.com> |
| Tested-by: Swarup Laxman Kotikalapudi<swarupkotikalapudi@gmail.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| tools/testing/selftests/proc/proc-empty-vm.c | 79 +++++++++++++---- |
| 1 file changed, 61 insertions(+), 18 deletions(-) |
| |
| --- a/tools/testing/selftests/proc/proc-empty-vm.c~proc-test-protectionkey-in-proc-empty-vm-test |
| +++ a/tools/testing/selftests/proc/proc-empty-vm.c |
| @@ -23,6 +23,9 @@ |
| * /proc/${pid}/smaps |
| * /proc/${pid}/smaps_rollup |
| */ |
| +#undef _GNU_SOURCE |
| +#define _GNU_SOURCE |
| + |
| #undef NDEBUG |
| #include <assert.h> |
| #include <errno.h> |
| @@ -34,6 +37,7 @@ |
| #include <sys/mman.h> |
| #include <sys/ptrace.h> |
| #include <sys/resource.h> |
| +#include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <unistd.h> |
| @@ -42,6 +46,43 @@ |
| #define TEST_VSYSCALL |
| #endif |
| |
| +#if defined __amd64__ |
| + #ifndef SYS_pkey_alloc |
| + #define SYS_pkey_alloc 330 |
| + #endif |
| + #ifndef SYS_pkey_free |
| + #define SYS_pkey_free 331 |
| + #endif |
| +#elif defined __i386__ |
| + #ifndef SYS_pkey_alloc |
| + #define SYS_pkey_alloc 381 |
| + #endif |
| + #ifndef SYS_pkey_free |
| + #define SYS_pkey_free 382 |
| + #endif |
| +#else |
| + #error "SYS_pkey_alloc" |
| +#endif |
| + |
| +static int g_protection_key_support; |
| + |
| +static int protection_key_support(void) |
| +{ |
| + long rv = syscall(SYS_pkey_alloc, 0, 0); |
| + if (rv > 0) { |
| + syscall(SYS_pkey_free, (int)rv); |
| + return 1; |
| + } else if (rv == -1 && errno == ENOSYS) { |
| + return 0; |
| + } else if (rv == -1 && errno == EINVAL) { |
| + // ospke=n |
| + return 0; |
| + } else { |
| + fprintf(stderr, "%s: error: rv %ld, errno %d\n", __func__, rv, errno); |
| + exit(EXIT_FAILURE); |
| + } |
| +} |
| + |
| /* |
| * 0: vsyscall VMA doesn't exist vsyscall=none |
| * 1: vsyscall VMA is --xp vsyscall=xonly |
| @@ -84,10 +125,6 @@ static const char proc_pid_smaps_vsyscal |
| "SwapPss: 0 kB\n" |
| "Locked: 0 kB\n" |
| "THPeligible: 0\n" |
| -/* |
| - * "ProtectionKey:" field is conditional. It is possible to check it as well, |
| - * but I don't have such machine. |
| - */ |
| ; |
| |
| static const char proc_pid_smaps_vsyscall_2[] = |
| @@ -115,10 +152,6 @@ static const char proc_pid_smaps_vsyscal |
| "SwapPss: 0 kB\n" |
| "Locked: 0 kB\n" |
| "THPeligible: 0\n" |
| -/* |
| - * "ProtectionKey:" field is conditional. It is possible to check it as well, |
| - * but I'm too tired. |
| - */ |
| ; |
| |
| static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___) |
| @@ -240,19 +273,27 @@ static int test_proc_pid_smaps(pid_t pid |
| } |
| perror("open /proc/${pid}/smaps"); |
| return EXIT_FAILURE; |
| + } |
| + ssize_t rv = read(fd, buf, sizeof(buf)); |
| + close(fd); |
| + |
| + assert(0 <= rv); |
| + assert(rv <= sizeof(buf)); |
| + |
| + if (g_vsyscall == 0) { |
| + assert(rv == 0); |
| } else { |
| - ssize_t rv = read(fd, buf, sizeof(buf)); |
| - close(fd); |
| - if (g_vsyscall == 0) { |
| - assert(rv == 0); |
| - } else { |
| - size_t len = strlen(g_proc_pid_smaps_vsyscall); |
| - /* TODO "ProtectionKey:" */ |
| - assert(rv > len); |
| - assert(memcmp(buf, g_proc_pid_smaps_vsyscall, len) == 0); |
| + size_t len = strlen(g_proc_pid_smaps_vsyscall); |
| + assert(rv > len); |
| + assert(memcmp(buf, g_proc_pid_smaps_vsyscall, len) == 0); |
| + |
| + if (g_protection_key_support) { |
| +#define PROTECTION_KEY "ProtectionKey: 0\n" |
| + assert(memmem(buf, rv, PROTECTION_KEY, strlen(PROTECTION_KEY))); |
| } |
| - return EXIT_SUCCESS; |
| } |
| + |
| + return EXIT_SUCCESS; |
| } |
| |
| static const char g_smaps_rollup[] = |
| @@ -419,6 +460,8 @@ int main(void) |
| abort(); |
| } |
| |
| + g_protection_key_support = protection_key_support(); |
| + |
| pid_t pid = fork(); |
| if (pid == -1) { |
| perror("fork"); |
| _ |