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