xref: /unit/src/nxt_process.c (revision 2426:d5e936f09dc0)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 
9 #include <nxt_application.h>
10 #include <nxt_cgroup.h>
11 
12 #if (NXT_HAVE_LINUX_NS)
13 #include <nxt_clone.h>
14 #endif
15 
16 #include <signal.h>
17 
18 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
19 #include <sys/prctl.h>
20 #endif
21 
22 
23 #if (NXT_HAVE_LINUX_NS) && (NXT_HAVE_CLONE_NEWPID)
24 #define nxt_is_pid_isolated(process)                                          \
25     nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)
26 #else
27 #define nxt_is_pid_isolated(process)                                          \
28     (0)
29 #endif
30 
31 
32 #if (NXT_HAVE_LINUX_NS)
33 static nxt_int_t nxt_process_pipe_timer(nxt_fd_t fd, short event);
34 static nxt_int_t nxt_process_check_pid_status(const nxt_fd_t *gc_pipe);
35 static nxt_pid_t nxt_process_recv_pid(const nxt_fd_t *pid_pipe,
36     const nxt_fd_t *gc_pipe);
37 static void nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid);
38 static nxt_int_t nxt_process_unshare(nxt_task_t *task, nxt_process_t *process,
39     nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, nxt_bool_t use_pidns);
40 static nxt_int_t nxt_process_init_pidns(nxt_task_t *task,
41     const nxt_process_t *process, nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
42     nxt_bool_t *use_pidns);
43 #endif
44 
45 static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process);
46 static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process);
47 static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process);
48 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
49 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
50     nxt_process_t *process);
51 static void nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
52     void *data);
53 static void nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
54     void *data);
55 static nxt_int_t nxt_process_send_created(nxt_task_t *task,
56     nxt_process_t *process);
57 static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
58     nxt_process_t *process);
59 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
60     void *data);
61 static void nxt_process_created_error(nxt_task_t *task,
62     nxt_port_recv_msg_t *msg, void *data);
63 
64 
65 /* A cached process pid. */
66 nxt_pid_t  nxt_pid;
67 
68 /* An original parent process pid. */
69 nxt_pid_t  nxt_ppid;
70 
71 /* A cached process effective uid */
72 nxt_uid_t  nxt_euid;
73 
74 /* A cached process effective gid */
75 nxt_gid_t  nxt_egid;
76 
77 uint8_t  nxt_proc_keep_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
78     { 1, 1, 1, 1, 1, 1 },
79     { 1, 0, 0, 0, 0, 0 },
80     { 1, 0, 0, 1, 0, 0 },
81     { 1, 0, 1, 1, 1, 1 },
82     { 1, 0, 0, 1, 0, 0 },
83     { 1, 0, 0, 1, 0, 0 },
84 };
85 
86 uint8_t  nxt_proc_send_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
87     { 1, 1, 1, 1, 1, 1 },
88     { 1, 0, 0, 0, 0, 0 },
89     { 1, 0, 0, 1, 0, 0 },
90     { 1, 0, 1, 1, 1, 1 },
91     { 1, 0, 0, 0, 0, 0 },
92     { 1, 0, 0, 0, 0, 0 },
93 };
94 
95 uint8_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
96     { 0, 0, 0, 0, 0, 0 },
97     { 0, 0, 0, 0, 0, 0 },
98     { 0, 0, 0, 1, 0, 0 },
99     { 0, 0, 1, 0, 1, 1 },
100     { 0, 0, 0, 1, 0, 0 },
101     { 1, 0, 0, 1, 0, 0 },
102 };
103 
104 
105 static const nxt_port_handlers_t  nxt_process_whoami_port_handlers = {
106     .quit         = nxt_signal_quit_handler,
107     .rpc_ready    = nxt_port_rpc_handler,
108     .rpc_error    = nxt_port_rpc_handler,
109 };
110 
111 
112 nxt_process_t *
nxt_process_new(nxt_runtime_t * rt)113 nxt_process_new(nxt_runtime_t *rt)
114 {
115     nxt_process_t  *process;
116 
117     process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t)
118                             + sizeof(nxt_process_init_t));
119 
120     if (nxt_slow_path(process == NULL)) {
121         return NULL;
122     }
123 
124     nxt_queue_init(&process->ports);
125 
126     nxt_thread_mutex_create(&process->incoming.mutex);
127 
128     process->use_count = 1;
129 
130     nxt_queue_init(&process->children);
131 
132     return process;
133 }
134 
135 
136 void
nxt_process_use(nxt_task_t * task,nxt_process_t * process,int i)137 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
138 {
139     process->use_count += i;
140 
141     if (process->use_count == 0) {
142         nxt_runtime_process_release(task->thread->runtime, process);
143     }
144 }
145 
146 
147 nxt_int_t
nxt_process_init_start(nxt_task_t * task,nxt_process_init_t init)148 nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init)
149 {
150     nxt_int_t           ret;
151     nxt_runtime_t       *rt;
152     nxt_process_t       *process;
153     nxt_process_init_t  *pinit;
154 
155     rt = task->thread->runtime;
156 
157     process = nxt_process_new(rt);
158     if (nxt_slow_path(process == NULL)) {
159         return NXT_ERROR;
160     }
161 
162     process->parent_port = rt->port_by_type[rt->type];
163 
164     process->name = init.name;
165     process->user_cred = &rt->user_cred;
166 
167     pinit = nxt_process_init(process);
168     *pinit = init;
169 
170     ret = nxt_process_start(task, process);
171     if (nxt_slow_path(ret == NXT_ERROR)) {
172         nxt_process_use(task, process, -1);
173     }
174 
175     return ret;
176 }
177 
178 
179 nxt_int_t
nxt_process_start(nxt_task_t * task,nxt_process_t * process)180 nxt_process_start(nxt_task_t *task, nxt_process_t *process)
181 {
182     nxt_mp_t            *tmp_mp;
183     nxt_int_t           ret;
184     nxt_pid_t           pid;
185     nxt_port_t          *port;
186     nxt_process_init_t  *init;
187 
188     init = nxt_process_init(process);
189 
190     port = nxt_port_new(task, 0, 0, init->type);
191     if (nxt_slow_path(port == NULL)) {
192         return NXT_ERROR;
193     }
194 
195     nxt_process_port_add(task, process, port);
196 
197     ret = nxt_port_socket_init(task, port, 0);
198     if (nxt_slow_path(ret != NXT_OK)) {
199         goto free_port;
200     }
201 
202     tmp_mp = nxt_mp_create(1024, 128, 256, 32);
203     if (nxt_slow_path(tmp_mp == NULL)) {
204         ret = NXT_ERROR;
205 
206         goto close_port;
207     }
208 
209     if (init->prefork) {
210         ret = init->prefork(task, process, tmp_mp);
211         if (nxt_slow_path(ret != NXT_OK)) {
212             goto free_mempool;
213         }
214     }
215 
216     pid = nxt_process_create(task, process);
217 
218     switch (pid) {
219 
220     case -1:
221         ret = NXT_ERROR;
222         break;
223 
224     case 0:
225         /* The child process: return to the event engine work queue loop. */
226 
227         nxt_process_use(task, process, -1);
228 
229         ret = NXT_AGAIN;
230         break;
231 
232     default:
233         /* The parent process created a new process. */
234 
235         nxt_process_use(task, process, -1);
236 
237         nxt_port_read_close(port);
238         nxt_port_write_enable(task, port);
239 
240         ret = NXT_OK;
241         break;
242     }
243 
244 free_mempool:
245 
246     nxt_mp_destroy(tmp_mp);
247 
248 close_port:
249 
250     if (nxt_slow_path(ret == NXT_ERROR)) {
251         nxt_port_close(task, port);
252     }
253 
254 free_port:
255 
256     nxt_port_use(task, port, -1);
257 
258     return ret;
259 }
260 
261 
262 static nxt_int_t
nxt_process_child_fixup(nxt_task_t * task,nxt_process_t * process)263 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
264 {
265     nxt_process_t       *p;
266     nxt_runtime_t       *rt;
267     nxt_process_init_t  *init;
268     nxt_process_type_t  ptype;
269 
270     init = nxt_process_init(process);
271 
272     nxt_ppid = nxt_pid;
273 
274     nxt_pid = getpid();
275 
276     process->pid = nxt_pid;
277     process->isolated_pid = nxt_pid;
278 
279     /* Clean inherited cached thread tid. */
280     task->thread->tid = 0;
281 
282     ptype = init->type;
283 
284     nxt_port_reset_next_id();
285 
286     nxt_event_engine_thread_adopt(task->thread->engine);
287 
288     rt = task->thread->runtime;
289 
290     /* Remove not ready processes. */
291     nxt_runtime_process_each(rt, p) {
292 
293         if (nxt_proc_keep_matrix[ptype][nxt_process_type(p)] == 0
294             && p->pid != nxt_ppid) /* Always keep parent's port. */
295         {
296             nxt_debug(task, "remove not required process %PI", p->pid);
297 
298             nxt_process_close_ports(task, p);
299 
300             continue;
301         }
302 
303         if (p->state != NXT_PROCESS_STATE_READY) {
304             nxt_debug(task, "remove not ready process %PI", p->pid);
305 
306             nxt_process_close_ports(task, p);
307 
308             continue;
309         }
310 
311         nxt_port_mmaps_destroy(&p->incoming, 0);
312 
313     } nxt_runtime_process_loop;
314 
315     if (init->siblings != NULL) {
316         nxt_queue_each(p, init->siblings, nxt_process_t, link) {
317 
318             nxt_debug(task, "remove sibling process %PI", p->pid);
319 
320             nxt_process_close_ports(task, p);
321 
322         } nxt_queue_loop;
323     }
324 
325     return NXT_OK;
326 }
327 
328 
329 #if (NXT_HAVE_LINUX_NS)
330 
331 static nxt_int_t
nxt_process_pipe_timer(nxt_fd_t fd,short event)332 nxt_process_pipe_timer(nxt_fd_t fd, short event)
333 {
334     int                           ret;
335     sigset_t                      mask;
336     struct pollfd                 pfd;
337 
338     static const struct timespec  ts = { .tv_sec = 5 };
339 
340     /*
341      * Temporarily block the signals we are handling, (except
342      * for SIGINT & SIGTERM) so that ppoll(2) doesn't get
343      * interrupted. After ppoll(2) returns, our old sigmask
344      * will be back in effect and any pending signals will be
345      * delivered.
346      *
347      * This is because while the kernel ppoll syscall updates
348      * the struct timespec with the time remaining if it got
349      * interrupted with EINTR, the glibc wrapper hides this
350      * from us so we have no way of knowing how long to retry
351      * the ppoll(2) for and if we just retry with the same
352      * timeout we could find ourselves in an infinite loop.
353      */
354     pthread_sigmask(SIG_SETMASK, NULL, &mask);
355     sigdelset(&mask, SIGINT);
356     sigdelset(&mask, SIGTERM);
357 
358     pfd.fd = fd;
359     pfd.events = event;
360 
361     ret = ppoll(&pfd, 1, &ts, &mask);
362     if (ret <= 0 || (ret == 1 && pfd.revents & POLLERR)) {
363         return NXT_ERROR;
364     }
365 
366     return NXT_OK;
367 }
368 
369 
370 static nxt_int_t
nxt_process_check_pid_status(const nxt_fd_t * gc_pipe)371 nxt_process_check_pid_status(const nxt_fd_t *gc_pipe)
372 {
373     int8_t   status;
374     ssize_t  ret;
375 
376     close(gc_pipe[1]);
377 
378     ret = nxt_process_pipe_timer(gc_pipe[0], POLLIN);
379     if (ret == NXT_OK) {
380         ret = read(gc_pipe[0], &status, sizeof(int8_t));
381     }
382 
383     if (ret <= 0) {
384         status = -1;
385     }
386 
387     close(gc_pipe[0]);
388 
389     return status;
390 }
391 
392 
393 static nxt_pid_t
nxt_process_recv_pid(const nxt_fd_t * pid_pipe,const nxt_fd_t * gc_pipe)394 nxt_process_recv_pid(const nxt_fd_t *pid_pipe, const nxt_fd_t *gc_pipe)
395 {
396     int8_t     status;
397     ssize_t    ret;
398     nxt_pid_t  pid;
399 
400     close(pid_pipe[1]);
401     close(gc_pipe[0]);
402 
403     status = 0;
404 
405     ret = nxt_process_pipe_timer(pid_pipe[0], POLLIN);
406     if (ret == NXT_OK) {
407         ret = read(pid_pipe[0], &pid, sizeof(nxt_pid_t));
408     }
409 
410     if (ret <= 0) {
411         status = -1;
412         pid = -1;
413     }
414 
415     write(gc_pipe[1], &status, sizeof(int8_t));
416 
417     close(pid_pipe[0]);
418     close(gc_pipe[1]);
419 
420     return pid;
421 }
422 
423 
424 static void
nxt_process_send_pid(const nxt_fd_t * pid_pipe,nxt_pid_t pid)425 nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid)
426 {
427     nxt_int_t  ret;
428 
429     close(pid_pipe[0]);
430 
431     ret = nxt_process_pipe_timer(pid_pipe[1], POLLOUT);
432     if (ret == NXT_OK) {
433         write(pid_pipe[1], &pid, sizeof(nxt_pid_t));
434     }
435 
436     close(pid_pipe[1]);
437 }
438 
439 
440 static nxt_int_t
nxt_process_unshare(nxt_task_t * task,nxt_process_t * process,nxt_fd_t * pid_pipe,nxt_fd_t * gc_pipe,nxt_bool_t use_pidns)441 nxt_process_unshare(nxt_task_t *task, nxt_process_t *process,
442                     nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
443                     nxt_bool_t use_pidns)
444 {
445     int        ret;
446     nxt_pid_t  pid;
447 
448     if (process->isolation.clone.flags == 0) {
449         return NXT_OK;
450     }
451 
452     ret = unshare(process->isolation.clone.flags);
453     if (nxt_slow_path(ret == -1)) {
454         nxt_alert(task, "unshare() failed for %s %E", process->name,
455                   nxt_errno);
456 
457         if (use_pidns) {
458             nxt_pipe_close(task, gc_pipe);
459             nxt_pipe_close(task, pid_pipe);
460         }
461 
462         return NXT_ERROR;
463     }
464 
465     if (!use_pidns) {
466         return NXT_OK;
467     }
468 
469     /*
470      * PID namespace requested. Employ a double fork(2) technique
471      * so that the prototype process will be placed into the new
472      * namespace and end up with PID 1 (as before with clone).
473      */
474     pid = fork();
475     if (nxt_slow_path(pid < 0)) {
476         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
477         nxt_pipe_close(task, gc_pipe);
478         nxt_pipe_close(task, pid_pipe);
479 
480         return NXT_ERROR;
481 
482     } else if (pid > 0) {
483         nxt_pipe_close(task, gc_pipe);
484         nxt_process_send_pid(pid_pipe, pid);
485 
486         _exit(EXIT_SUCCESS);
487     }
488 
489     nxt_pipe_close(task, pid_pipe);
490     ret = nxt_process_check_pid_status(gc_pipe);
491     if (ret == -1) {
492         return NXT_ERROR;
493     }
494 
495     return NXT_OK;
496 }
497 
498 
499 static nxt_int_t
nxt_process_init_pidns(nxt_task_t * task,const nxt_process_t * process,nxt_fd_t * pid_pipe,nxt_fd_t * gc_pipe,nxt_bool_t * use_pidns)500 nxt_process_init_pidns(nxt_task_t *task, const nxt_process_t *process,
501                        nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
502                        nxt_bool_t *use_pidns)
503 {
504     int ret;
505 
506     *use_pidns = 0;
507 
508 #if (NXT_HAVE_CLONE_NEWPID)
509     *use_pidns = nxt_is_pid_isolated(process);
510 #endif
511 
512     if (!*use_pidns) {
513         return NXT_OK;
514     }
515 
516     ret = nxt_pipe_create(task, pid_pipe, 0, 0);
517     if (nxt_slow_path(ret == NXT_ERROR)) {
518         return NXT_ERROR;
519     }
520 
521     ret = nxt_pipe_create(task, gc_pipe, 0, 0);
522     if (nxt_slow_path(ret == NXT_ERROR)) {
523         return NXT_ERROR;
524     }
525 
526 #if (NXT_HAVE_PR_SET_CHILD_SUBREAPER)
527     ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
528     if (nxt_slow_path(ret == -1)) {
529         nxt_alert(task, "prctl(PR_SET_CHILD_SUBREAPER) failed for %s %E",
530                   process->name, nxt_errno);
531     }
532 #endif
533 
534     return NXT_OK;
535 }
536 
537 #endif /* NXT_HAVE_LINUX_NS */
538 
539 
540 static nxt_pid_t
nxt_process_create(nxt_task_t * task,nxt_process_t * process)541 nxt_process_create(nxt_task_t *task, nxt_process_t *process)
542 {
543     nxt_int_t      ret;
544     nxt_pid_t      pid;
545     nxt_runtime_t  *rt;
546 
547 #if (NXT_HAVE_LINUX_NS)
548     nxt_fd_t       pid_pipe[2], gc_pipe[2];
549     nxt_bool_t     use_pidns;
550 
551     ret = nxt_process_init_pidns(task, process, pid_pipe, gc_pipe, &use_pidns);
552     if (ret == NXT_ERROR) {
553         return -1;
554     }
555 #endif
556 
557     pid = fork();
558     if (nxt_slow_path(pid < 0)) {
559         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
560         return pid;
561     }
562 
563     if (pid == 0) {
564         /* Child. */
565 
566 #if (NXT_HAVE_LINUX_NS)
567         ret = nxt_process_unshare(task, process, pid_pipe, gc_pipe, use_pidns);
568         if (ret == NXT_ERROR) {
569             _exit(EXIT_FAILURE);
570         }
571 #endif
572 
573         ret = nxt_process_child_fixup(task, process);
574         if (nxt_slow_path(ret != NXT_OK)) {
575             nxt_process_quit(task, 1);
576             return -1;
577         }
578 
579         ret = nxt_process_setup(task, process);
580         if (nxt_slow_path(ret != NXT_OK)) {
581             nxt_process_quit(task, 1);
582         }
583 
584         /*
585          * Explicitly return 0 to notice the caller function this is the child.
586          * The caller must return to the event engine work queue loop.
587          */
588         return 0;
589     }
590 
591     /* Parent. */
592 
593     nxt_debug(task, "fork(%s): %PI", process->name, pid);
594 
595 #if (NXT_HAVE_LINUX_NS)
596     if (use_pidns) {
597         pid = nxt_process_recv_pid(pid_pipe, gc_pipe);
598         if (pid == -1) {
599             return pid;
600         }
601     }
602 #endif
603 
604     process->pid = pid;
605     process->isolated_pid = pid;
606 
607     rt = task->thread->runtime;
608 
609     if (rt->is_pid_isolated) {
610         /*
611          * Do not register process in runtime with isolated pid.
612          * Only global pid can be the key to avoid clash.
613          */
614         nxt_assert(!nxt_queue_is_empty(&process->ports));
615 
616         nxt_port_use(task, nxt_process_port_first(process), 1);
617 
618     } else {
619         nxt_runtime_process_add(task, process);
620     }
621 
622 #if (NXT_HAVE_CGROUP)
623     ret = nxt_cgroup_proc_add(task, process);
624     if (nxt_slow_path(ret != NXT_OK)) {
625         nxt_alert(task, "cgroup: failed to add process %s to %s %E",
626                   process->name, process->isolation.cgroup.path, nxt_errno);
627         nxt_cgroup_cleanup(task, process);
628         kill(pid, SIGTERM);
629         return -1;
630     }
631 #endif
632 
633     return pid;
634 }
635 
636 
637 static nxt_int_t
nxt_process_setup(nxt_task_t * task,nxt_process_t * process)638 nxt_process_setup(nxt_task_t *task, nxt_process_t *process)
639 {
640     nxt_int_t                    ret;
641     nxt_thread_t                 *thread;
642     nxt_runtime_t                *rt;
643     nxt_process_init_t           *init;
644     nxt_event_engine_t           *engine;
645     const nxt_event_interface_t  *interface;
646 
647     init = nxt_process_init(process);
648 
649     nxt_debug(task, "%s setup", process->name);
650 
651     nxt_process_title(task, "unit: %s", process->name);
652 
653     thread = task->thread;
654     rt     = thread->runtime;
655 
656     if (process->parent_port == rt->port_by_type[NXT_PROCESS_PROTOTYPE]) {
657         nxt_app_set_logs();
658     }
659 
660     nxt_random_init(&thread->random);
661 
662     rt->type = init->type;
663 
664     engine = thread->engine;
665 
666     /* Update inherited main process event engine and signals processing. */
667     engine->signals->sigev = init->signals;
668 
669     interface = nxt_service_get(rt->services, "engine", rt->engine);
670     if (nxt_slow_path(interface == NULL)) {
671         return NXT_ERROR;
672     }
673 
674     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
675         return NXT_ERROR;
676     }
677 
678     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
679                                          60000 * 1000000LL);
680     if (nxt_slow_path(ret != NXT_OK)) {
681         return NXT_ERROR;
682     }
683 
684     nxt_port_read_close(process->parent_port);
685     nxt_port_write_enable(task, process->parent_port);
686 
687     /*
688      * If the parent process is already isolated, rt->pid_isolation is already
689      * set to 1 at this point.
690      */
691     if (nxt_is_pid_isolated(process)) {
692         rt->is_pid_isolated = 1;
693     }
694 
695     if (rt->is_pid_isolated
696         || process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN])
697     {
698         ret = nxt_process_whoami(task, process);
699 
700     } else {
701         ret = nxt_process_do_start(task, process);
702     }
703 
704     return ret;
705 }
706 
707 
708 static nxt_int_t
nxt_process_do_start(nxt_task_t * task,nxt_process_t * process)709 nxt_process_do_start(nxt_task_t *task, nxt_process_t *process)
710 {
711     nxt_int_t           ret;
712     nxt_port_t          *port;
713     nxt_process_init_t  *init;
714 
715     nxt_runtime_process_add(task, process);
716 
717     init = nxt_process_init(process);
718     port = nxt_process_port_first(process);
719 
720     nxt_port_enable(task, port, init->port_handlers);
721 
722     ret = init->setup(task, process);
723     if (nxt_slow_path(ret != NXT_OK)) {
724         return NXT_ERROR;
725     }
726 
727     switch (process->state) {
728 
729     case NXT_PROCESS_STATE_CREATED:
730         ret = nxt_process_send_created(task, process);
731         break;
732 
733     case NXT_PROCESS_STATE_READY:
734         ret = nxt_process_send_ready(task, process);
735 
736         if (nxt_slow_path(ret != NXT_OK)) {
737             break;
738         }
739 
740         ret = init->start(task, &process->data);
741 
742         nxt_port_write_close(port);
743 
744         break;
745 
746     default:
747         nxt_assert(0);
748     }
749 
750     if (nxt_slow_path(ret != NXT_OK)) {
751         nxt_alert(task, "%s failed to start", process->name);
752     }
753 
754     return ret;
755 }
756 
757 
758 static nxt_int_t
nxt_process_whoami(nxt_task_t * task,nxt_process_t * process)759 nxt_process_whoami(nxt_task_t *task, nxt_process_t *process)
760 {
761     uint32_t       stream;
762     nxt_fd_t       fd;
763     nxt_buf_t      *buf;
764     nxt_int_t      ret;
765     nxt_port_t     *my_port, *main_port;
766     nxt_runtime_t  *rt;
767 
768     rt = task->thread->runtime;
769 
770     my_port = nxt_process_port_first(process);
771     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
772 
773     nxt_assert(my_port != NULL && main_port != NULL);
774 
775     nxt_port_enable(task, my_port, &nxt_process_whoami_port_handlers);
776 
777     buf = nxt_buf_mem_alloc(main_port->mem_pool, sizeof(nxt_pid_t), 0);
778     if (nxt_slow_path(buf == NULL)) {
779         return NXT_ERROR;
780     }
781 
782     buf->mem.free = nxt_cpymem(buf->mem.free, &nxt_ppid, sizeof(nxt_pid_t));
783 
784     stream = nxt_port_rpc_register_handler(task, my_port,
785                                            nxt_process_whoami_ok,
786                                            nxt_process_whoami_error,
787                                            main_port->pid, process);
788     if (nxt_slow_path(stream == 0)) {
789         nxt_mp_free(main_port->mem_pool, buf);
790 
791         return NXT_ERROR;
792     }
793 
794     fd = (process->parent_port != main_port) ? my_port->pair[1] : -1;
795 
796     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_WHOAMI,
797                                 fd, stream, my_port->id, buf);
798 
799     if (nxt_slow_path(ret != NXT_OK)) {
800         nxt_alert(task, "%s failed to send WHOAMI message", process->name);
801         nxt_port_rpc_cancel(task, my_port, stream);
802         nxt_mp_free(main_port->mem_pool, buf);
803 
804         return NXT_ERROR;
805     }
806 
807     return NXT_OK;
808 }
809 
810 
811 static void
nxt_process_whoami_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)812 nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
813 {
814     nxt_pid_t      pid, isolated_pid;
815     nxt_buf_t      *buf;
816     nxt_port_t     *port;
817     nxt_process_t  *process;
818     nxt_runtime_t  *rt;
819 
820     process = data;
821 
822     buf = msg->buf;
823 
824     nxt_assert(nxt_buf_used_size(buf) == sizeof(nxt_pid_t));
825 
826     nxt_memcpy(&pid, buf->mem.pos, sizeof(nxt_pid_t));
827 
828     isolated_pid = nxt_pid;
829 
830     if (isolated_pid != pid) {
831         nxt_pid = pid;
832         process->pid = pid;
833 
834         nxt_process_port_each(process, port) {
835             port->pid = pid;
836         } nxt_process_port_loop;
837     }
838 
839     rt = task->thread->runtime;
840 
841     if (process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) {
842         port = process->parent_port;
843 
844         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_PROCESS_CREATED,
845                                      -1, 0, 0, NULL);
846 
847         nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
848     }
849 
850     if (nxt_slow_path(nxt_process_do_start(task, process) != NXT_OK)) {
851         nxt_process_quit(task, 1);
852     }
853 }
854 
855 
856 static void
nxt_process_whoami_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)857 nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
858 {
859     nxt_alert(task, "WHOAMI error");
860 
861     nxt_process_quit(task, 1);
862 }
863 
864 
865 static nxt_int_t
nxt_process_send_created(nxt_task_t * task,nxt_process_t * process)866 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
867 {
868     uint32_t            stream;
869     nxt_int_t           ret;
870     nxt_port_t          *my_port, *main_port;
871     nxt_runtime_t       *rt;
872 
873     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
874 
875     rt = task->thread->runtime;
876 
877     my_port = nxt_process_port_first(process);
878     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
879 
880     nxt_assert(my_port != NULL && main_port != NULL);
881 
882     stream = nxt_port_rpc_register_handler(task, my_port,
883                                            nxt_process_created_ok,
884                                            nxt_process_created_error,
885                                            main_port->pid, process);
886 
887     if (nxt_slow_path(stream == 0)) {
888         return NXT_ERROR;
889     }
890 
891     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
892                                 -1, stream, my_port->id, NULL);
893 
894     if (nxt_slow_path(ret != NXT_OK)) {
895         nxt_alert(task, "%s failed to send CREATED message", process->name);
896         nxt_port_rpc_cancel(task, my_port, stream);
897         return NXT_ERROR;
898     }
899 
900     nxt_debug(task, "%s created", process->name);
901 
902     return NXT_OK;
903 }
904 
905 
906 static void
nxt_process_created_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)907 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
908 {
909     nxt_int_t           ret;
910     nxt_process_t       *process;
911     nxt_process_init_t  *init;
912 
913     process = data;
914 
915     process->state = NXT_PROCESS_STATE_READY;
916 
917     init = nxt_process_init(process);
918 
919     ret = nxt_process_apply_creds(task, process);
920     if (nxt_slow_path(ret != NXT_OK)) {
921         goto fail;
922     }
923 
924     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
925 
926     ret = nxt_process_send_ready(task, process);
927     if (nxt_slow_path(ret != NXT_OK)) {
928         goto fail;
929     }
930 
931     ret = init->start(task, &process->data);
932 
933     if (nxt_process_type(process) != NXT_PROCESS_PROTOTYPE) {
934         nxt_port_write_close(nxt_process_port_first(process));
935     }
936 
937     if (nxt_fast_path(ret == NXT_OK)) {
938         return;
939     }
940 
941 fail:
942     nxt_process_quit(task, 1);
943 }
944 
945 
946 static void
nxt_process_created_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)947 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
948     void *data)
949 {
950     nxt_process_t       *process;
951     nxt_process_init_t  *init;
952 
953     process = data;
954     init = nxt_process_init(process);
955 
956     nxt_alert(task, "%s failed to start", init->name);
957 
958     nxt_process_quit(task, 1);
959 }
960 
961 
962 nxt_int_t
nxt_process_core_setup(nxt_task_t * task,nxt_process_t * process)963 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process)
964 {
965     nxt_int_t  ret;
966 
967     ret = nxt_process_apply_creds(task, process);
968     if (nxt_slow_path(ret != NXT_OK)) {
969         return NXT_ERROR;
970     }
971 
972     process->state = NXT_PROCESS_STATE_READY;
973 
974     return NXT_OK;
975 }
976 
977 
978 nxt_int_t
nxt_process_creds_set(nxt_task_t * task,nxt_process_t * process,nxt_str_t * user,nxt_str_t * group)979 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user,
980     nxt_str_t *group)
981 {
982     char  *str;
983 
984     process->user_cred = nxt_mp_zalloc(process->mem_pool,
985                                        sizeof(nxt_credential_t));
986 
987     if (nxt_slow_path(process->user_cred == NULL)) {
988         return NXT_ERROR;
989     }
990 
991     str = nxt_mp_zalloc(process->mem_pool, user->length + 1);
992     if (nxt_slow_path(str == NULL)) {
993         return NXT_ERROR;
994     }
995 
996     nxt_memcpy(str, user->start, user->length);
997     str[user->length] = '\0';
998 
999     process->user_cred->user = str;
1000 
1001     if (group->start != NULL) {
1002         str = nxt_mp_zalloc(process->mem_pool, group->length + 1);
1003         if (nxt_slow_path(str == NULL)) {
1004             return NXT_ERROR;
1005         }
1006 
1007         nxt_memcpy(str, group->start, group->length);
1008         str[group->length] = '\0';
1009 
1010     } else {
1011         str = NULL;
1012     }
1013 
1014     return nxt_credential_get(task, process->mem_pool, process->user_cred, str);
1015 }
1016 
1017 
1018 nxt_int_t
nxt_process_apply_creds(nxt_task_t * task,nxt_process_t * process)1019 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
1020 {
1021     nxt_int_t      ret, cap_setid;
1022     nxt_runtime_t  *rt;
1023 
1024     rt = task->thread->runtime;
1025 
1026     cap_setid = rt->capabilities.setid;
1027 
1028 #if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER)
1029     if (!cap_setid
1030         && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER))
1031     {
1032         cap_setid = 1;
1033     }
1034 #endif
1035 
1036     if (cap_setid) {
1037         ret = nxt_credential_setgids(task, process->user_cred);
1038         if (nxt_slow_path(ret != NXT_OK)) {
1039             return NXT_ERROR;
1040         }
1041 
1042         ret = nxt_credential_setuid(task, process->user_cred);
1043         if (nxt_slow_path(ret != NXT_OK)) {
1044             return NXT_ERROR;
1045         }
1046     }
1047 
1048 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
1049     if (nxt_slow_path(process->isolation.new_privs == 0
1050                       && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0))
1051     {
1052         nxt_alert(task, "failed to set no_new_privs %E", nxt_errno);
1053         return NXT_ERROR;
1054     }
1055 #endif
1056 
1057     return NXT_OK;
1058 }
1059 
1060 
1061 static nxt_int_t
nxt_process_send_ready(nxt_task_t * task,nxt_process_t * process)1062 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process)
1063 {
1064     nxt_int_t  ret;
1065 
1066     ret = nxt_port_socket_write(task, process->parent_port,
1067                                 NXT_PORT_MSG_PROCESS_READY,
1068                                 -1, process->stream, 0, NULL);
1069 
1070     if (nxt_slow_path(ret != NXT_OK)) {
1071         nxt_alert(task, "%s failed to send READY message", process->name);
1072         return NXT_ERROR;
1073     }
1074 
1075     nxt_debug(task, "%s sent ready", process->name);
1076 
1077     return NXT_OK;
1078 }
1079 
1080 
1081 /*
1082  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
1083  * Linux glibc 2.4 posix_spawn() without file actions and spawn
1084  * attributes uses vfork()/execve().
1085  *
1086  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
1087  *
1088  * Solaris 10:
1089  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
1090  *   private-to-libc vfork(), execve(), and exit() functions.  They are
1091  *   identical to regular vfork(), execve(), and exit() in functionality,
1092  *   but they are not exported from libc and therefore don't cause the
1093  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
1094  *   outside of libc that calls vfork() can cause.
1095  *
1096  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
1097  * as syscall.
1098  */
1099 
1100 nxt_pid_t
nxt_process_execute(nxt_task_t * task,char * name,char ** argv,char ** envp)1101 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
1102 {
1103     nxt_pid_t  pid;
1104 
1105     nxt_debug(task, "posix_spawn(\"%s\")", name);
1106 
1107     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
1108         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
1109         return -1;
1110     }
1111 
1112     return pid;
1113 }
1114 
1115 
1116 nxt_int_t
nxt_process_daemon(nxt_task_t * task)1117 nxt_process_daemon(nxt_task_t *task)
1118 {
1119     nxt_fd_t      fd;
1120     nxt_pid_t     pid;
1121     const char    *msg;
1122 
1123     fd = -1;
1124 
1125     /*
1126      * fork() followed by a parent process's exit() detaches a child process
1127      * from an init script or terminal shell process which has started the
1128      * parent process and allows the child process to run in background.
1129      */
1130 
1131     pid = fork();
1132 
1133     switch (pid) {
1134 
1135     case -1:
1136         msg = "fork() failed %E";
1137         goto fail;
1138 
1139     case 0:
1140         /* A child. */
1141         break;
1142 
1143     default:
1144         /* A parent. */
1145         nxt_debug(task, "fork(): %PI", pid);
1146         exit(0);
1147         nxt_unreachable();
1148     }
1149 
1150     nxt_pid = getpid();
1151 
1152     /* Clean inherited cached thread tid. */
1153     task->thread->tid = 0;
1154 
1155     nxt_debug(task, "daemon");
1156 
1157     /* Detach from controlling terminal. */
1158 
1159     if (setsid() == -1) {
1160         nxt_alert(task, "setsid() failed %E", nxt_errno);
1161         return NXT_ERROR;
1162     }
1163 
1164     /*
1165      * Set a sefe umask to give at most 755/644 permissions on
1166      * directories/files.
1167      */
1168     umask(0022);
1169 
1170     /* Redirect STDIN and STDOUT to the "/dev/null". */
1171 
1172     fd = open("/dev/null", O_RDWR);
1173     if (fd == -1) {
1174         msg = "open(\"/dev/null\") failed %E";
1175         goto fail;
1176     }
1177 
1178     if (dup2(fd, STDIN_FILENO) == -1) {
1179         msg = "dup2(\"/dev/null\", STDIN) failed %E";
1180         goto fail;
1181     }
1182 
1183     if (dup2(fd, STDOUT_FILENO) == -1) {
1184         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
1185         goto fail;
1186     }
1187 
1188     if (fd > STDERR_FILENO) {
1189         nxt_fd_close(fd);
1190     }
1191 
1192     return NXT_OK;
1193 
1194 fail:
1195 
1196     nxt_alert(task, msg, nxt_errno);
1197 
1198     if (fd != -1) {
1199         nxt_fd_close(fd);
1200     }
1201 
1202     return NXT_ERROR;
1203 }
1204 
1205 
1206 void
nxt_nanosleep(nxt_nsec_t ns)1207 nxt_nanosleep(nxt_nsec_t ns)
1208 {
1209     struct timespec  ts;
1210 
1211     ts.tv_sec = ns / 1000000000;
1212     ts.tv_nsec = ns % 1000000000;
1213 
1214     (void) nanosleep(&ts, NULL);
1215 }
1216 
1217 
1218 void
nxt_process_port_add(nxt_task_t * task,nxt_process_t * process,nxt_port_t * port)1219 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
1220 {
1221     nxt_assert(port->process == NULL);
1222 
1223     port->process = process;
1224     nxt_queue_insert_tail(&process->ports, &port->link);
1225 
1226     nxt_process_use(task, process, 1);
1227 }
1228 
1229 
1230 nxt_process_type_t
nxt_process_type(nxt_process_t * process)1231 nxt_process_type(nxt_process_t *process)
1232 {
1233     return nxt_queue_is_empty(&process->ports) ? 0 :
1234         (nxt_process_port_first(process))->type;
1235 }
1236 
1237 
1238 void
nxt_process_close_ports(nxt_task_t * task,nxt_process_t * process)1239 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
1240 {
1241     nxt_port_t  *port;
1242 
1243     nxt_process_use(task, process, 1);
1244 
1245     nxt_process_port_each(process, port) {
1246 
1247         nxt_port_close(task, port);
1248 
1249         nxt_runtime_port_remove(task, port);
1250 
1251     } nxt_process_port_loop;
1252 
1253     nxt_process_use(task, process, -1);
1254 }
1255 
1256 
1257 void
nxt_process_quit(nxt_task_t * task,nxt_uint_t exit_status)1258 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
1259 {
1260     nxt_queue_t          *listen;
1261     nxt_queue_link_t     *link, *next;
1262     nxt_listen_event_t   *lev;
1263 
1264     nxt_debug(task, "close listen connections");
1265 
1266     listen = &task->thread->engine->listen_connections;
1267 
1268     for (link = nxt_queue_first(listen);
1269          link != nxt_queue_tail(listen);
1270          link = next)
1271     {
1272         next = nxt_queue_next(link);
1273         lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
1274         nxt_queue_remove(link);
1275 
1276         nxt_fd_event_close(task->thread->engine, &lev->socket);
1277     }
1278 
1279     nxt_runtime_quit(task, exit_status);
1280 }
1281