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