Coverage Report

Created: 2025-11-01 06:34

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