1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2024 ARM Ltd.
7 * Test describing a clear distinction between signal states - delivered and
8 * blocked, and their relation with ucontext.
10 * A process can request blocking of a signal by masking it into its set of
11 * blocked signals; such a signal, when sent to the process by the kernel,
12 * will get blocked by the process and it may later unblock it and take an
13 * action. At that point, the signal will be delivered.
15 * We test the following functionalities of the kernel:
17 * ucontext_t describes the interrupted context of the thread; this implies
18 * that, in case of registering a handler and catching the corresponding
19 * signal, that state is before what was jumping into the handler.
21 * The thread's mask of blocked signals can be permanently changed, i.e, not
22 * just during the execution of the handler, by mangling with uc_sigmask
23 * from inside the handler.
25 * Assume that we block the set of signals, S1, by sigaction(), and say, the
26 * signal for which the handler was installed, is S2. When S2 is sent to the
27 * program, it will be considered "delivered", since we will act on the
28 * signal and jump to the handler. Any instances of S1 or S2 raised, while the
29 * program is executing inside the handler, will be blocked; they will be
30 * delivered immediately upon termination of the handler.
32 * For standard signals (also see real-time signals in the man page), multiple
33 * blocked instances of the same signal are not queued; such a signal will
34 * be delivered just once.
42 #include "../kselftest.h"
44 void handler_verify_ucontext(int signo, siginfo_t *info, void *uc)
48 /* Kernel dumps ucontext with USR2 blocked */
49 ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR2);
50 ksft_test_result(ret == 1, "USR2 blocked in ucontext\n");
53 * USR2 is blocked; can be delivered neither here, nor after
57 ksft_exit_fail_perror("raise");
60 void handler_segv(int signo, siginfo_t *info, void *uc)
63 * Three cases possible:
64 * 1. Program already terminated due to segmentation fault.
65 * 2. SEGV was blocked even after returning from handler_usr.
66 * 3. SEGV was delivered on returning from handler_usr.
67 * The last option must happen.
69 ksft_test_result_pass("SEGV delivered\n");
74 void handler_usr(int signo, siginfo_t *info, void *uc)
79 * Break out of infinite recursion caused by raise(SIGUSR1) invoked
80 * from inside the handler
86 /* SEGV blocked during handler execution, delivered on return */
88 ksft_exit_fail_perror("raise");
90 ksft_print_msg("SEGV bypassed successfully\n");
93 * Signal responsible for handler invocation is blocked by default;
94 * delivered on return, leading to recursion
97 ksft_exit_fail_perror("raise");
99 ksft_test_result(cnt == 1,
100 "USR1 is blocked, cannot invoke handler right now\n");
102 /* Raise USR1 again; only one instance must be delivered upon exit */
104 ksft_exit_fail_perror("raise");
106 /* SEGV has been blocked in sa_mask, but ucontext is empty */
107 ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGSEGV);
108 ksft_test_result(ret == 0, "SEGV not blocked in ucontext\n");
110 /* USR1 has been blocked, but ucontext is empty */
111 ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR1);
112 ksft_test_result(ret == 0, "USR1 not blocked in ucontext\n");
115 * Mangle ucontext; this will be copied back into ¤t->blocked
116 * on return from the handler.
118 if (sigaddset(&((ucontext_t *)uc)->uc_sigmask, SIGUSR2))
119 ksft_exit_fail_perror("sigaddset");
122 int main(int argc, char *argv[])
124 struct sigaction act, act2;
125 sigset_t set, oldset;
130 act.sa_flags = SA_SIGINFO;
131 act.sa_sigaction = &handler_usr;
133 /* Add SEGV to blocked mask */
134 if (sigemptyset(&act.sa_mask) || sigaddset(&act.sa_mask, SIGSEGV)
135 || (sigismember(&act.sa_mask, SIGSEGV) != 1))
136 ksft_exit_fail_msg("Cannot add SEGV to blocked mask\n");
138 if (sigaction(SIGUSR1, &act, NULL))
139 ksft_exit_fail_perror("Cannot install handler");
141 act2.sa_flags = SA_SIGINFO;
142 act2.sa_sigaction = &handler_segv;
144 if (sigaction(SIGSEGV, &act2, NULL))
145 ksft_exit_fail_perror("Cannot install handler");
149 ksft_exit_fail_perror("raise");
151 /* USR1 must not be queued */
152 ksft_test_result(cnt == 2, "handler invoked only twice\n");
154 /* Mangled ucontext implies USR2 is blocked for current thread */
156 ksft_exit_fail_perror("raise");
158 ksft_print_msg("USR2 bypassed successfully\n");
160 act.sa_sigaction = &handler_verify_ucontext;
161 if (sigaction(SIGUSR1, &act, NULL))
162 ksft_exit_fail_perror("Cannot install handler");
165 ksft_exit_fail_perror("raise");
168 * Raising USR2 in handler_verify_ucontext is redundant since it
171 ksft_print_msg("USR2 still blocked on return from handler\n");
173 /* Confirm USR2 blockage by sigprocmask() too */
174 if (sigemptyset(&set))
175 ksft_exit_fail_perror("sigemptyset");
177 if (sigprocmask(SIG_BLOCK, &set, &oldset))
178 ksft_exit_fail_perror("sigprocmask");
180 ksft_test_result(sigismember(&oldset, SIGUSR2) == 1,
181 "USR2 present in ¤t->blocked\n");