1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 Jessica Clarke <jrtc27@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/errno.h>
30 #include <sys/procctl.h>
31 #include <sys/queue.h>
32 #include <sys/resource.h>
33 #include <sys/sysctl.h>
34 #include <sys/wait.h>
35
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sysexits.h>
46 #include <termios.h>
47 #include <ttyent.h>
48 #include <unistd.h>
49
50 #include "common.h"
51 #include "child.h"
52
53 /* -1: not started, 0: reaped */
54 static volatile pid_t grandchild_pid = -1;
55 static volatile int grandchild_status;
56
57 static struct pipe_barrier wait_grandchild_barrier;
58 static struct pipe_barrier wait_all_descendants_barrier;
59
60 static void
kill_descendants(int sig)61 kill_descendants(int sig)
62 {
63 struct procctl_reaper_kill rk;
64
65 rk.rk_sig = sig;
66 rk.rk_flags = 0;
67 procctl(P_PID, getpid(), PROC_REAP_KILL, &rk);
68 }
69
70 static void
sigalrm_handler(int sig __unused)71 sigalrm_handler(int sig __unused)
72 {
73 int saved_errno;
74
75 saved_errno = errno;
76 kill_descendants(SIGKILL);
77 errno = saved_errno;
78 }
79
80 static void
wait_all_descendants(void)81 wait_all_descendants(void)
82 {
83 sigset_t set, oset;
84
85 err_set_exit(NULL);
86
87 /*
88 * We may be run in a context where SIGALRM is blocked; temporarily
89 * unblock so we can SIGKILL. Similarly, SIGCHLD may be blocked, but if
90 * we're waiting on the pipe we need to make sure it's not.
91 */
92 sigemptyset(&set);
93 sigaddset(&set, SIGALRM);
94 sigaddset(&set, SIGCHLD);
95 sigprocmask(SIG_UNBLOCK, &set, &oset);
96 alarm(KILL_TIMEOUT);
97 pipe_barrier_wait(&wait_all_descendants_barrier);
98 alarm(0);
99 sigprocmask(SIG_SETMASK, &oset, NULL);
100 }
101
102 static void
sigchld_handler(int sig __unused)103 sigchld_handler(int sig __unused)
104 {
105 int status, saved_errno;
106 pid_t pid;
107
108 saved_errno = errno;
109
110 while ((void)(pid = waitpid(-1, &status, WNOHANG)),
111 pid != -1 && pid != 0) {
112 /* NB: No need to check grandchild_pid due to the pid checks */
113 if (pid == grandchild_pid) {
114 grandchild_status = status;
115 grandchild_pid = 0;
116 pipe_barrier_ready(&wait_grandchild_barrier);
117 }
118 }
119
120 /*
121 * Another process calling kill(..., SIGCHLD) could cause us to get
122 * here before we've spawned the grandchild; only ready when we have no
123 * children if the grandchild has been reaped.
124 */
125 if (pid == -1 && errno == ECHILD && grandchild_pid == 0)
126 pipe_barrier_ready(&wait_all_descendants_barrier);
127
128 errno = saved_errno;
129 }
130
131 static void
exit_signal_handler(int sig)132 exit_signal_handler(int sig)
133 {
134 int saved_errno;
135
136 /*
137 * If we get killed before we've started the grandchild then just exit
138 * with that signal, otherwise kill all our descendants with that
139 * signal and let the main program pick up the grandchild's death.
140 */
141 if (grandchild_pid == -1) {
142 reproduce_signal_death(sig);
143 exit(EXIT_FAILURE);
144 }
145
146 saved_errno = errno;
147 kill_descendants(sig);
148 errno = saved_errno;
149 }
150
151 static void
kill_wait_all_descendants(int sig)152 kill_wait_all_descendants(int sig)
153 {
154 kill_descendants(sig);
155 wait_all_descendants();
156 }
157
158 static void
kill_wait_all_descendants_err_exit(int eval __unused)159 kill_wait_all_descendants_err_exit(int eval __unused)
160 {
161 kill_wait_all_descendants(SIGTERM);
162 }
163
164 static void __dead2
grandchild_run(const char ** argv,const sigset_t * oset)165 grandchild_run(const char **argv, const sigset_t *oset)
166 {
167 sig_t orig;
168
169 /* Restore signals */
170 orig = signal(SIGALRM, SIG_DFL);
171 if (orig == SIG_ERR)
172 err(EX_OSERR, "could not restore SIGALRM");
173 orig = signal(SIGCHLD, SIG_DFL);
174 if (orig == SIG_ERR)
175 err(EX_OSERR, "could not restore SIGCHLD");
176 orig = signal(SIGTERM, SIG_DFL);
177 if (orig == SIG_ERR)
178 err(EX_OSERR, "could not restore SIGTERM");
179 orig = signal(SIGINT, SIG_DFL);
180 if (orig == SIG_ERR)
181 err(EX_OSERR, "could not restore SIGINT");
182 orig = signal(SIGQUIT, SIG_DFL);
183 if (orig == SIG_ERR)
184 err(EX_OSERR, "could not restore SIGQUIT");
185 orig = signal(SIGPIPE, SIG_DFL);
186 if (orig == SIG_ERR)
187 err(EX_OSERR, "could not restore SIGPIPE");
188 orig = signal(SIGTTOU, SIG_DFL);
189 if (orig == SIG_ERR)
190 err(EX_OSERR, "could not restore SIGTTOU");
191
192 /* Now safe to unmask signals */
193 sigprocmask(SIG_SETMASK, oset, NULL);
194
195 /* Only run with stdin/stdout/stderr */
196 closefrom(3);
197
198 /* Ready to execute the requested program */
199 execvp(argv[0], __DECONST(char * const *, argv));
200 err(EX_OSERR, "cannot execvp %s", argv[0]);
201 }
202
203 static int
wait_grandchild_descendants(void)204 wait_grandchild_descendants(void)
205 {
206 pipe_barrier_wait(&wait_grandchild_barrier);
207
208 /*
209 * Once the grandchild itself has exited, kill any lingering
210 * descendants and wait until we've reaped them all.
211 */
212 kill_wait_all_descendants(SIGTERM);
213
214 if (grandchild_pid != 0)
215 errx(EX_SOFTWARE, "failed to reap grandchild");
216
217 return (grandchild_status);
218 }
219
220 void
child_leader_run(const char * name,int fd,bool new_session,const char ** argv,const sigset_t * oset,struct pipe_barrier * start_children_barrier)221 child_leader_run(const char *name, int fd, bool new_session, const char **argv,
222 const sigset_t *oset, struct pipe_barrier *start_children_barrier)
223 {
224 struct pipe_barrier start_grandchild_barrier;
225 pid_t pid, sid, pgid;
226 struct sigaction sa;
227 int error, status;
228 sigset_t set;
229
230 setproctitle("%s [%s]", getprogname(), name);
231
232 error = procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL);
233 if (error != 0)
234 err(EX_OSERR, "could not acquire reaper status");
235
236 /*
237 * Set up our own signal handlers for everything the parent overrides
238 * other than SIGPIPE and SIGTTOU which we leave as ignored, since we
239 * also use pipe-based synchronisation and want to be able to print
240 * errors.
241 */
242 sa.sa_flags = SA_RESTART;
243 sa.sa_handler = sigchld_handler;
244 sigfillset(&sa.sa_mask);
245 error = sigaction(SIGCHLD, &sa, NULL);
246 if (error != 0)
247 err(EX_OSERR, "could not enable SIGCHLD handler");
248 sa.sa_handler = sigalrm_handler;
249 error = sigaction(SIGALRM, &sa, NULL);
250 if (error != 0)
251 err(EX_OSERR, "could not enable SIGALRM handler");
252 sa.sa_handler = exit_signal_handler;
253 error = sigaction(SIGTERM, &sa, NULL);
254 if (error != 0)
255 err(EX_OSERR, "could not enable SIGTERM handler");
256 error = sigaction(SIGINT, &sa, NULL);
257 if (error != 0)
258 err(EX_OSERR, "could not enable SIGINT handler");
259 error = sigaction(SIGQUIT, &sa, NULL);
260 if (error != 0)
261 err(EX_OSERR, "could not enable SIGQUIT handler");
262
263 /*
264 * Now safe to unmask signals. Note that creating the barriers used by
265 * the SIGCHLD handler with signals unmasked is safe since they won't
266 * be used if the grandchild hasn't been forked (and reaped), which
267 * comes later.
268 */
269 sigprocmask(SIG_SETMASK, oset, NULL);
270
271 error = pipe_barrier_init(&start_grandchild_barrier);
272 if (error != 0)
273 err(EX_OSERR, "could not create start grandchild barrier");
274
275 error = pipe_barrier_init(&wait_grandchild_barrier);
276 if (error != 0)
277 err(EX_OSERR, "could not create wait grandchild barrier");
278
279 error = pipe_barrier_init(&wait_all_descendants_barrier);
280 if (error != 0)
281 err(EX_OSERR, "could not create wait all descendants barrier");
282
283 /*
284 * Create a new session if this is on a different terminal to
285 * the current one, otherwise just create a new process group to keep
286 * things as similar as possible between the two cases.
287 */
288 if (new_session) {
289 sid = setsid();
290 pgid = sid;
291 if (sid == -1)
292 err(EX_OSERR, "could not create session");
293 } else {
294 sid = -1;
295 pgid = getpid();
296 error = setpgid(0, pgid);
297 if (error == -1)
298 err(EX_OSERR, "could not create process group");
299 }
300
301 /* Wait until parent is ready for us to start */
302 pipe_barrier_destroy_ready(start_children_barrier);
303 pipe_barrier_wait(start_children_barrier);
304
305 /*
306 * Use the console for stdin/stdout/stderr.
307 *
308 * NB: dup2(2) is a no-op if the two fds are equal, and the call to
309 * closefrom(2) later in the grandchild will close the fd if it isn't
310 * one of stdin/stdout/stderr already. This means we do not need to
311 * handle that special case differently.
312 */
313 error = dup2(fd, STDIN_FILENO);
314 if (error == -1)
315 err(EX_IOERR, "could not dup %s to stdin", name);
316 error = dup2(fd, STDOUT_FILENO);
317 if (error == -1)
318 err(EX_IOERR, "could not dup %s to stdout", name);
319 error = dup2(fd, STDERR_FILENO);
320 if (error == -1)
321 err(EX_IOERR, "could not dup %s to stderr", name);
322
323 /*
324 * If we created a new session, make the console our controlling
325 * terminal. Either way, also make this the foreground process group.
326 */
327 if (new_session) {
328 error = tcsetsid(STDIN_FILENO, sid);
329 if (error != 0)
330 err(EX_IOERR, "could not set session for %s", name);
331 } else {
332 error = tcsetpgrp(STDIN_FILENO, pgid);
333 if (error != 0)
334 err(EX_IOERR, "could not set process group for %s",
335 name);
336 }
337
338 /*
339 * Temporarily block signals again; forking, setting grandchild_pid and
340 * calling err_set_exit need to all be atomic for similar reasons as
341 * the parent when forking us.
342 */
343 sigfillset(&set);
344 sigprocmask(SIG_BLOCK, &set, NULL);
345 pid = fork();
346 if (pid == -1)
347 err(EX_OSERR, "could not fork");
348
349 if (pid == 0) {
350 /*
351 * We need to destroy the ready ends so we don't block these
352 * child leader-only self-pipes, and might as well destroy the
353 * wait ends too given we're not going to use them.
354 */
355 pipe_barrier_destroy(&wait_grandchild_barrier);
356 pipe_barrier_destroy(&wait_all_descendants_barrier);
357
358 /* Wait until the parent has put us in a new process group */
359 pipe_barrier_destroy_ready(&start_grandchild_barrier);
360 pipe_barrier_wait(&start_grandchild_barrier);
361 grandchild_run(argv, oset);
362 }
363
364 grandchild_pid = pid;
365
366 /*
367 * Now the grandchild exists make sure to clean it up, and any of its
368 * descendants, on exit.
369 */
370 err_set_exit(kill_wait_all_descendants_err_exit);
371
372 sigprocmask(SIG_SETMASK, oset, NULL);
373
374 /* Start the grandchild and wait for it and its descendants to exit */
375 pipe_barrier_ready(&start_grandchild_barrier);
376
377 status = wait_grandchild_descendants();
378
379 if (WIFSIGNALED(status))
380 reproduce_signal_death(WTERMSIG(status));
381
382 if (WIFEXITED(status))
383 exit(WEXITSTATUS(status));
384
385 exit(EXIT_FAILURE);
386 }
387