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
24static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
25static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
26 nxt_process_t *process);
27static nxt_int_t nxt_process_send_created(nxt_task_t *task,
28 nxt_process_t *process);
29static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
30 nxt_process_t *process);
31static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
32 void *data);
33static 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)
37static nxt_int_t nxt_process_chroot(nxt_task_t *task, const char *path);
38#endif
39
40#if (NXT_HAVE_PIVOT_ROOT)
41static nxt_int_t nxt_process_pivot_root(nxt_task_t *task, const char *rootfs);
42static nxt_int_t nxt_process_private_mount(nxt_task_t *task,
43 const char *rootfs);
44#endif
45
46#if (NXT_HAVE_PIVOT_ROOT)
47static int nxt_pivot_root(const char *new_root, const char *old_root);
48#endif
49
50/* A cached process pid. */
51nxt_pid_t nxt_pid;
52
53/* An original parent process pid. */
54nxt_pid_t nxt_ppid;
55
56/* A cached process effective uid */
57nxt_uid_t nxt_euid;

--- 453 unchanged lines hidden (view full) ---

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
538nxt_int_t
539nxt_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
568nxt_int_t
569nxt_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
598static nxt_int_t
599nxt_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
610void
611nxt_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
638static nxt_int_t
639nxt_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
689static nxt_int_t
690nxt_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
729again:
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
812found:
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
825fail:
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
851static int
852nxt_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
860static nxt_int_t
861nxt_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

--- 331 unchanged lines hidden ---