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