File Index
Files and directories
Sign in
FILE

sigreturn_kernel.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/powerpc/signal/sigreturn_kernel.c 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
 19static volatile unsigned long long sigreturn_addr;
 20static volatile unsigned long long sigreturn_msr_mask;
 21
 22static 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
 33static 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
 46static 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
 58int 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
129int main(void)
130{
131	return test_harness(test_sigreturn_kernel, "sigreturn_kernel");
132}
~/ Read-only file preview.