8static volatile sig_atomic_t child_notice = -1;
10static void child_changed(
int signal, siginfo_t* info,
void* context) {
15 .code = info->si_code,
18 .result = info->si_status};
19 if (child_notice >= 0) {
26static int parent_notification(
void) {
27 int failed = 0, installed = 0, mask_saved = 0;
28 int report[2] = {-1, -1};
29 struct tc_child child = TC_CHILD_INIT;
31 struct sigaction action = {.sa_sigaction = child_changed, .sa_flags = SA_SIGINFO | SA_RESTART};
33 sigset_t mask, previous;
34 sigemptyset(&action.sa_mask);
36 sigaddset(&mask, SIGCHLD);
37 CHECK(pipe2(report, O_CLOEXEC | O_NONBLOCK) == 0);
38 child_notice = report[1];
39 CHECK(sigaction(SIGCHLD, &action, &old) == 0);
41 CHECK(sigprocmask(SIG_UNBLOCK, &mask, &previous) == 0);
43 CHECK(tc_spawn(&child, 1) == 0 && tc_stop(&child, SIGUSR1) == 0);
44 CHECK(tc_receive(report[0],
'C', &
message) == 0);
47 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0 && tc_receive(child.report,
'A', NULL) == 0);
48 CHECK(tc_finish(&child) == 0);
52 if (installed && sigaction(SIGCHLD, &old, NULL))
54 if (mask_saved && sigprocmask(SIG_SETMASK, &previous, NULL))
63static int configure(
struct tc_child* child,
int operation,
int signal) {
65 if (tc_send(child, operation, signal) || tc_receive(child->report, operation, &
message))
70static int handler(
struct tc_child* child,
int signal,
int code, pid_t pid) {
72 if (tc_receive(child->report,
'H', &
message))
77 fprintf(stderr,
"handler actual=%d/%d/%d/%u expected=%d/%d/%d/%u\n",
message.signal,
message.code,
82static int decisions(
void) {
83 int failed = 0, status;
84 struct tc_child child = TC_CHILD_INIT;
86 struct user_regs_struct registers;
87 CHECK(tc_spawn(&child, 1) == 0);
88 CHECK(tc_stop(&child, SIGUSR1) == 0);
89 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0);
90 CHECK(tc_receive(child.report,
'A', NULL) == 0);
92 CHECK(tc_stop(&child, SIGUSR1) == 0);
93 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
94 CHECK(tc_signal_info(&info, SIGUSR1, SI_TKILL, child.pid, getuid()) == 0);
95 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGUSR1) == 0);
96 CHECK(handler(&child, SIGUSR1, SI_TKILL, child.pid) == 0);
97 CHECK(tc_receive(child.report,
'A', NULL) == 0);
99 CHECK(tc_stop(&child, SIGUSR1) == 0);
100 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGUSR2) == 0);
101 CHECK(handler(&child, SIGUSR2, SI_USER, getpid()) == 0);
102 CHECK(tc_receive(child.report,
'A', NULL) == 0);
104 CHECK(configure(&child,
'B', SIGUSR2) == 0 && tc_stop(&child, SIGUSR1) == 0);
105 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGUSR2) == 0);
106 CHECK(tc_receive(child.report,
'A', NULL) == 0);
107 CHECK(tc_send(&child,
'U', SIGUSR2) == 0);
108 CHECK(tc_wait_stop(&child, SIGUSR2) == 0);
109 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
110 CHECK(tc_signal_info(&info, SIGUSR2, SI_USER, getpid(), getuid()) == 0);
111 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGUSR2) == 0);
112 CHECK(handler(&child, SIGUSR2, SI_USER, getpid()) == 0);
113 CHECK(tc_receive(child.report,
'U', NULL) == 0);
115 CHECK(configure(&child,
'I', SIGUSR2) == 0 && tc_stop(&child, SIGUSR2) == 0);
116 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGUSR2) == 0);
117 CHECK(tc_receive(child.report,
'A', NULL) == 0);
118 CHECK(configure(&child,
'F', SIGCHLD) == 0 && tc_stop(&child, SIGCHLD) == 0);
119 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
120 CHECK(tc_signal_info(&info, SIGCHLD, SI_TKILL, child.pid, getuid()) == 0);
121 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGCHLD) == 0);
122 CHECK(tc_receive(child.report,
'A', NULL) == 0);
124 CHECK(tc_stop(&child, SIGUSR1) == 0 && tc_resume(child.pid, PTRACE_DETACH, 0) == 0);
125 CHECK(tc_receive(child.report,
'A', NULL) == 0);
127 CHECK(ptrace(PTRACE_GETREGS, child.pid, (
void*)0, (
void*)®isters) == -1 && errno == ESRCH);
128 CHECK(tc_send(&child,
'S', SIGUSR1) == 0);
129 CHECK(handler(&child, SIGUSR1, SI_TKILL, child.pid) == 0);
130 CHECK(tc_receive(child.report,
'A', NULL) == 0);
131 CHECK(wait4(child.pid, &status, WNOHANG, NULL) == 0);
132 CHECK(tc_finish(&child) == 0);
138static int default_fatal(
void) {
139 int failed = 0, status;
140 struct tc_child child = TC_CHILD_INIT;
142 CHECK(tc_spawn(&child, 1) == 0 && tc_stop(&child, SIGTERM) == 0);
143 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
144 CHECK(tc_signal_info(&info, SIGTERM, SI_TKILL, child.pid, getuid()) == 0);
145 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGTERM) == 0);
146 CHECK(tc_wait(child.pid, &status, 10000) == 0);
147 if (WIFEXITED(status) || WIFSIGNALED(status))
149 CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
155static int group_stop(
void) {
157 struct tc_child child = TC_CHILD_INIT;
158 siginfo_t info, untouched;
159 struct user_regs_struct first, second;
160 CHECK(tc_spawn(&child, 1) == 0 && tc_stop(&child, SIGSTOP) == 0);
161 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
162 CHECK(tc_signal_info(&info, SIGSTOP, SI_TKILL, child.pid, getuid()) == 0);
163 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGSTOP) == 0);
164 CHECK(tc_wait_stop(&child, SIGSTOP) == 0);
165 memset(&info, 0xa5,
sizeof(info));
168 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == -1 && errno == EINVAL);
169 CHECK(memcmp(&info, &untouched,
sizeof(info)) == 0);
170 CHECK(ptrace(PTRACE_GETREGS, child.pid, (
void*)0, (
void*)&first) == 0);
171 CHECK(kill(child.pid, SIGCONT) == 0);
172 CHECK(ptrace(PTRACE_GETREGS, child.pid, (
void*)0, (
void*)&second) == 0);
173 CHECK(memcmp(&first, &second,
sizeof(first)) == 0);
175 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == -1 && errno == EINVAL);
176 for (
unsigned i = 0; i < 2; ++i) {
177 CHECK(waitid(P_PID, child.pid, &info, WCONTINUED | WNOWAIT) == 0);
178 CHECK(info.si_pid == child.pid && info.si_code == CLD_CONTINUED && info.si_status == SIGCONT);
180 CHECK(waitid(P_PID, child.pid, &info, WCONTINUED) == 0 && info.si_pid == child.pid);
181 CHECK(waitid(P_PID, child.pid, &info, WCONTINUED | WNOHANG) == 0 && !info.si_pid);
182 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0);
183 CHECK(tc_wait_stop(&child, SIGCONT) == 0);
184 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == 0);
185 CHECK(tc_signal_info(&info, SIGCONT, SI_USER, getpid(), getuid()) == 0);
186 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0 && tc_receive(child.report,
'A', NULL) == 0);
187 CHECK(tc_finish(&child) == 0);
193static int group_cont_alone(
void) {
195 struct tc_child child = TC_CHILD_INIT;
197 CHECK(tc_spawn(&child, 1) == 0 && tc_stop(&child, SIGSTOP) == 0);
198 CHECK(tc_resume(child.pid, PTRACE_CONT, SIGSTOP) == 0 && tc_wait_stop(&child, SIGSTOP) == 0);
200 CHECK(ptrace(PTRACE_GETSIGINFO, child.pid, (
void*)0, (
void*)&info) == -1 && errno == EINVAL);
202 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0 && tc_receive(child.report,
'A', NULL) == 0);
203 CHECK(tc_finish(&child) == 0);
209int tc_signals(
void) {
210 return parent_notification() || decisions() || default_fatal() || group_stop() ||