xref: /unit/src/nxt_process.c (revision 1579:c80e692dc644)
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_write_close(port);
252 
253     nxt_port_enable(task, port, init->port_handlers);
254 
255     ret = init->setup(task, process);
256 
257     if (nxt_slow_path(ret != NXT_OK)) {
258         return NXT_ERROR;
259     }
260 
261     switch (process->state) {
262 
263     case NXT_PROCESS_STATE_CREATED:
264         ret = nxt_process_send_created(task, process);
265         break;
266 
267     case NXT_PROCESS_STATE_READY:
268         ret = nxt_process_send_ready(task, process);
269 
270         if (nxt_slow_path(ret != NXT_OK)) {
271             break;
272         }
273 
274         ret = init->start(task, &process->data);
275         break;
276 
277     default:
278         nxt_assert(0);
279     }
280 
281     if (nxt_slow_path(ret != NXT_OK)) {
282         nxt_alert(task, "%s failed to start", process->name);
283     }
284 
285     return ret;
286 }
287 
288 
289 static nxt_int_t
290 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
291 {
292     uint32_t            stream;
293     nxt_int_t           ret;
294     nxt_port_t          *my_port, *main_port;
295     nxt_runtime_t       *rt;
296 
297     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
298 
299     rt = task->thread->runtime;
300 
301     my_port = nxt_process_port_first(process);
302     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
303 
304     nxt_assert(my_port != NULL && main_port != NULL);
305 
306     stream = nxt_port_rpc_register_handler(task, my_port,
307                                            nxt_process_created_ok,
308                                            nxt_process_created_error,
309                                            main_port->pid, process);
310 
311     if (nxt_slow_path(stream == 0)) {
312         return NXT_ERROR;
313     }
314 
315     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
316                                 -1, stream, my_port->id, NULL);
317 
318     if (nxt_slow_path(ret != NXT_OK)) {
319         nxt_alert(task, "%s failed to send CREATED message", process->name);
320         nxt_port_rpc_cancel(task, my_port, stream);
321         return NXT_ERROR;
322     }
323 
324     nxt_debug(task, "%s created", process->name);
325 
326     return NXT_OK;
327 }
328 
329 
330 static void
331 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
332 {
333     nxt_int_t           ret;
334     nxt_process_t       *process;
335     nxt_process_init_t  *init;
336 
337     process = data;
338     init = nxt_process_init(process);
339 
340     ret = nxt_process_apply_creds(task, process);
341     if (nxt_slow_path(ret != NXT_OK)) {
342         goto fail;
343     }
344 
345     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
346 
347     ret = init->start(task, &process->data);
348 
349 fail:
350 
351     nxt_process_quit(task, ret == NXT_OK ? 0 : 1);
352 }
353 
354 
355 static void
356 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
357     void *data)
358 {
359     nxt_process_t       *process;
360     nxt_process_init_t  *init;
361 
362     process = data;
363     init = nxt_process_init(process);
364 
365     nxt_alert(task, "%s failed to start", init->name);
366 
367     nxt_process_quit(task, 1);
368 }
369 
370 
371 nxt_int_t
372 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process)
373 {
374     nxt_int_t  ret;
375 
376     ret = nxt_process_apply_creds(task, process);
377     if (nxt_slow_path(ret != NXT_OK)) {
378         return NXT_ERROR;
379     }
380 
381     process->state = NXT_PROCESS_STATE_READY;
382 
383     return NXT_OK;
384 }
385 
386 
387 nxt_int_t
388 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user,
389     nxt_str_t *group)
390 {
391     char  *str;
392 
393     process->user_cred = nxt_mp_zalloc(process->mem_pool,
394                                        sizeof(nxt_credential_t));
395 
396     if (nxt_slow_path(process->user_cred == NULL)) {
397         return NXT_ERROR;
398     }
399 
400     str = nxt_mp_zalloc(process->mem_pool, user->length + 1);
401     if (nxt_slow_path(str == NULL)) {
402         return NXT_ERROR;
403     }
404 
405     nxt_memcpy(str, user->start, user->length);
406     str[user->length] = '\0';
407 
408     process->user_cred->user = str;
409 
410     if (group->start != NULL) {
411         str = nxt_mp_zalloc(process->mem_pool, group->length + 1);
412         if (nxt_slow_path(str == NULL)) {
413             return NXT_ERROR;
414         }
415 
416         nxt_memcpy(str, group->start, group->length);
417         str[group->length] = '\0';
418 
419     } else {
420         str = NULL;
421     }
422 
423     return nxt_credential_get(task, process->mem_pool, process->user_cred, str);
424 }
425 
426 
427 nxt_int_t
428 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
429 {
430     nxt_int_t      ret, cap_setid;
431     nxt_runtime_t  *rt;
432 
433     rt = task->thread->runtime;
434 
435     cap_setid = rt->capabilities.setid;
436 
437 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
438     if (!cap_setid
439         && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
440         cap_setid = 1;
441     }
442 #endif
443 
444     if (cap_setid) {
445         ret = nxt_credential_setgids(task, process->user_cred);
446         if (nxt_slow_path(ret != NXT_OK)) {
447             return NXT_ERROR;
448         }
449 
450         ret = nxt_credential_setuid(task, process->user_cred);
451         if (nxt_slow_path(ret != NXT_OK)) {
452             return NXT_ERROR;
453         }
454     }
455 
456 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
457     if (nxt_slow_path(process->isolation.new_privs == 0
458                       && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0))
459     {
460         nxt_alert(task, "failed to set no_new_privs %E", nxt_errno);
461         return NXT_ERROR;
462     }
463 #endif
464 
465     return NXT_OK;
466 }
467 
468 
469 static nxt_int_t
470 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process)
471 {
472     nxt_int_t           ret;
473     nxt_port_t          *main_port;
474     nxt_runtime_t       *rt;
475 
476     rt = task->thread->runtime;
477 
478     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
479 
480     nxt_assert(main_port != NULL);
481 
482     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY,
483                                 -1, process->stream, 0, NULL);
484 
485     if (nxt_slow_path(ret != NXT_OK)) {
486         nxt_alert(task, "%s failed to send READY message", process->name);
487         return NXT_ERROR;
488     }
489 
490     nxt_debug(task, "%s sent ready", process->name);
491 
492     return NXT_OK;
493 }
494 
495 
496 #if (NXT_HAVE_POSIX_SPAWN)
497 
498 /*
499  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
500  * Linux glibc 2.4 posix_spawn() without file actions and spawn
501  * attributes uses vfork()/execve().
502  *
503  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
504  *
505  * Solaris 10:
506  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
507  *   private-to-libc vfork(), execve(), and exit() functions.  They are
508  *   identical to regular vfork(), execve(), and exit() in functionality,
509  *   but they are not exported from libc and therefore don't cause the
510  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
511  *   outside of libc that calls vfork() can cause.
512  *
513  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
514  * as syscall.
515  */
516 
517 nxt_pid_t
518 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
519 {
520     nxt_pid_t  pid;
521 
522     nxt_debug(task, "posix_spawn(\"%s\")", name);
523 
524     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
525         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
526         return -1;
527     }
528 
529     return pid;
530 }
531 
532 #else
533 
534 nxt_pid_t
535 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
536 {
537     nxt_pid_t  pid;
538 
539     /*
540      * vfork() is better than fork() because:
541      *   it is faster several times;
542      *   its execution time does not depend on private memory mapping size;
543      *   it has lesser chances to fail due to the ENOMEM error.
544      */
545 
546     pid = vfork();
547 
548     switch (pid) {
549 
550     case -1:
551         nxt_alert(task, "vfork() failed while executing \"%s\" %E",
552                   name, nxt_errno);
553         break;
554 
555     case 0:
556         /* A child. */
557         nxt_debug(task, "execve(\"%s\")", name);
558 
559         (void) execve(name, argv, envp);
560 
561         nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
562 
563         exit(1);
564         nxt_unreachable();
565         break;
566 
567     default:
568         /* A parent. */
569         nxt_debug(task, "vfork(): %PI", pid);
570         break;
571     }
572 
573     return pid;
574 }
575 
576 #endif
577 
578 
579 nxt_int_t
580 nxt_process_daemon(nxt_task_t *task)
581 {
582     nxt_fd_t      fd;
583     nxt_pid_t     pid;
584     const char    *msg;
585 
586     fd = -1;
587 
588     /*
589      * fork() followed by a parent process's exit() detaches a child process
590      * from an init script or terminal shell process which has started the
591      * parent process and allows the child process to run in background.
592      */
593 
594     pid = fork();
595 
596     switch (pid) {
597 
598     case -1:
599         msg = "fork() failed %E";
600         goto fail;
601 
602     case 0:
603         /* A child. */
604         break;
605 
606     default:
607         /* A parent. */
608         nxt_debug(task, "fork(): %PI", pid);
609         exit(0);
610         nxt_unreachable();
611     }
612 
613     nxt_pid = getpid();
614 
615     /* Clean inherited cached thread tid. */
616     task->thread->tid = 0;
617 
618     nxt_debug(task, "daemon");
619 
620     /* Detach from controlling terminal. */
621 
622     if (setsid() == -1) {
623         nxt_alert(task, "setsid() failed %E", nxt_errno);
624         return NXT_ERROR;
625     }
626 
627     /*
628      * Reset file mode creation mask: any access
629      * rights can be set on file creation.
630      */
631     umask(0);
632 
633     /* Redirect STDIN and STDOUT to the "/dev/null". */
634 
635     fd = open("/dev/null", O_RDWR);
636     if (fd == -1) {
637         msg = "open(\"/dev/null\") failed %E";
638         goto fail;
639     }
640 
641     if (dup2(fd, STDIN_FILENO) == -1) {
642         msg = "dup2(\"/dev/null\", STDIN) failed %E";
643         goto fail;
644     }
645 
646     if (dup2(fd, STDOUT_FILENO) == -1) {
647         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
648         goto fail;
649     }
650 
651     if (fd > STDERR_FILENO) {
652         nxt_fd_close(fd);
653     }
654 
655     return NXT_OK;
656 
657 fail:
658 
659     nxt_alert(task, msg, nxt_errno);
660 
661     if (fd != -1) {
662         nxt_fd_close(fd);
663     }
664 
665     return NXT_ERROR;
666 }
667 
668 
669 void
670 nxt_nanosleep(nxt_nsec_t ns)
671 {
672     struct timespec  ts;
673 
674     ts.tv_sec = ns / 1000000000;
675     ts.tv_nsec = ns % 1000000000;
676 
677     (void) nanosleep(&ts, NULL);
678 }
679 
680 
681 void
682 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
683 {
684     process->use_count += i;
685 
686     if (process->use_count == 0) {
687         nxt_runtime_process_release(task->thread->runtime, process);
688     }
689 }
690 
691 
692 void
693 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
694 {
695     nxt_assert(port->process == NULL);
696 
697     port->process = process;
698     nxt_queue_insert_tail(&process->ports, &port->link);
699 
700     nxt_process_use(task, process, 1);
701 }
702 
703 
704 nxt_process_type_t
705 nxt_process_type(nxt_process_t *process)
706 {
707     return nxt_queue_is_empty(&process->ports) ? 0 :
708         (nxt_process_port_first(process))->type;
709 }
710 
711 
712 void
713 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
714 {
715     nxt_port_t  *port;
716 
717     nxt_process_port_each(process, port) {
718 
719         nxt_port_close(task, port);
720 
721         nxt_runtime_port_remove(task, port);
722 
723     } nxt_process_port_loop;
724 }
725 
726 
727 void
728 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
729 {
730     nxt_uint_t           n;
731     nxt_queue_t          *listen;
732     nxt_runtime_t        *rt;
733     nxt_queue_link_t     *link, *next;
734     nxt_listen_event_t   *lev;
735     nxt_listen_socket_t  *ls;
736 
737     rt = task->thread->runtime;
738 
739     nxt_debug(task, "close listen connections");
740 
741     listen = &task->thread->engine->listen_connections;
742 
743     for (link = nxt_queue_first(listen);
744          link != nxt_queue_tail(listen);
745          link = next)
746     {
747         next = nxt_queue_next(link);
748         lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
749         nxt_queue_remove(link);
750 
751         nxt_fd_event_close(task->thread->engine, &lev->socket);
752     }
753 
754     if (rt->listen_sockets != NULL) {
755 
756         ls = rt->listen_sockets->elts;
757         n = rt->listen_sockets->nelts;
758 
759         while (n != 0) {
760             nxt_socket_close(task, ls->socket);
761             ls->socket = -1;
762 
763             ls++;
764             n--;
765         }
766 
767         rt->listen_sockets->nelts = 0;
768     }
769 
770     nxt_runtime_quit(task, exit_status);
771 }
772