t_ptrace_sigchld.c revision 1.2.2.2 1 1.2.2.2 martin /* $NetBSD: t_ptrace_sigchld.c,v 1.2.2.2 2020/04/08 14:09:09 martin Exp $ */
2 1.2.2.2 martin
3 1.2.2.2 martin /*-
4 1.2.2.2 martin * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 1.2.2.2 martin * All rights reserved.
6 1.2.2.2 martin *
7 1.2.2.2 martin * Redistribution and use in source and binary forms, with or without
8 1.2.2.2 martin * modification, are permitted provided that the following conditions
9 1.2.2.2 martin * are met:
10 1.2.2.2 martin * 1. Redistributions of source code must retain the above copyright
11 1.2.2.2 martin * notice, this list of conditions and the following disclaimer.
12 1.2.2.2 martin * 2. Redistributions in binary form must reproduce the above copyright
13 1.2.2.2 martin * notice, this list of conditions and the following disclaimer in the
14 1.2.2.2 martin * documentation and/or other materials provided with the distribution.
15 1.2.2.2 martin *
16 1.2.2.2 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.2.2.2 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.2.2.2 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.2.2.2 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.2.2.2 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.2.2.2 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.2.2.2 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.2.2.2 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.2.2.2 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.2.2.2 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.2.2.2 martin * POSSIBILITY OF SUCH DAMAGE.
27 1.2.2.2 martin */
28 1.2.2.2 martin
29 1.2.2.2 martin #include <sys/cdefs.h>
30 1.2.2.2 martin __RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.2.2.2 2020/04/08 14:09:09 martin Exp $");
31 1.2.2.2 martin
32 1.2.2.2 martin #include <sys/param.h>
33 1.2.2.2 martin #include <sys/types.h>
34 1.2.2.2 martin #include <sys/exec_elf.h>
35 1.2.2.2 martin #include <sys/mman.h>
36 1.2.2.2 martin #include <sys/ptrace.h>
37 1.2.2.2 martin #include <sys/resource.h>
38 1.2.2.2 martin #include <sys/stat.h>
39 1.2.2.2 martin #include <sys/syscall.h>
40 1.2.2.2 martin #include <sys/sysctl.h>
41 1.2.2.2 martin #include <sys/uio.h>
42 1.2.2.2 martin #include <sys/wait.h>
43 1.2.2.2 martin #include <machine/reg.h>
44 1.2.2.2 martin #include <assert.h>
45 1.2.2.2 martin #include <elf.h>
46 1.2.2.2 martin #include <err.h>
47 1.2.2.2 martin #include <errno.h>
48 1.2.2.2 martin #include <fcntl.h>
49 1.2.2.2 martin #include <lwp.h>
50 1.2.2.2 martin #include <pthread.h>
51 1.2.2.2 martin #include <sched.h>
52 1.2.2.2 martin #include <signal.h>
53 1.2.2.2 martin #include <spawn.h>
54 1.2.2.2 martin #include <stdint.h>
55 1.2.2.2 martin #include <stdio.h>
56 1.2.2.2 martin #include <stdlib.h>
57 1.2.2.2 martin #include <strings.h>
58 1.2.2.2 martin #include <time.h>
59 1.2.2.2 martin #include <unistd.h>
60 1.2.2.2 martin
61 1.2.2.2 martin #include <atf-c.h>
62 1.2.2.2 martin
63 1.2.2.2 martin #include "h_macros.h"
64 1.2.2.2 martin #include "msg.h"
65 1.2.2.2 martin
66 1.2.2.2 martin #include "t_ptrace_wait.h"
67 1.2.2.2 martin
68 1.2.2.2 martin #define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
69 1.2.2.2 martin strerror(errno))
70 1.2.2.2 martin #define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
71 1.2.2.2 martin "%d(%s) != %d", res, strerror(res), exp)
72 1.2.2.2 martin
73 1.2.2.2 martin static int debug = 0;
74 1.2.2.2 martin
75 1.2.2.2 martin #define DPRINTF(a, ...) do \
76 1.2.2.2 martin if (debug) \
77 1.2.2.2 martin printf("%s() %d.%d %s:%d " a, \
78 1.2.2.2 martin __func__, getpid(), _lwp_self(), __FILE__, __LINE__, ##__VA_ARGS__); \
79 1.2.2.2 martin while (/*CONSTCOND*/0)
80 1.2.2.2 martin
81 1.2.2.2 martin /// ----------------------------------------------------------------------------
82 1.2.2.2 martin
83 1.2.2.2 martin static int expected_signo;
84 1.2.2.2 martin static int expected_code;
85 1.2.2.2 martin static int expected_status;
86 1.2.2.2 martin static pid_t expected_pid;
87 1.2.2.2 martin
88 1.2.2.2 martin static void
89 1.2.2.2 martin sigchld_action(int sig, siginfo_t *info, void *ctx)
90 1.2.2.2 martin {
91 1.2.2.2 martin
92 1.2.2.2 martin FORKEE_ASSERT_EQ(info->si_signo, expected_signo);
93 1.2.2.2 martin FORKEE_ASSERT_EQ(info->si_code, expected_code);
94 1.2.2.2 martin FORKEE_ASSERT_EQ(info->si_uid, getuid());
95 1.2.2.2 martin FORKEE_ASSERT_EQ(info->si_pid, expected_pid);
96 1.2.2.2 martin
97 1.2.2.2 martin if (WIFEXITED(info->si_status))
98 1.2.2.2 martin ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), expected_status);
99 1.2.2.2 martin else if (WIFSTOPPED(info->si_status))
100 1.2.2.2 martin ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), expected_status);
101 1.2.2.2 martin else if (WIFSIGNALED(info->si_status))
102 1.2.2.2 martin ATF_REQUIRE_EQ(WTERMSIG(info->si_status), expected_status);
103 1.2.2.2 martin /*
104 1.2.2.2 martin else if (WIFCONTINUED(info->si_status))
105 1.2.2.2 martin ;
106 1.2.2.2 martin */
107 1.2.2.2 martin }
108 1.2.2.2 martin
109 1.2.2.2 martin static void
110 1.2.2.2 martin traceme_raise(int sigval)
111 1.2.2.2 martin {
112 1.2.2.2 martin const int exitval = 5;
113 1.2.2.2 martin struct sigaction sa;
114 1.2.2.2 martin pid_t child;
115 1.2.2.2 martin struct msg_fds parent_child;
116 1.2.2.2 martin uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
117 1.2.2.2 martin
118 1.2.2.2 martin struct ptrace_siginfo info;
119 1.2.2.2 martin memset(&info, 0, sizeof(info));
120 1.2.2.2 martin
121 1.2.2.2 martin memset(&sa, 0, sizeof(sa));
122 1.2.2.2 martin sa.sa_sigaction = sigchld_action;
123 1.2.2.2 martin sa.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
124 1.2.2.2 martin sigemptyset(&sa.sa_mask);
125 1.2.2.2 martin
126 1.2.2.2 martin atf_tc_fail("XXX: zombie is not collected before tracer's death");
127 1.2.2.2 martin
128 1.2.2.2 martin SYSCALL_REQUIRE(sigaction(SIGCHLD, &sa, NULL) == 0);
129 1.2.2.2 martin
130 1.2.2.2 martin SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
131 1.2.2.2 martin
132 1.2.2.2 martin DPRINTF("Before forking process PID=%d\n", getpid());
133 1.2.2.2 martin SYSCALL_REQUIRE((child = fork()) != -1);
134 1.2.2.2 martin if (child == 0) {
135 1.2.2.2 martin DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
136 1.2.2.2 martin FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
137 1.2.2.2 martin
138 1.2.2.2 martin CHILD_FROM_PARENT("raise1 child", parent_child, msg);
139 1.2.2.2 martin
140 1.2.2.2 martin raise(sigval);
141 1.2.2.2 martin
142 1.2.2.2 martin CHILD_TO_PARENT("raise2 child", parent_child, msg);
143 1.2.2.2 martin
144 1.2.2.2 martin switch (sigval) {
145 1.2.2.2 martin case SIGKILL:
146 1.2.2.2 martin /* NOTREACHED */
147 1.2.2.2 martin FORKEE_ASSERTX(0 && "This shall not be reached");
148 1.2.2.2 martin __unreachable();
149 1.2.2.2 martin default:
150 1.2.2.2 martin DPRINTF("Before exiting of the child process\n");
151 1.2.2.2 martin _exit(exitval);
152 1.2.2.2 martin }
153 1.2.2.2 martin }
154 1.2.2.2 martin DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
155 1.2.2.2 martin
156 1.2.2.2 martin expected_signo = SIGCHLD;
157 1.2.2.2 martin expected_pid = child;
158 1.2.2.2 martin switch (sigval) {
159 1.2.2.2 martin case SIGKILL:
160 1.2.2.2 martin expected_code = CLD_KILLED;
161 1.2.2.2 martin expected_status = SIGKILL;
162 1.2.2.2 martin break;
163 1.2.2.2 martin case SIGSTOP:
164 1.2.2.2 martin expected_code = CLD_STOPPED;
165 1.2.2.2 martin expected_status = SIGSTOP;
166 1.2.2.2 martin break;
167 1.2.2.2 martin default:
168 1.2.2.2 martin break;
169 1.2.2.2 martin }
170 1.2.2.2 martin
171 1.2.2.2 martin PARENT_TO_CHILD("raise1 child", parent_child, msg);
172 1.2.2.2 martin
173 1.2.2.2 martin switch (sigval) {
174 1.2.2.2 martin case SIGKILL:
175 1.2.2.2 martin break;
176 1.2.2.2 martin default:
177 1.2.2.2 martin PARENT_FROM_CHILD("raise2 child", parent_child, msg);
178 1.2.2.2 martin
179 1.2.2.2 martin DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
180 1.2.2.2 martin "child\n");
181 1.2.2.2 martin SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
182 1.2.2.2 martin sizeof(info)) != -1);
183 1.2.2.2 martin
184 1.2.2.2 martin DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
185 1.2.2.2 martin DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
186 1.2.2.2 martin "si_errno=%#x\n",
187 1.2.2.2 martin info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
188 1.2.2.2 martin info.psi_siginfo.si_errno);
189 1.2.2.2 martin
190 1.2.2.2 martin ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
191 1.2.2.2 martin ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
192 1.2.2.2 martin
193 1.2.2.2 martin expected_code = CLD_EXITED;
194 1.2.2.2 martin expected_status = exitval;
195 1.2.2.2 martin
196 1.2.2.2 martin SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0));
197 1.2.2.2 martin
198 1.2.2.2 martin break;
199 1.2.2.2 martin }
200 1.2.2.2 martin
201 1.2.2.2 martin await_collected(child); /* XXX: Process is never collected */
202 1.2.2.2 martin }
203 1.2.2.2 martin
204 1.2.2.2 martin #define TRACEME_RAISE(test, sig) \
205 1.2.2.2 martin ATF_TC(test); \
206 1.2.2.2 martin ATF_TC_HEAD(test, tc) \
207 1.2.2.2 martin { \
208 1.2.2.2 martin atf_tc_set_md_var(tc, "descr", \
209 1.2.2.2 martin "Verify " #sig " followed by _exit(2) in a child"); \
210 1.2.2.2 martin atf_tc_set_md_var(tc, "timeout", "10"); \
211 1.2.2.2 martin } \
212 1.2.2.2 martin \
213 1.2.2.2 martin ATF_TC_BODY(test, tc) \
214 1.2.2.2 martin { \
215 1.2.2.2 martin \
216 1.2.2.2 martin traceme_raise(sig); \
217 1.2.2.2 martin }
218 1.2.2.2 martin
219 1.2.2.2 martin TRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
220 1.2.2.2 martin #if notyet
221 1.2.2.2 martin TRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
222 1.2.2.2 martin TRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
223 1.2.2.2 martin TRACEME_RAISE(traceme_raise4, SIGHUP) /* hangup */
224 1.2.2.2 martin TRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
225 1.2.2.2 martin TRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
226 1.2.2.2 martin TRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
227 1.2.2.2 martin TRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
228 1.2.2.2 martin TRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
229 1.2.2.2 martin TRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
230 1.2.2.2 martin #endif
231 1.2.2.2 martin
232 1.2.2.2 martin ATF_TP_ADD_TCS(tp)
233 1.2.2.2 martin {
234 1.2.2.2 martin setvbuf(stdout, NULL, _IONBF, 0);
235 1.2.2.2 martin setvbuf(stderr, NULL, _IONBF, 0);
236 1.2.2.2 martin
237 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise1);
238 1.2.2.2 martin #if notyet
239 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise2);
240 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise3);
241 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise4);
242 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise5);
243 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise6);
244 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise7);
245 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise8);
246 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise9);
247 1.2.2.2 martin ATF_TP_ADD_TC(tp, traceme_raise10);
248 1.2.2.2 martin #endif
249 1.2.2.2 martin
250 1.2.2.2 martin return atf_no_error();
251 1.2.2.2 martin }
252