Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/powerpc: Add a test of sigreturning to the kernel

We have a general signal fuzzer, sigfuz, which can modify the MSR & NIP
before sigreturn. But the chance of it hitting a kernel address and also
clearing MSR_PR is fairly slim.

So add a specific test of sigreturn to a kernel address, both with and
without attempting to clear MSR_PR (which the kernel must block).

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20211209115944.4062384-1-mpe@ellerman.id.au

+134
+1
tools/testing/selftests/powerpc/signal/.gitignore
··· 4 4 sigfuz 5 5 sigreturn_vdso 6 6 sig_sc_double_restart 7 + sigreturn_kernel
+1
tools/testing/selftests/powerpc/signal/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso sig_sc_double_restart 3 + TEST_GEN_PROGS += sigreturn_kernel 3 4 4 5 CFLAGS += -maltivec 5 6 $(OUTPUT)/signal_tm: CFLAGS += -mhtm
+132
tools/testing/selftests/powerpc/signal/sigreturn_kernel.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Test that we can't sigreturn to kernel addresses, or to kernel mode. 4 + */ 5 + 6 + #define _GNU_SOURCE 7 + 8 + #include <stdio.h> 9 + #include <signal.h> 10 + #include <stdlib.h> 11 + #include <sys/types.h> 12 + #include <sys/wait.h> 13 + #include <unistd.h> 14 + 15 + #include "utils.h" 16 + 17 + #define MSR_PR (1ul << 14) 18 + 19 + static volatile unsigned long long sigreturn_addr; 20 + static volatile unsigned long long sigreturn_msr_mask; 21 + 22 + static void sigusr1_handler(int signo, siginfo_t *si, void *uc_ptr) 23 + { 24 + ucontext_t *uc = (ucontext_t *)uc_ptr; 25 + 26 + if (sigreturn_addr) 27 + UCONTEXT_NIA(uc) = sigreturn_addr; 28 + 29 + if (sigreturn_msr_mask) 30 + UCONTEXT_MSR(uc) &= sigreturn_msr_mask; 31 + } 32 + 33 + static pid_t fork_child(void) 34 + { 35 + pid_t pid; 36 + 37 + pid = fork(); 38 + if (pid == 0) { 39 + raise(SIGUSR1); 40 + exit(0); 41 + } 42 + 43 + return pid; 44 + } 45 + 46 + static int expect_segv(pid_t pid) 47 + { 48 + int child_ret; 49 + 50 + waitpid(pid, &child_ret, 0); 51 + FAIL_IF(WIFEXITED(child_ret)); 52 + FAIL_IF(!WIFSIGNALED(child_ret)); 53 + FAIL_IF(WTERMSIG(child_ret) != 11); 54 + 55 + return 0; 56 + } 57 + 58 + int test_sigreturn_kernel(void) 59 + { 60 + struct sigaction act; 61 + int child_ret, i; 62 + pid_t pid; 63 + 64 + act.sa_sigaction = sigusr1_handler; 65 + act.sa_flags = SA_SIGINFO; 66 + sigemptyset(&act.sa_mask); 67 + 68 + FAIL_IF(sigaction(SIGUSR1, &act, NULL)); 69 + 70 + for (i = 0; i < 2; i++) { 71 + // Return to kernel 72 + sigreturn_addr = 0xcull << 60; 73 + pid = fork_child(); 74 + expect_segv(pid); 75 + 76 + // Return to kernel virtual 77 + sigreturn_addr = 0xc008ull << 48; 78 + pid = fork_child(); 79 + expect_segv(pid); 80 + 81 + // Return out of range 82 + sigreturn_addr = 0xc010ull << 48; 83 + pid = fork_child(); 84 + expect_segv(pid); 85 + 86 + // Return to no-man's land, just below PAGE_OFFSET 87 + sigreturn_addr = (0xcull << 60) - (64 * 1024); 88 + pid = fork_child(); 89 + expect_segv(pid); 90 + 91 + // Return to no-man's land, above TASK_SIZE_4PB 92 + sigreturn_addr = 0x1ull << 52; 93 + pid = fork_child(); 94 + expect_segv(pid); 95 + 96 + // Return to 0xd space 97 + sigreturn_addr = 0xdull << 60; 98 + pid = fork_child(); 99 + expect_segv(pid); 100 + 101 + // Return to 0xe space 102 + sigreturn_addr = 0xeull << 60; 103 + pid = fork_child(); 104 + expect_segv(pid); 105 + 106 + // Return to 0xf space 107 + sigreturn_addr = 0xfull << 60; 108 + pid = fork_child(); 109 + expect_segv(pid); 110 + 111 + // Attempt to set PR=0 for 2nd loop (should be blocked by kernel) 112 + sigreturn_msr_mask = ~MSR_PR; 113 + } 114 + 115 + printf("All children killed as expected\n"); 116 + 117 + // Don't change address, just MSR, should return to user as normal 118 + sigreturn_addr = 0; 119 + sigreturn_msr_mask = ~MSR_PR; 120 + pid = fork_child(); 121 + waitpid(pid, &child_ret, 0); 122 + FAIL_IF(!WIFEXITED(child_ret)); 123 + FAIL_IF(WIFSIGNALED(child_ret)); 124 + FAIL_IF(WEXITSTATUS(child_ret) != 0); 125 + 126 + return 0; 127 + } 128 + 129 + int main(void) 130 + { 131 + return test_harness(test_sigreturn_kernel, "sigreturn_kernel"); 132 + }