xref: /unit/src/nxt_process.c (revision 1668:03fa2be97871)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 #include <nxt_main_process.h>
9 
10 #if (NXT_HAVE_CLONE)
11 #include <nxt_clone.h>
12 #endif
13 
14 #include <signal.h>
15 
16 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
17 #include <sys/prctl.h>
18 #endif
19 
20 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
21 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
22     nxt_process_t *process);
23 static nxt_int_t nxt_process_send_created(nxt_task_t *task,
24     nxt_process_t *process);
25 static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
26     nxt_process_t *process);
27 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
28     void *data);
29 static void nxt_process_created_error(nxt_task_t *task,
30     nxt_port_recv_msg_t *msg, void *data);
31 
32 
33 /* A cached process pid. */
34 nxt_pid_t  nxt_pid;
35 
36 /* An original parent process pid. */
37 nxt_pid_t  nxt_ppid;
38 
39 /* A cached process effective uid */
40 nxt_uid_t  nxt_euid;
41 
42 /* A cached process effective gid */
43 nxt_gid_t  nxt_egid;
44 
45 nxt_bool_t  nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
46     { 1, 1, 1, 1, 1 },
47     { 1, 0, 0, 0, 0 },
48     { 1, 0, 0, 1, 0 },
49     { 1, 0, 1, 0, 1 },
50     { 1, 0, 0, 1, 0 },
51 };
52 
53 nxt_bool_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
54     { 0, 0, 0, 0, 0 },
55     { 0, 0, 0, 0, 0 },
56     { 0, 0, 0, 1, 0 },
57     { 0, 0, 1, 0, 1 },
58     { 0, 0, 0, 1, 0 },
59 };
60 
61 
62 static nxt_int_t
63 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
64 {
65     nxt_process_t       *p;
66     nxt_runtime_t       *rt;
67     nxt_process_init_t  *init;
68     nxt_process_type_t  ptype;
69 
70     init = nxt_process_init(process);
71 
72     nxt_pid = nxt_getpid();
73 
74     process->pid = nxt_pid;
75 
76     /* Clean inherited cached thread tid. */
77     task->thread->tid = 0;
78 
79 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWPID)
80     if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)) {
81         ssize_t  pidsz;
82         char     procpid[10];
83 
84         nxt_debug(task, "%s isolated pid is %d", process->name, nxt_pid);
85 
86         pidsz = readlink("/proc/self", procpid, sizeof(procpid));
87 
88         if (nxt_slow_path(pidsz < 0 || pidsz >= (ssize_t) sizeof(procpid))) {
89             nxt_alert(task, "failed to read real pid from /proc/self");
90             return NXT_ERROR;
91         }
92 
93         procpid[pidsz] = '\0';
94 
95         nxt_pid = (nxt_pid_t) strtol(procpid, NULL, 10);
96 
97         nxt_assert(nxt_pid >  0 && nxt_errno != ERANGE);
98 
99         process->pid = nxt_pid;
100         task->thread->tid = nxt_pid;
101 
102         nxt_debug(task, "%s real pid is %d", process->name, nxt_pid);
103     }
104 
105 #endif
106 
107     ptype = init->type;
108 
109     nxt_port_reset_next_id();
110 
111     nxt_event_engine_thread_adopt(task->thread->engine);
112 
113     rt = task->thread->runtime;
114 
115     /* Remove not ready processes. */
116     nxt_runtime_process_each(rt, p) {
117 
118         if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) {
119             nxt_debug(task, "remove not required process %PI", p->pid);
120 
121             nxt_process_close_ports(task, p);
122 
123             continue;
124         }
125 
126         if (p->state != NXT_PROCESS_STATE_READY) {
127             nxt_debug(task, "remove not ready process %PI", p->pid);
128 
129             nxt_process_close_ports(task, p);
130 
131             continue;
132         }
133 
134         nxt_port_mmaps_destroy(&p->incoming, 0);
135 
136     } nxt_runtime_process_loop;
137 
138     return NXT_OK;
139 }
140 
141 
142 nxt_pid_t
143 nxt_process_create(nxt_task_t *task, nxt_process_t *process)
144 {
145     nxt_int_t           ret;
146     nxt_pid_t           pid;
147 
148 #if (NXT_HAVE_CLONE)
149     pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
150     if (nxt_slow_path(pid < 0)) {
151         nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno);
152         return pid;
153     }
154 #else
155     pid = fork();
156     if (nxt_slow_path(pid < 0)) {
157         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
158         return pid;
159     }
160 #endif
161 
162     if (pid == 0) {
163         /* Child. */
164 
165         ret = nxt_process_child_fixup(task, process);
166         if (nxt_slow_path(ret != NXT_OK)) {
167             nxt_process_quit(task, 1);
168             return -1;
169         }
170 
171         nxt_runtime_process_add(task, process);
172 
173         if (nxt_slow_path(nxt_process_setup(task, process) != NXT_OK)) {
174             nxt_process_quit(task, 1);
175         }
176 
177         /*
178          * Explicitly return 0 to notice the caller function this is the child.
179          * The caller must return to the event engine work queue loop.
180          */
181         return 0;
182     }
183 
184     /* Parent. */
185 
186 #if (NXT_HAVE_CLONE)
187     nxt_debug(task, "clone(%s): %PI", process->name, pid);
188 #else
189     nxt_debug(task, "fork(%s): %PI", process->name, pid);
190 #endif
191 
192     process->pid = pid;
193 
194     nxt_runtime_process_add(task, process);
195 
196     return pid;
197 }
198 
199 
200 static nxt_int_t
201 nxt_process_setup(nxt_task_t *task, nxt_process_t *process)
202 {
203     nxt_int_t                    ret;
204     nxt_port_t                   *port, *main_port;
205     nxt_thread_t                 *thread;
206     nxt_runtime_t                *rt;
207     nxt_process_init_t           *init;
208     nxt_event_engine_t           *engine;
209     const nxt_event_interface_t  *interface;
210 
211     init = nxt_process_init(process);
212 
213     nxt_debug(task, "%s setup", process->name);
214 
215     nxt_process_title(task, "unit: %s", process->name);
216 
217     thread = task->thread;
218     rt     = thread->runtime;
219 
220     nxt_random_init(&thread->random);
221 
222     rt->type = init->type;
223 
224     engine = thread->engine;
225 
226     /* Update inherited main process event engine and signals processing. */
227     engine->signals->sigev = init->signals;
228 
229     interface = nxt_service_get(rt->services, "engine", rt->engine);
230     if (nxt_slow_path(interface == NULL)) {
231         return NXT_ERROR;
232     }
233 
234     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
235         return NXT_ERROR;
236     }
237 
238     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
239                                          60000 * 1000000LL);
240     if (nxt_slow_path(ret != NXT_OK)) {
241         return NXT_ERROR;
242     }
243 
244     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
245 
246     nxt_port_read_close(main_port);
247     nxt_port_write_enable(task, main_port);
248 
249     port = nxt_process_port_first(process);
250 
251     nxt_port_enable(task, port, init->port_handlers);
252 
253     ret = init->setup(task, process);
254 
255     if (nxt_slow_path(ret != NXT_OK)) {
256         return NXT_ERROR;
257     }
258 
259     switch (process->state) {
260 
261     case NXT_PROCESS_STATE_CREATED:
262         ret = nxt_process_send_created(task, process);
263         break;
264 
265     case NXT_PROCESS_STATE_READY:
266         ret = nxt_process_send_ready(task, process);
267 
268         if (nxt_slow_path(ret != NXT_OK)) {
269             break;
270         }
271 
272         ret = init->start(task, &process->data);
273 
274         nxt_port_write_close(port);
275 
276         break;
277 
278     default:
279         nxt_assert(0);
280     }
281 
282     if (nxt_slow_path(ret != NXT_OK)) {
283         nxt_alert(task, "%s failed to start", process->name);
284     }
285 
286     return ret;
287 }
288 
289 
290 static nxt_int_t
291 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
292 {
293     uint32_t            stream;
294     nxt_int_t           ret;
295     nxt_port_t          *my_port, *main_port;
296     nxt_runtime_t       *rt;
297 
298     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
299 
300     rt = task->thread->runtime;
301 
302     my_port = nxt_process_port_first(process);
303     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
304 
305     nxt_assert(my_port != NULL && main_port != NULL);
306 
307     stream = nxt_port_rpc_register_handler(task, my_port,
308                                            nxt_process_created_ok,
309                                            nxt_process_created_error,
310                                            main_port->pid, process);
311 
312     if (nxt_slow_path(stream == 0)) {
313         return NXT_ERROR;
314     }
315 
316     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
317                                 -1, stream, my_port->id, NULL);
318 
319     if (nxt_slow_path(ret != NXT_OK)) {
320         nxt_alert(task, "%s failed to send CREATED message", process->name);
321         nxt_port_rpc_cancel(task, my_port, stream);
322         return NXT_ERROR;
323     }
324 
325     nxt_debug(task, "%s created", process->name);
326 
327     return NXT_OK;
328 }
329 
330 
331 static void
332 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
333 {
334     nxt_int_t           ret;
335     nxt_process_t       *process;
336     nxt_process_init_t  *init;
337 
338     process = data;
339     init = nxt_process_init(process);
340 
341     ret = nxt_process_apply_creds(task, process);
342     if (nxt_slow_path(ret != NXT_OK)) {
343         goto fail;
344     }
345 
346     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
347 
348     ret = init->start(task, &process->data);
349 
350 fail:
351 
352     nxt_process_quit(task, ret == NXT_OK ? 0 : 1);
353 }
354 
355 
356 static void
357 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
358     void *data)
359 {
360     nxt_process_t       *process;
361     nxt_process_init_t  *init;
362 
363     process = data;
364     init = nxt_process_init(process);
365 
366     nxt_alert(task, "%s failed to start", init->name);
367 
368     nxt_process_quit(task, 1);
369 }
370 
371 
372 nxt_int_t
373 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process)
374 {
375     nxt_int_t  ret;
376 
377     ret = nxt_process_apply_creds(task, process);
378     if (nxt_slow_path(ret != NXT_OK)) {
379         return NXT_ERROR;
380     }
381 
382     process->state = NXT_PROCESS_STATE_READY;
383 
384     return NXT_OK;
385 }
386 
387 
388 nxt_int_t
389 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user,
390     nxt_str_t *group)
391 {
392     char  *str;
393 
394     process->user_cred = nxt_mp_zalloc(process->mem_pool,
395                                        sizeof(nxt_credential_t));
396 
397     if (nxt_slow_path(process->user_cred == NULL)) {
398         return NXT_ERROR;
399     }
400 
401     str = nxt_mp_zalloc(process->mem_pool, user->length + 1);
402     if (nxt_slow_path(str == NULL)) {
403         return NXT_ERROR;
404     }
405 
406     nxt_memcpy(str, user->start, user->length);
407     str[user->length] = '\0';
408 
409     process->user_cred->user = str;
410 
411     if (group->start != NULL) {
412         str = nxt_mp_zalloc(process->mem_pool, group->length + 1);
413         if (nxt_slow_path(str == NULL)) {
414             return NXT_ERROR;
415         }
416 
417         nxt_memcpy(str, group->start, group->length);
418         str[group->length] = '\0';
419 
420     } else {
421         str = NULL;
422     }
423 
424     return nxt_credential_get(task, process->mem_pool, process->user_cred, str);
425 }
426 
427 
428 nxt_int_t
429 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
430 {
431     nxt_int_t      ret, cap_setid;
432     nxt_runtime_t  *rt;
433 
434     rt = task->thread->runtime;
435 
436     cap_setid = rt->capabilities.setid;
437 
438 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
439     if (!cap_setid
440         && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
441         cap_setid = 1;
442     }
443 #endif
444 
445     if (cap_setid) {
446         ret = nxt_credential_setgids(task, process->user_cred);
447         if (nxt_slow_path(ret != NXT_OK)) {
448             return NXT_ERROR;
449         }
450 
451         ret = nxt_credential_setuid(task, process->user_cred);
452         if (nxt_slow_path(ret != NXT_OK)) {
453             return NXT_ERROR;
454         }
455     }
456 
457 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
458     if (nxt_slow_path(process->isolation.new_privs == 0
459                       && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0))
460     {
461         nxt_alert(task, "failed to set no_new_privs %E", nxt_errno);
462         return NXT_ERROR;
463     }
464 #endif
465 
466     return NXT_OK;
467 }
468 
469 
470 static nxt_int_t
471 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process)
472 {
473     nxt_int_t           ret;
474     nxt_port_t          *main_port;
475     nxt_runtime_t       *rt;
476 
477     rt = task->thread->runtime;
478 
479     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
480 
481     nxt_assert(main_port != NULL);
482 
483     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY,
484                                 -1, process->stream, 0, NULL);
485 
486     if (nxt_slow_path(ret != NXT_OK)) {
487         nxt_alert(task, "%s failed to send READY message", process->name);
488         return NXT_ERROR;
489     }
490 
491     nxt_debug(task, "%s sent ready", process->name);
492 
493     return NXT_OK;
494 }
495 
496 
497 #if (NXT_HAVE_POSIX_SPAWN)
498 
499 /*
500  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
501  * Linux glibc 2.4 posix_spawn() without file actions and spawn
502  * attributes uses vfork()/execve().
503  *
504  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
505  *
506  * Solaris 10:
507  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
508  *   private-to-libc vfork(), execve(), and exit() functions.  They are
509  *   identical to regular vfork(), execve(), and exit() in functionality,
510  *   but they are not exported from libc and therefore don't cause the
511  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
512  *   outside of libc that calls vfork() can cause.
513  *
514  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
515  * as syscall.
516  */
517 
518 nxt_pid_t
519 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
520 {
521     nxt_pid_t  pid;
522 
523     nxt_debug(task, "posix_spawn(\"%s\")", name);
524 
525     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
526         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
527         return -1;
528     }
529 
530     return pid;
531 }
532 
533 #else
534 
535 nxt_pid_t
536 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
537 {
538     nxt_pid_t  pid;
539 
540     /*
541      * vfork() is better than fork() because:
542      *   it is faster several times;
543      *   its execution time does not depend on private memory mapping size;
544      *   it has lesser chances to fail due to the ENOMEM error.
545      */
546 
547     pid = vfork();
548 
549     switch (pid) {
550 
551     case -1:
552         nxt_alert(task, "vfork() failed while executing \"%s\" %E",
553                   name, nxt_errno);
554         break;
555 
556     case 0:
557         /* A child. */
558         nxt_debug(task, "execve(\"%s\")", name);
559 
560         (void) execve(name, argv, envp);
561 
562         nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
563 
564         exit(1);
565         nxt_unreachable();
566         break;
567 
568     default:
569         /* A parent. */
570         nxt_debug(task, "vfork(): %PI", pid);
571         break;
572     }
573 
574     return pid;
575 }
576 
577 #endif
578 
579 
580 nxt_int_t
581 nxt_process_daemon(nxt_task_t *task)
582 {
583     nxt_fd_t      fd;
584     nxt_pid_t     pid;
585     const char    *msg;
586 
587     fd = -1;
588 
589     /*
590      * fork() followed by a parent process's exit() detaches a child process
591      * from an init script or terminal shell process which has started the
592      * parent process and allows the child process to run in background.
593      */
594 
595     pid = fork();
596 
597     switch (pid) {
598 
599     case -1:
600         msg = "fork() failed %E";
601         goto fail;
602 
603     case 0:
604         /* A child. */
605         break;
606 
607     default:
608         /* A parent. */
609         nxt_debug(task, "fork(): %PI", pid);
610         exit(0);
611         nxt_unreachable();
612     }
613 
614     nxt_pid = getpid();
615 
616     /* Clean inherited cached thread tid. */
617     task->thread->tid = 0;
618 
619     nxt_debug(task, "daemon");
620 
621     /* Detach from controlling terminal. */
622 
623     if (setsid() == -1) {
624         nxt_alert(task, "setsid() failed %E", nxt_errno);
625         return NXT_ERROR;
626     }
627 
628     /*
629      * Reset file mode creation mask: any access
630      * rights can be set on file creation.
631      */
632     umask(0);
633 
634     /* Redirect STDIN and STDOUT to the "/dev/null". */
635 
636     fd = open("/dev/null", O_RDWR);
637     if (fd == -1) {
638         msg = "open(\"/dev/null\") failed %E";
639         goto fail;
640     }
641 
642     if (dup2(fd, STDIN_FILENO) == -1) {
643         msg = "dup2(\"/dev/null\", STDIN) failed %E";
644         goto fail;
645     }
646 
647     if (dup2(fd, STDOUT_FILENO) == -1) {
648         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
649         goto fail;
650     }
651 
652     if (fd > STDERR_FILENO) {
653         nxt_fd_close(fd);
654     }
655 
656     return NXT_OK;
657 
658 fail:
659 
660     nxt_alert(task, msg, nxt_errno);
661 
662     if (fd != -1) {
663         nxt_fd_close(fd);
664     }
665 
666     return NXT_ERROR;
667 }
668 
669 
670 void
671 nxt_nanosleep(nxt_nsec_t ns)
672 {
673     struct timespec  ts;
674 
675     ts.tv_sec = ns / 1000000000;
676     ts.tv_nsec = ns % 1000000000;
677 
678     (void) nanosleep(&ts, NULL);
679 }
680 
681 
682 void
683 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
684 {
685     process->use_count += i;
686 
687     if (process->use_count == 0) {
688         nxt_runtime_process_release(task->thread->runtime, process);
689     }
690 }
691 
692 
693 void
694 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
695 {
696     nxt_assert(port->process == NULL);
697 
698     port->process = process;
699     nxt_queue_insert_tail(&process->ports, &port->link);
700 
701     nxt_process_use(task, process, 1);
702 }
703 
704 
705 nxt_process_type_t
706 nxt_process_type(nxt_process_t *process)
707 {
708     return nxt_queue_is_empty(&process->ports) ? 0 :
709         (nxt_process_port_first(process))->type;
710 }
711 
712 
713 void
714 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
715 {
716     nxt_port_t  *port;
717 
718     nxt_process_port_each(process, port) {
719 
720         nxt_port_close(task, port);
721 
722         nxt_runtime_port_remove(task, port);
723 
724     } nxt_process_port_loop;
725 }
726 
727 
728 void
729 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
730 {
731     nxt_uint_t           n;
732     nxt_queue_t          *listen;
733     nxt_runtime_t        *rt;
734     nxt_queue_link_t     *link, *next;
735     nxt_listen_event_t   *lev;
736     nxt_listen_socket_t  *ls;
737 
738     rt = task->thread->runtime;
739 
740     nxt_debug(task, "close listen connections");
741 
742     listen = &task->thread->engine->listen_connections;
743 
744     for (link = nxt_queue_first(listen);
745          link != nxt_queue_tail(listen);
746          link = next)
747     {
748         next = nxt_queue_next(link);
749         lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
750         nxt_queue_remove(link);
751 
752         nxt_fd_event_close(task->thread->engine, &lev->socket);
753     }
754 
755     if (rt->listen_sockets != NULL) {
756 
757         ls = rt->listen_sockets->elts;
758         n = rt->listen_sockets->nelts;
759 
760         while (n != 0) {
761             nxt_socket_close(task, ls->socket);
762             ls->socket = -1;
763 
764             ls++;
765             n--;
766         }
767 
768         rt->listen_sockets->nelts = 0;
769     }
770 
771     nxt_runtime_quit(task, exit_status);
772 }
773