1 /*        $NetBSD: master_spawn.c,v 1.3 2020/03/18 19:05:16 christos Exp $      */
2 
3 /*++
4 /* NAME
5 /*        master_spawn 3
6 /* SUMMARY
7 /*        Postfix master - child process birth and death
8 /* SYNOPSIS
9 /*        #include "master.h"
10 /*
11 /*        void      master_spawn(serv)
12 /*        MASTER_SERV *serv;
13 /*
14 /*        void      master_reap_child()
15 /*
16 /*        void      master_delete_children(serv)
17 /*        MASTER_SERV *serv;
18 /* DESCRIPTION
19 /*        This module creates and cleans up child processes, and applies
20 /*        a process creation throttle in case of serious trouble.
21 /*        This module is the working horse for the master_avail(3) process
22 /*        creation policy module.
23 /*
24 /*        master_spawn() spawns off a child process for the specified service,
25 /*        making the child process available for servicing connection requests.
26 /*        It is an error to call this function then the specified service is
27 /*        throttled.
28 /*
29 /*        master_reap_child() cleans up all dead child processes.  One typically
30 /*        runs this function at a convenient moment after receiving a SIGCHLD
31 /*        signal. When a child process terminates abnormally after being used
32 /*        for the first time, process creation for that service is throttled
33 /*        for a configurable amount of time.
34 /*
35 /*        master_delete_children() deletes all child processes that provide
36 /*        the named service. Upon exit, the process creation throttle for that
37 /*        service is released.
38 /* DIAGNOSTICS
39 /*        Panic: interface violations, internal inconsistencies.
40 /*        Fatal errors: out of memory.  Warnings: throttle on/off.
41 /* BUGS
42 /* SEE ALSO
43 /*        master_avail(3), process creation policy.
44 /* LICENSE
45 /* .ad
46 /* .fi
47 /*        The Secure Mailer license must be distributed with this software.
48 /* AUTHOR(S)
49 /*        Wietse Venema
50 /*        IBM T.J. Watson Research
51 /*        P.O. Box 704
52 /*        Yorktown Heights, NY 10598, USA
53 /*--*/
54 
55 /* System libraries. */
56 
57 #include <sys_defs.h>
58 #include <sys/wait.h>
59 #include <stdlib.h>
60 #include <unistd.h>
61 #include <syslog.h>                     /* closelog() */
62 #include <signal.h>
63 #include <stdarg.h>
64 #include <syslog.h>
65 
66 /* Utility libraries. */
67 
68 #include <msg.h>
69 #include <binhash.h>
70 #include <mymalloc.h>
71 #include <events.h>
72 #include <vstring.h>
73 #include <argv.h>
74 
75 /* Global library. */
76 
77 #include <mail_conf.h>
78 
79 /* Application-specific. */
80 
81 #include "master_proto.h"
82 #include "master.h"
83 
84 BINHASH *master_child_table;
85 static void master_unthrottle(MASTER_SERV *serv);
86 
87 /* master_unthrottle_wrapper - in case (char *) != (struct *) */
88 
master_unthrottle_wrapper(int unused_event,void * ptr)89 static void master_unthrottle_wrapper(int unused_event, void *ptr)
90 {
91     MASTER_SERV *serv = (MASTER_SERV *) ptr;
92 
93     /*
94      * This routine runs after expiry of the timer set in master_throttle(),
95      * which gets called when it appears that the world is falling apart.
96      */
97     master_unthrottle(serv);
98 }
99 
100 /* master_unthrottle - enable process creation */
101 
master_unthrottle(MASTER_SERV * serv)102 static void master_unthrottle(MASTER_SERV *serv)
103 {
104 
105     /*
106      * Enable process creation within this class. Disable the "unthrottle"
107      * timer just in case we're being called directly from the cleanup
108      * routine, instead of from the event manager.
109      */
110     if ((serv->flags & MASTER_FLAG_THROTTLE) != 0) {
111           serv->flags &= ~MASTER_FLAG_THROTTLE;
112           event_cancel_timer(master_unthrottle_wrapper, (void *) serv);
113           if (msg_verbose)
114               msg_info("throttle released for command %s", serv->path);
115           master_avail_listen(serv);
116     }
117 }
118 
119 /* master_throttle - suspend process creation */
120 
master_throttle(MASTER_SERV * serv)121 static void master_throttle(MASTER_SERV *serv)
122 {
123 
124     /*
125      * Perhaps the command to be run is defective, perhaps some configuration
126      * is wrong, or perhaps the system is out of resources. Disable further
127      * process creation attempts for a while.
128      */
129     if ((serv->flags & MASTER_FLAG_THROTTLE) == 0) {
130           serv->flags |= MASTER_FLAG_THROTTLE;
131           event_request_timer(master_unthrottle_wrapper, (void *) serv,
132                                   serv->throttle_delay);
133           if (msg_verbose)
134               msg_info("throttling command %s", serv->path);
135           master_avail_listen(serv);
136     }
137 }
138 
139 /* master_spawn - spawn off new child process if we can */
140 
master_spawn(MASTER_SERV * serv)141 void    master_spawn(MASTER_SERV *serv)
142 {
143     const char *myname = "master_spawn";
144     MASTER_PROC *proc;
145     MASTER_PID pid;
146     int     n;
147     static unsigned master_generation = 0;
148     static VSTRING *env_gen = 0;
149 
150     if (master_child_table == 0)
151           master_child_table = binhash_create(0);
152     if (env_gen == 0)
153           env_gen = vstring_alloc(100);
154 
155     /*
156      * Sanity checks. The master_avail module is supposed to know what it is
157      * doing.
158      */
159     if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc))
160           msg_panic("%s: at process limit %d", myname, serv->total_proc);
161     if (serv->avail_proc > 0)
162           msg_panic("%s: processes available: %d", myname, serv->avail_proc);
163     if (serv->flags & MASTER_FLAG_THROTTLE)
164           msg_panic("%s: throttled service: %s", myname, serv->path);
165 
166     /*
167      * Create a child process and connect parent and child via the status
168      * pipe.
169      */
170     master_generation += 1;
171     switch (pid = fork()) {
172 
173           /*
174            * Error. We're out of some essential resource. Best recourse is to
175            * try again later.
176            */
177     case -1:
178           msg_warn("%s: fork: %m -- throttling", myname);
179           master_throttle(serv);
180           return;
181 
182           /*
183            * Child process. Redirect child stdin/stdout to the parent-child
184            * connection and run the requested command. Leave child stderr
185            * alone. Disable exit handlers: they should be executed by the
186            * parent only.
187            *
188            * When we reach the process limit on a public internet service, we
189            * create stress-mode processes until the process count stays below
190            * the limit for some amount of time. See master_avail_listen().
191            */
192     case 0:
193           msg_cleanup((void (*) (void)) 0);       /* disable exit handler */
194           closelog();                                       /* avoid filedes leak */
195 
196           if (master_flow_pipe[0] <= MASTER_FLOW_READ)
197               msg_fatal("%s: flow pipe read descriptor <= %d",
198                           myname, MASTER_FLOW_READ);
199           if (DUP2(master_flow_pipe[0], MASTER_FLOW_READ) < 0)
200               msg_fatal("%s: dup2: %m", myname);
201           if (close(master_flow_pipe[0]) < 0)
202               msg_fatal("close %d: %m", master_flow_pipe[0]);
203 
204           if (master_flow_pipe[1] <= MASTER_FLOW_WRITE)
205               msg_fatal("%s: flow pipe read descriptor <= %d",
206                           myname, MASTER_FLOW_WRITE);
207           if (DUP2(master_flow_pipe[1], MASTER_FLOW_WRITE) < 0)
208               msg_fatal("%s: dup2: %m", myname);
209           if (close(master_flow_pipe[1]) < 0)
210               msg_fatal("close %d: %m", master_flow_pipe[1]);
211 
212           close(serv->status_fd[0]);              /* status channel */
213           if (serv->status_fd[1] <= MASTER_STATUS_FD)
214               msg_fatal("%s: status file descriptor collision", myname);
215           if (DUP2(serv->status_fd[1], MASTER_STATUS_FD) < 0)
216               msg_fatal("%s: dup2 status_fd: %m", myname);
217           (void) close(serv->status_fd[1]);
218 
219           for (n = 0; n < serv->listen_fd_count; n++) {
220               if (serv->listen_fd[n] <= MASTER_LISTEN_FD + n)
221                     msg_fatal("%s: listen file descriptor collision", myname);
222               if (DUP2(serv->listen_fd[n], MASTER_LISTEN_FD + n) < 0)
223                     msg_fatal("%s: dup2 listen_fd %d: %m",
224                                 myname, serv->listen_fd[n]);
225               (void) close(serv->listen_fd[n]);
226           }
227           vstring_sprintf(env_gen, "%s=%o", MASTER_GEN_NAME, master_generation);
228           if (putenv(vstring_str(env_gen)) < 0)
229               msg_fatal("%s: putenv: %m", myname);
230           if (serv->stress_param_val && serv->stress_expire_time > event_time())
231               serv->stress_param_val[0] = CONFIG_BOOL_YES[0];
232 
233           execvp(serv->path, serv->args->argv);
234           msg_fatal("%s: exec %s: %m", myname, serv->path);
235           /* NOTREACHED */
236 
237           /*
238            * Parent. Fill in a process member data structure and set up links
239            * between child and process. Say this process has become available.
240            * If this service has a wakeup timer that is turned on only when the
241            * service is actually used, turn on the wakeup timer.
242            */
243     default:
244           if (msg_verbose)
245               msg_info("spawn command %s; pid %d", serv->path, pid);
246           proc = (MASTER_PROC *) mymalloc(sizeof(MASTER_PROC));
247           proc->serv = serv;
248           proc->pid = pid;
249           proc->gen = master_generation;
250           proc->use_count = 0;
251           proc->avail = 0;
252           binhash_enter(master_child_table, (void *) &pid,
253                           sizeof(pid), (void *) proc);
254           serv->total_proc++;
255           master_avail_more(serv, proc);
256           if (serv->flags & MASTER_FLAG_CONDWAKE) {
257               serv->flags &= ~MASTER_FLAG_CONDWAKE;
258               master_wakeup_init(serv);
259               if (msg_verbose)
260                     msg_info("start conditional timer for %s", serv->name);
261           }
262           return;
263     }
264 }
265 
266 /* master_delete_child - destroy child process info */
267 
master_delete_child(MASTER_PROC * proc)268 static void master_delete_child(MASTER_PROC *proc)
269 {
270     MASTER_SERV *serv;
271 
272     /*
273      * Undo the things that master_spawn did. Stop the process if it still
274      * exists, and remove it from the lookup tables. Update the number of
275      * available processes.
276      */
277     serv = proc->serv;
278     serv->total_proc--;
279     if (proc->avail == MASTER_STAT_AVAIL)
280           master_avail_less(serv, proc);
281     else
282           master_avail_listen(serv);
283     binhash_delete(master_child_table, (void *) &proc->pid,
284                        sizeof(proc->pid), (void (*) (void *)) 0);
285     myfree((void *) proc);
286 }
287 
288 /* master_reap_child - reap dead children */
289 
master_reap_child(void)290 void    master_reap_child(void)
291 {
292     MASTER_SERV *serv;
293     MASTER_PROC *proc;
294     MASTER_PID pid;
295     WAIT_STATUS_T status;
296 
297     /*
298      * Pick up termination status of all dead children. When a process failed
299      * on its first job, assume we see the symptom of a structural problem
300      * (configuration problem, system running out of resources) and back off.
301      */
302     while ((pid = waitpid((pid_t) - 1, &status, WNOHANG)) > 0) {
303           if (msg_verbose)
304               msg_info("master_reap_child: pid %d", pid);
305           if ((proc = (MASTER_PROC *) binhash_find(master_child_table,
306                                                   (void *) &pid, sizeof(pid))) == 0) {
307               if (init_mode)
308                     continue;                     /* non-Postfix process */
309               msg_panic("master_reap: unknown pid: %d", pid);
310           }
311           serv = proc->serv;
312 
313 #define MASTER_KILL_SIGNAL    SIGTERM
314 #define MASTER_SENT_SIGNAL(serv, status) \
315           (MASTER_MARKED_FOR_DELETION(serv) \
316               && WTERMSIG(status) == MASTER_KILL_SIGNAL)
317 
318           /*
319            * XXX The code for WIFSTOPPED() is here in case some buggy kernel
320            * reports WIFSTOPPED() events to a Postfix daemon's parent process
321            * (the master(8) daemon) instead of the tracing process (e.g., gdb).
322            *
323            * The WIFSTOPPED() test prevents master(8) from deleting its record of
324            * a child process that is stopped. That would cause a master(8)
325            * panic (unknown child) when the child terminates.
326            */
327           if (!NORMAL_EXIT_STATUS(status)) {
328               if (WIFSTOPPED(status)) {
329                     msg_warn("process %s pid %d stopped by signal %d",
330                                serv->path, pid, WSTOPSIG(status));
331                     continue;
332               }
333               if (WIFEXITED(status))
334                     msg_warn("process %s pid %d exit status %d",
335                                serv->path, pid, WEXITSTATUS(status));
336               if (WIFSIGNALED(status) && !MASTER_SENT_SIGNAL(serv, status))
337                     msg_warn("process %s pid %d killed by signal %d",
338                                serv->path, pid, WTERMSIG(status));
339               /* master_delete_children() throttles first, then kills. */
340               if (proc->use_count == 0
341                     && (serv->flags & MASTER_FLAG_THROTTLE) == 0) {
342                     msg_warn("%s: bad command startup -- throttling", serv->path);
343                     master_throttle(serv);
344               }
345           }
346           master_delete_child(proc);
347     }
348 }
349 
350 /* master_delete_children - delete all child processes of service */
351 
master_delete_children(MASTER_SERV * serv)352 void    master_delete_children(MASTER_SERV *serv)
353 {
354     BINHASH_INFO **list;
355     BINHASH_INFO **info;
356     MASTER_PROC *proc;
357 
358     /*
359      * XXX turn on the throttle so that master_reap_child() doesn't. Someone
360      * has to turn off the throttle in order to stop the associated timer
361      * request, so we might just as well do it at the end.
362      */
363     master_throttle(serv);
364     for (info = list = binhash_list(master_child_table); *info; info++) {
365           proc = (MASTER_PROC *) info[0]->value;
366           if (proc->serv == serv)
367               (void) kill(proc->pid, MASTER_KILL_SIGNAL);
368     }
369     while (serv->total_proc > 0)
370           master_reap_child();
371     myfree((void *) list);
372     master_unthrottle(serv);
373 }
374