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 #if (NXT_HAVE_PIVOT_ROOT) 21 #include <mntent.h> 22 #endif 23 24 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process); 25 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task, 26 nxt_process_t *process); 27 static nxt_int_t nxt_process_send_created(nxt_task_t *task, 28 nxt_process_t *process); 29 static nxt_int_t nxt_process_send_ready(nxt_task_t *task, 30 nxt_process_t *process); 31 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, 32 void *data); 33 static void nxt_process_created_error(nxt_task_t *task, 34 nxt_port_recv_msg_t *msg, void *data); 35 36 #if (NXT_HAVE_ISOLATION_ROOTFS) 37 static nxt_int_t nxt_process_chroot(nxt_task_t *task, const char *path); 38 39 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) 40 static nxt_int_t nxt_process_pivot_root(nxt_task_t *task, const char *rootfs); 41 static nxt_int_t nxt_process_private_mount(nxt_task_t *task, 42 const char *rootfs); 43 static int nxt_pivot_root(const char *new_root, const char *old_root); 44 #endif 45 #endif 46 47 /* A cached process pid. */ 48 nxt_pid_t nxt_pid; 49 50 /* An original parent process pid. */ 51 nxt_pid_t nxt_ppid; 52 53 /* A cached process effective uid */ 54 nxt_uid_t nxt_euid; 55 56 /* A cached process effective gid */ 57 nxt_gid_t nxt_egid; 58 59 nxt_bool_t nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 60 { 1, 1, 1, 1, 1 }, 61 { 1, 0, 0, 0, 0 }, 62 { 1, 0, 0, 1, 0 }, 63 { 1, 0, 1, 0, 1 }, 64 { 1, 0, 0, 1, 0 }, 65 }; 66 67 nxt_bool_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 68 { 0, 0, 0, 0, 0 }, 69 { 0, 0, 0, 0, 0 }, 70 { 0, 0, 0, 1, 0 }, 71 { 0, 0, 1, 0, 1 }, 72 { 0, 0, 0, 1, 0 }, 73 }; 74 75 76 static nxt_int_t 77 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) 78 { 79 nxt_process_t *p; 80 nxt_runtime_t *rt; 81 nxt_process_init_t *init; 82 nxt_process_type_t ptype; 83 84 init = nxt_process_init(process); 85 86 nxt_pid = nxt_getpid(); 87 88 process->pid = nxt_pid; 89 90 /* Clean inherited cached thread tid. */ 91 task->thread->tid = 0; 92 93 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWPID) 94 if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)) { 95 ssize_t pidsz; 96 char procpid[10]; 97 98 nxt_debug(task, "%s isolated pid is %d", process->name, nxt_pid); 99 100 pidsz = readlink("/proc/self", procpid, sizeof(procpid)); 101 102 if (nxt_slow_path(pidsz < 0 || pidsz >= (ssize_t) sizeof(procpid))) { 103 nxt_alert(task, "failed to read real pid from /proc/self"); 104 return NXT_ERROR; 105 } 106 107 procpid[pidsz] = '\0'; 108 109 nxt_pid = (nxt_pid_t) strtol(procpid, NULL, 10); 110 111 nxt_assert(nxt_pid > 0 && nxt_errno != ERANGE); 112 113 process->pid = nxt_pid; 114 task->thread->tid = nxt_pid; 115 116 nxt_debug(task, "%s real pid is %d", process->name, nxt_pid); 117 } 118 119 #endif 120 121 ptype = init->type; 122 123 nxt_port_reset_next_id(); 124 125 nxt_event_engine_thread_adopt(task->thread->engine); 126 127 rt = task->thread->runtime; 128 129 /* Remove not ready processes. */ 130 nxt_runtime_process_each(rt, p) { 131 132 if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) { 133 nxt_debug(task, "remove not required process %PI", p->pid); 134 135 nxt_process_close_ports(task, p); 136 137 continue; 138 } 139 140 if (p->state != NXT_PROCESS_STATE_READY) { 141 nxt_debug(task, "remove not ready process %PI", p->pid); 142 143 nxt_process_close_ports(task, p); 144 145 continue; 146 } 147 148 nxt_port_mmaps_destroy(&p->incoming, 0); 149 150 } nxt_runtime_process_loop; 151 152 return NXT_OK; 153 } 154 155 156 nxt_pid_t 157 nxt_process_create(nxt_task_t *task, nxt_process_t *process) 158 { 159 nxt_int_t ret; 160 nxt_pid_t pid; 161 162 #if (NXT_HAVE_CLONE) 163 pid = nxt_clone(SIGCHLD | process->isolation.clone.flags); 164 if (nxt_slow_path(pid < 0)) { 165 nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno); 166 return pid; 167 } 168 #else 169 pid = fork(); 170 if (nxt_slow_path(pid < 0)) { 171 nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); 172 return pid; 173 } 174 #endif 175 176 if (pid == 0) { 177 /* Child. */ 178 179 ret = nxt_process_child_fixup(task, process); 180 if (nxt_slow_path(ret != NXT_OK)) { 181 nxt_process_quit(task, 1); 182 return -1; 183 } 184 185 nxt_runtime_process_add(task, process); 186 187 if (nxt_slow_path(nxt_process_setup(task, process) != NXT_OK)) { 188 nxt_process_quit(task, 1); 189 } 190 191 /* 192 * Explicitly return 0 to notice the caller function this is the child. 193 * The caller must return to the event engine work queue loop. 194 */ 195 return 0; 196 } 197 198 /* Parent. */ 199 200 #if (NXT_HAVE_CLONE) 201 nxt_debug(task, "clone(%s): %PI", process->name, pid); 202 #else 203 nxt_debug(task, "fork(%s): %PI", process->name, pid); 204 #endif 205 206 process->pid = pid; 207 208 nxt_runtime_process_add(task, process); 209 210 return pid; 211 } 212 213 214 static nxt_int_t 215 nxt_process_setup(nxt_task_t *task, nxt_process_t *process) 216 { 217 nxt_int_t ret; 218 nxt_port_t *port, *main_port; 219 nxt_thread_t *thread; 220 nxt_runtime_t *rt; 221 nxt_process_init_t *init; 222 nxt_event_engine_t *engine; 223 const nxt_event_interface_t *interface; 224 225 init = nxt_process_init(process); 226 227 nxt_debug(task, "%s setup", process->name); 228 229 nxt_process_title(task, "unit: %s", process->name); 230 231 thread = task->thread; 232 rt = thread->runtime; 233 234 nxt_random_init(&thread->random); 235 236 rt->type = init->type; 237 238 engine = thread->engine; 239 240 /* Update inherited main process event engine and signals processing. */ 241 engine->signals->sigev = init->signals; 242 243 interface = nxt_service_get(rt->services, "engine", rt->engine); 244 if (nxt_slow_path(interface == NULL)) { 245 return NXT_ERROR; 246 } 247 248 if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) { 249 return NXT_ERROR; 250 } 251 252 ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads, 253 60000 * 1000000LL); 254 if (nxt_slow_path(ret != NXT_OK)) { 255 return NXT_ERROR; 256 } 257 258 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 259 260 nxt_port_read_close(main_port); 261 nxt_port_write_enable(task, main_port); 262 263 port = nxt_process_port_first(process); 264 265 nxt_port_write_close(port); 266 267 nxt_port_enable(task, port, init->port_handlers); 268 269 ret = init->setup(task, process); 270 271 if (nxt_slow_path(ret != NXT_OK)) { 272 return NXT_ERROR; 273 } 274 275 switch (process->state) { 276 277 case NXT_PROCESS_STATE_CREATED: 278 ret = nxt_process_send_created(task, process); 279 break; 280 281 case NXT_PROCESS_STATE_READY: 282 ret = nxt_process_send_ready(task, process); 283 284 if (nxt_slow_path(ret != NXT_OK)) { 285 break; 286 } 287 288 ret = init->start(task, &process->data); 289 break; 290 291 default: 292 nxt_assert(0); 293 } 294 295 if (nxt_slow_path(ret != NXT_OK)) { 296 nxt_alert(task, "%s failed to start", process->name); 297 } 298 299 return ret; 300 } 301 302 303 static nxt_int_t 304 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process) 305 { 306 uint32_t stream; 307 nxt_int_t ret; 308 nxt_port_t *my_port, *main_port; 309 nxt_runtime_t *rt; 310 311 nxt_assert(process->state == NXT_PROCESS_STATE_CREATED); 312 313 rt = task->thread->runtime; 314 315 my_port = nxt_process_port_first(process); 316 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 317 318 nxt_assert(my_port != NULL && main_port != NULL); 319 320 stream = nxt_port_rpc_register_handler(task, my_port, 321 nxt_process_created_ok, 322 nxt_process_created_error, 323 main_port->pid, process); 324 325 if (nxt_slow_path(stream == 0)) { 326 return NXT_ERROR; 327 } 328 329 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED, 330 -1, stream, my_port->id, NULL); 331 332 if (nxt_slow_path(ret != NXT_OK)) { 333 nxt_alert(task, "%s failed to send CREATED message", process->name); 334 nxt_port_rpc_cancel(task, my_port, stream); 335 return NXT_ERROR; 336 } 337 338 nxt_debug(task, "%s created", process->name); 339 340 return NXT_OK; 341 } 342 343 344 static void 345 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 346 { 347 nxt_int_t ret; 348 nxt_process_t *process; 349 nxt_process_init_t *init; 350 351 process = data; 352 init = nxt_process_init(process); 353 354 ret = nxt_process_apply_creds(task, process); 355 if (nxt_slow_path(ret != NXT_OK)) { 356 goto fail; 357 } 358 359 nxt_log(task, NXT_LOG_INFO, "%s started", process->name); 360 361 ret = init->start(task, &process->data); 362 363 fail: 364 365 nxt_process_quit(task, ret == NXT_OK ? 0 : 1); 366 } 367 368 369 static void 370 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 371 void *data) 372 { 373 nxt_process_t *process; 374 nxt_process_init_t *init; 375 376 process = data; 377 init = nxt_process_init(process); 378 379 nxt_alert(task, "%s failed to start", init->name); 380 381 nxt_process_quit(task, 1); 382 } 383 384 385 nxt_int_t 386 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process) 387 { 388 nxt_int_t ret; 389 390 ret = nxt_process_apply_creds(task, process); 391 if (nxt_slow_path(ret != NXT_OK)) { 392 return NXT_ERROR; 393 } 394 395 process->state = NXT_PROCESS_STATE_READY; 396 397 return NXT_OK; 398 } 399 400 401 #if (NXT_HAVE_CLONE_NEWUSER) 402 403 nxt_int_t 404 nxt_process_vldt_isolation_creds(nxt_task_t *task, nxt_process_t *process) 405 { 406 nxt_int_t ret; 407 nxt_clone_t *clone; 408 nxt_credential_t *creds; 409 410 clone = &process->isolation.clone; 411 creds = process->user_cred; 412 413 if (clone->uidmap.size == 0 && clone->gidmap.size == 0) { 414 return NXT_OK; 415 } 416 417 if (!nxt_is_clone_flag_set(clone->flags, NEWUSER)) { 418 if (nxt_slow_path(clone->uidmap.size > 0)) { 419 nxt_log(task, NXT_LOG_ERR, "\"uidmap\" is set but " 420 "\"isolation.namespaces.credential\" is false or unset"); 421 422 return NXT_ERROR; 423 } 424 425 if (nxt_slow_path(clone->gidmap.size > 0)) { 426 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" is set but " 427 "\"isolation.namespaces.credential\" is false or unset"); 428 429 return NXT_ERROR; 430 } 431 432 return NXT_OK; 433 } 434 435 ret = nxt_clone_vldt_credential_uidmap(task, &clone->uidmap, creds); 436 if (nxt_slow_path(ret != NXT_OK)) { 437 return NXT_ERROR; 438 } 439 440 return nxt_clone_vldt_credential_gidmap(task, &clone->gidmap, creds); 441 } 442 443 #endif 444 445 446 nxt_int_t 447 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user, 448 nxt_str_t *group) 449 { 450 char *str; 451 452 process->user_cred = nxt_mp_zalloc(process->mem_pool, 453 sizeof(nxt_credential_t)); 454 455 if (nxt_slow_path(process->user_cred == NULL)) { 456 return NXT_ERROR; 457 } 458 459 str = nxt_mp_zalloc(process->mem_pool, user->length + 1); 460 if (nxt_slow_path(str == NULL)) { 461 return NXT_ERROR; 462 } 463 464 nxt_memcpy(str, user->start, user->length); 465 str[user->length] = '\0'; 466 467 process->user_cred->user = str; 468 469 if (group->start != NULL) { 470 str = nxt_mp_zalloc(process->mem_pool, group->length + 1); 471 if (nxt_slow_path(str == NULL)) { 472 return NXT_ERROR; 473 } 474 475 nxt_memcpy(str, group->start, group->length); 476 str[group->length] = '\0'; 477 478 } else { 479 str = NULL; 480 } 481 482 return nxt_credential_get(task, process->mem_pool, process->user_cred, str); 483 } 484 485 486 nxt_int_t 487 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process) 488 { 489 nxt_int_t ret, cap_setid; 490 nxt_runtime_t *rt; 491 492 rt = task->thread->runtime; 493 494 cap_setid = rt->capabilities.setid; 495 496 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) 497 if (!cap_setid 498 && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { 499 cap_setid = 1; 500 } 501 #endif 502 503 if (cap_setid) { 504 ret = nxt_credential_setgids(task, process->user_cred); 505 if (nxt_slow_path(ret != NXT_OK)) { 506 return NXT_ERROR; 507 } 508 509 ret = nxt_credential_setuid(task, process->user_cred); 510 if (nxt_slow_path(ret != NXT_OK)) { 511 return NXT_ERROR; 512 } 513 } 514 515 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 516 if (nxt_slow_path(process->isolation.new_privs == 0 517 && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)) 518 { 519 nxt_alert(task, "failed to set no_new_privs %E", nxt_errno); 520 return NXT_ERROR; 521 } 522 #endif 523 524 return NXT_OK; 525 } 526 527 528 #if (NXT_HAVE_ISOLATION_ROOTFS) 529 530 531 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) 532 533 534 nxt_int_t 535 nxt_process_change_root(nxt_task_t *task, nxt_process_t *process) 536 { 537 char *rootfs; 538 nxt_int_t ret; 539 540 rootfs = (char *) process->isolation.rootfs; 541 542 nxt_debug(task, "change root: %s", rootfs); 543 544 if (NXT_CLONE_MNT(process->isolation.clone.flags)) { 545 ret = nxt_process_pivot_root(task, rootfs); 546 } else { 547 ret = nxt_process_chroot(task, rootfs); 548 } 549 550 if (nxt_fast_path(ret == NXT_OK)) { 551 if (nxt_slow_path(chdir("/") < 0)) { 552 nxt_alert(task, "chdir(\"/\") %E", nxt_errno); 553 return NXT_ERROR; 554 } 555 } 556 557 return ret; 558 } 559 560 561 #else 562 563 564 nxt_int_t 565 nxt_process_change_root(nxt_task_t *task, nxt_process_t *process) 566 { 567 char *rootfs; 568 569 rootfs = (char *) process->isolation.rootfs; 570 571 nxt_debug(task, "change root: %s", rootfs); 572 573 if (nxt_fast_path(nxt_process_chroot(task, rootfs) == NXT_OK)) { 574 if (nxt_slow_path(chdir("/") < 0)) { 575 nxt_alert(task, "chdir(\"/\") %E", nxt_errno); 576 return NXT_ERROR; 577 } 578 579 return NXT_OK; 580 } 581 582 return NXT_ERROR; 583 } 584 585 586 #endif 587 588 589 static nxt_int_t 590 nxt_process_chroot(nxt_task_t *task, const char *path) 591 { 592 if (nxt_slow_path(chroot(path) < 0)) { 593 nxt_alert(task, "chroot(%s) %E", path, nxt_errno); 594 return NXT_ERROR; 595 } 596 597 return NXT_OK; 598 } 599 600 601 void 602 nxt_process_unmount_all(nxt_task_t *task, nxt_process_t *process) 603 { 604 size_t i, n; 605 nxt_array_t *mounts; 606 nxt_fs_mount_t *mnt; 607 608 nxt_debug(task, "unmount all (%s)", process->name); 609 610 mounts = process->isolation.mounts; 611 n = mounts->nelts; 612 mnt = mounts->elts; 613 614 for (i = 0; i < n; i++) { 615 nxt_fs_unmount(mnt[i].dst); 616 } 617 } 618 619 620 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) 621 622 /* 623 * pivot_root(2) can only be safely used with containers, otherwise it can 624 * umount(2) the global root filesystem and screw up the machine. 625 */ 626 627 static nxt_int_t 628 nxt_process_pivot_root(nxt_task_t *task, const char *path) 629 { 630 /* 631 * This implementation makes use of a kernel trick that works for ages 632 * and now documented in Linux kernel 5. 633 * https://lore.kernel.org/linux-man/87r24piwhm.fsf@x220.int.ebiederm.org/T/ 634 */ 635 636 if (nxt_slow_path(mount("", "/", "", MS_SLAVE|MS_REC, "") != 0)) { 637 nxt_alert(task, "failed to make / a slave mount %E", nxt_errno); 638 return NXT_ERROR; 639 } 640 641 if (nxt_slow_path(nxt_process_private_mount(task, path) != NXT_OK)) { 642 return NXT_ERROR; 643 } 644 645 if (nxt_slow_path(mount(path, path, "bind", MS_BIND|MS_REC, "") != 0)) { 646 nxt_alert(task, "error bind mounting rootfs %E", nxt_errno); 647 return NXT_ERROR; 648 } 649 650 if (nxt_slow_path(chdir(path) != 0)) { 651 nxt_alert(task, "failed to chdir(%s) %E", path, nxt_errno); 652 return NXT_ERROR; 653 } 654 655 if (nxt_slow_path(nxt_pivot_root(".", ".") != 0)) { 656 nxt_alert(task, "failed to pivot_root %E", nxt_errno); 657 return NXT_ERROR; 658 } 659 660 /* 661 * Make oldroot a slave mount to avoid unmounts getting propagated to the 662 * host. 663 */ 664 if (nxt_slow_path(mount("", ".", "", MS_SLAVE | MS_REC, NULL) != 0)) { 665 nxt_alert(task, "failed to bind mount rootfs %E", nxt_errno); 666 return NXT_ERROR; 667 } 668 669 if (nxt_slow_path(umount2(".", MNT_DETACH) != 0)) { 670 nxt_alert(task, "failed to umount old root directory %E", nxt_errno); 671 return NXT_ERROR; 672 } 673 674 return NXT_OK; 675 } 676 677 678 static nxt_int_t 679 nxt_process_private_mount(nxt_task_t *task, const char *rootfs) 680 { 681 char *parent_mnt; 682 FILE *procfile; 683 u_char **mounts; 684 size_t len; 685 uint8_t *shared; 686 nxt_int_t ret, index, nmounts; 687 struct mntent *ent; 688 689 static const char *mount_path = "/proc/self/mounts"; 690 691 ret = NXT_ERROR; 692 ent = NULL; 693 shared = NULL; 694 procfile = NULL; 695 parent_mnt = NULL; 696 697 nmounts = 256; 698 699 mounts = nxt_malloc(nmounts * sizeof(uintptr_t)); 700 if (nxt_slow_path(mounts == NULL)) { 701 goto fail; 702 } 703 704 shared = nxt_malloc(nmounts); 705 if (nxt_slow_path(shared == NULL)) { 706 goto fail; 707 } 708 709 procfile = setmntent(mount_path, "r"); 710 if (nxt_slow_path(procfile == NULL)) { 711 nxt_alert(task, "failed to open %s %E", mount_path, nxt_errno); 712 713 goto fail; 714 } 715 716 index = 0; 717 718 again: 719 720 for ( ; index < nmounts; index++) { 721 ent = getmntent(procfile); 722 if (ent == NULL) { 723 nmounts = index; 724 break; 725 } 726 727 mounts[index] = (u_char *) strdup(ent->mnt_dir); 728 shared[index] = hasmntopt(ent, "shared") != NULL; 729 } 730 731 if (ent != NULL) { 732 /* there are still entries to be read */ 733 734 nmounts *= 2; 735 mounts = nxt_realloc(mounts, nmounts); 736 if (nxt_slow_path(mounts == NULL)) { 737 goto fail; 738 } 739 740 shared = nxt_realloc(shared, nmounts); 741 if (nxt_slow_path(shared == NULL)) { 742 goto fail; 743 } 744 745 goto again; 746 } 747 748 for (index = 0; index < nmounts; index++) { 749 if (nxt_strcmp(mounts[index], rootfs) == 0) { 750 parent_mnt = (char *) rootfs; 751 break; 752 } 753 } 754 755 if (parent_mnt == NULL) { 756 len = nxt_strlen(rootfs); 757 758 parent_mnt = nxt_malloc(len + 1); 759 if (parent_mnt == NULL) { 760 goto fail; 761 } 762 763 nxt_memcpy(parent_mnt, rootfs, len); 764 parent_mnt[len] = '\0'; 765 766 if (parent_mnt[len - 1] == '/') { 767 parent_mnt[len - 1] = '\0'; 768 len--; 769 } 770 771 for ( ;; ) { 772 for (index = 0; index < nmounts; index++) { 773 if (nxt_strcmp(mounts[index], parent_mnt) == 0) { 774 goto found; 775 } 776 } 777 778 if (len == 1 && parent_mnt[0] == '/') { 779 nxt_alert(task, "parent mount not found"); 780 goto fail; 781 } 782 783 /* parent dir */ 784 while (parent_mnt[len - 1] != '/' && len > 0) { 785 len--; 786 } 787 788 if (nxt_slow_path(len == 0)) { 789 nxt_alert(task, "parent mount not found"); 790 goto fail; 791 } 792 793 if (len == 1) { 794 parent_mnt[len] = '\0'; /* / */ 795 } else { 796 parent_mnt[len - 1] = '\0'; /* /<path> */ 797 } 798 } 799 } 800 801 found: 802 803 if (shared[index]) { 804 if (nxt_slow_path(mount("", parent_mnt, "", MS_PRIVATE, "") != 0)) { 805 nxt_alert(task, "mount(\"\", \"%s\", MS_PRIVATE) %E", parent_mnt, 806 nxt_errno); 807 808 goto fail; 809 } 810 } 811 812 ret = NXT_OK; 813 814 fail: 815 816 if (procfile != NULL) { 817 endmntent(procfile); 818 } 819 820 if (mounts != NULL) { 821 for (index = 0; index < nmounts; index++) { 822 nxt_free(mounts[index]); 823 } 824 825 nxt_free(mounts); 826 } 827 828 if (shared != NULL) { 829 nxt_free(shared); 830 } 831 832 if (parent_mnt != NULL && parent_mnt != rootfs) { 833 nxt_free(parent_mnt); 834 } 835 836 return ret; 837 } 838 839 840 static int 841 nxt_pivot_root(const char *new_root, const char *old_root) 842 { 843 return syscall(__NR_pivot_root, new_root, old_root); 844 } 845 846 #endif 847 848 #endif 849 850 851 static nxt_int_t 852 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process) 853 { 854 nxt_int_t ret; 855 nxt_port_t *main_port; 856 nxt_runtime_t *rt; 857 858 rt = task->thread->runtime; 859 860 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 861 862 nxt_assert(main_port != NULL); 863 864 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY, 865 -1, process->stream, 0, NULL); 866 867 if (nxt_slow_path(ret != NXT_OK)) { 868 nxt_alert(task, "%s failed to send READY message", process->name); 869 return NXT_ERROR; 870 } 871 872 nxt_debug(task, "%s sent ready", process->name); 873 874 return NXT_OK; 875 } 876 877 878 #if (NXT_HAVE_POSIX_SPAWN) 879 880 /* 881 * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). 882 * Linux glibc 2.4 posix_spawn() without file actions and spawn 883 * attributes uses vfork()/execve(). 884 * 885 * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve(). 886 * 887 * Solaris 10: 888 * In the Solaris 10 OS, posix_spawn() is currently implemented using 889 * private-to-libc vfork(), execve(), and exit() functions. They are 890 * identical to regular vfork(), execve(), and exit() in functionality, 891 * but they are not exported from libc and therefore don't cause the 892 * deadlock-in-the-dynamic-linker problem that any multithreaded code 893 * outside of libc that calls vfork() can cause. 894 * 895 * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented 896 * as syscall. 897 */ 898 899 nxt_pid_t 900 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 901 { 902 nxt_pid_t pid; 903 904 nxt_debug(task, "posix_spawn(\"%s\")", name); 905 906 if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) { 907 nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno); 908 return -1; 909 } 910 911 return pid; 912 } 913 914 #else 915 916 nxt_pid_t 917 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 918 { 919 nxt_pid_t pid; 920 921 /* 922 * vfork() is better than fork() because: 923 * it is faster several times; 924 * its execution time does not depend on private memory mapping size; 925 * it has lesser chances to fail due to the ENOMEM error. 926 */ 927 928 pid = vfork(); 929 930 switch (pid) { 931 932 case -1: 933 nxt_alert(task, "vfork() failed while executing \"%s\" %E", 934 name, nxt_errno); 935 break; 936 937 case 0: 938 /* A child. */ 939 nxt_debug(task, "execve(\"%s\")", name); 940 941 (void) execve(name, argv, envp); 942 943 nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno); 944 945 exit(1); 946 nxt_unreachable(); 947 break; 948 949 default: 950 /* A parent. */ 951 nxt_debug(task, "vfork(): %PI", pid); 952 break; 953 } 954 955 return pid; 956 } 957 958 #endif 959 960 961 nxt_int_t 962 nxt_process_daemon(nxt_task_t *task) 963 { 964 nxt_fd_t fd; 965 nxt_pid_t pid; 966 const char *msg; 967 968 fd = -1; 969 970 /* 971 * fork() followed by a parent process's exit() detaches a child process 972 * from an init script or terminal shell process which has started the 973 * parent process and allows the child process to run in background. 974 */ 975 976 pid = fork(); 977 978 switch (pid) { 979 980 case -1: 981 msg = "fork() failed %E"; 982 goto fail; 983 984 case 0: 985 /* A child. */ 986 break; 987 988 default: 989 /* A parent. */ 990 nxt_debug(task, "fork(): %PI", pid); 991 exit(0); 992 nxt_unreachable(); 993 } 994 995 nxt_pid = getpid(); 996 997 /* Clean inherited cached thread tid. */ 998 task->thread->tid = 0; 999 1000 nxt_debug(task, "daemon"); 1001 1002 /* Detach from controlling terminal. */ 1003 1004 if (setsid() == -1) { 1005 nxt_alert(task, "setsid() failed %E", nxt_errno); 1006 return NXT_ERROR; 1007 } 1008 1009 /* 1010 * Reset file mode creation mask: any access 1011 * rights can be set on file creation. 1012 */ 1013 umask(0); 1014 1015 /* Redirect STDIN and STDOUT to the "/dev/null". */ 1016 1017 fd = open("/dev/null", O_RDWR); 1018 if (fd == -1) { 1019 msg = "open(\"/dev/null\") failed %E"; 1020 goto fail; 1021 } 1022 1023 if (dup2(fd, STDIN_FILENO) == -1) { 1024 msg = "dup2(\"/dev/null\", STDIN) failed %E"; 1025 goto fail; 1026 } 1027 1028 if (dup2(fd, STDOUT_FILENO) == -1) { 1029 msg = "dup2(\"/dev/null\", STDOUT) failed %E"; 1030 goto fail; 1031 } 1032 1033 if (fd > STDERR_FILENO) { 1034 nxt_fd_close(fd); 1035 } 1036 1037 return NXT_OK; 1038 1039 fail: 1040 1041 nxt_alert(task, msg, nxt_errno); 1042 1043 if (fd != -1) { 1044 nxt_fd_close(fd); 1045 } 1046 1047 return NXT_ERROR; 1048 } 1049 1050 1051 void 1052 nxt_nanosleep(nxt_nsec_t ns) 1053 { 1054 struct timespec ts; 1055 1056 ts.tv_sec = ns / 1000000000; 1057 ts.tv_nsec = ns % 1000000000; 1058 1059 (void) nanosleep(&ts, NULL); 1060 } 1061 1062 1063 void 1064 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) 1065 { 1066 process->use_count += i; 1067 1068 if (process->use_count == 0) { 1069 nxt_runtime_process_release(task->thread->runtime, process); 1070 } 1071 } 1072 1073 1074 void 1075 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port) 1076 { 1077 nxt_assert(port->process == NULL); 1078 1079 port->process = process; 1080 nxt_queue_insert_tail(&process->ports, &port->link); 1081 1082 nxt_process_use(task, process, 1); 1083 } 1084 1085 1086 nxt_process_type_t 1087 nxt_process_type(nxt_process_t *process) 1088 { 1089 return nxt_queue_is_empty(&process->ports) ? 0 : 1090 (nxt_process_port_first(process))->type; 1091 } 1092 1093 1094 void 1095 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) 1096 { 1097 nxt_port_t *port; 1098 1099 nxt_process_port_each(process, port) { 1100 1101 nxt_port_close(task, port); 1102 1103 nxt_runtime_port_remove(task, port); 1104 1105 } nxt_process_port_loop; 1106 } 1107 1108 1109 void 1110 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status) 1111 { 1112 nxt_uint_t n; 1113 nxt_queue_t *listen; 1114 nxt_runtime_t *rt; 1115 nxt_queue_link_t *link, *next; 1116 nxt_listen_event_t *lev; 1117 nxt_listen_socket_t *ls; 1118 1119 rt = task->thread->runtime; 1120 1121 nxt_debug(task, "close listen connections"); 1122 1123 listen = &task->thread->engine->listen_connections; 1124 1125 for (link = nxt_queue_first(listen); 1126 link != nxt_queue_tail(listen); 1127 link = next) 1128 { 1129 next = nxt_queue_next(link); 1130 lev = nxt_queue_link_data(link, nxt_listen_event_t, link); 1131 nxt_queue_remove(link); 1132 1133 nxt_fd_event_close(task->thread->engine, &lev->socket); 1134 } 1135 1136 if (rt->listen_sockets != NULL) { 1137 1138 ls = rt->listen_sockets->elts; 1139 n = rt->listen_sockets->nelts; 1140 1141 while (n != 0) { 1142 nxt_socket_close(task, ls->socket); 1143 ls->socket = -1; 1144 1145 ls++; 1146 n--; 1147 } 1148 1149 rt->listen_sockets->nelts = 0; 1150 } 1151 1152 nxt_runtime_quit(task, exit_status); 1153 } 1154