15a16,23 > #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) > #include > #endif > > #if (NXT_HAVE_PIVOT_ROOT) > #include > #endif > 27a36,38 > #if (NXT_HAVE_ISOLATION_ROOTFS) > static nxt_int_t nxt_process_chroot(nxt_task_t *task, const char *path); > #endif 28a40,49 > #if (NXT_HAVE_PIVOT_ROOT) > static nxt_int_t nxt_process_pivot_root(nxt_task_t *task, const char *rootfs); > static nxt_int_t nxt_process_private_mount(nxt_task_t *task, > const char *rootfs); > #endif > > #if (NXT_HAVE_PIVOT_ROOT) > static int nxt_pivot_root(const char *new_root, const char *old_root); > #endif > 497a519,527 > #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) > if (nxt_slow_path(process->isolation.new_privs == 0 > && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)) > { > nxt_alert(task, "failed to set no_new_privs %E", nxt_errno); > return NXT_ERROR; > } > #endif > 501a532,597 > #if (NXT_HAVE_ISOLATION_ROOTFS) > > > #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) > > > nxt_int_t > nxt_process_change_root(nxt_task_t *task, nxt_process_t *process) > { > char *rootfs; > nxt_int_t ret; > > rootfs = (char *) process->isolation.rootfs; > > nxt_debug(task, "change root: %s", rootfs); > > if (NXT_CLONE_MNT(process->isolation.clone.flags)) { > ret = nxt_process_pivot_root(task, rootfs); > } else { > ret = nxt_process_chroot(task, rootfs); > } > > if (nxt_fast_path(ret == NXT_OK)) { > if (nxt_slow_path(chdir("/") < 0)) { > nxt_alert(task, "chdir(\"/\") %E", nxt_errno); > return NXT_ERROR; > } > } > > return ret; > } > > > #else > > > nxt_int_t > nxt_process_change_root(nxt_task_t *task, nxt_process_t *process) > { > char *rootfs; > > rootfs = (char *) process->isolation.rootfs; > > nxt_debug(task, "change root: %s", rootfs); > > if (nxt_fast_path(nxt_process_chroot(task, rootfs) == NXT_OK)) { > if (nxt_slow_path(chdir("/") < 0)) { > nxt_alert(task, "chdir(\"/\") %E", nxt_errno); > return NXT_ERROR; > } > > return NXT_OK; > } > > return NXT_ERROR; > } > > > #endif > > > #endif > > > #if (NXT_HAVE_ISOLATION_ROOTFS) > 502a599,860 > nxt_process_chroot(nxt_task_t *task, const char *path) > { > if (nxt_slow_path(chroot(path) < 0)) { > nxt_alert(task, "chroot(%s) %E", path, nxt_errno); > return NXT_ERROR; > } > > return NXT_OK; > } > > > void > nxt_process_unmount_all(nxt_task_t *task, nxt_process_t *process) > { > size_t i, n; > nxt_array_t *mounts; > nxt_fs_mount_t *mnt; > > nxt_debug(task, "unmount all (%s)", process->name); > > mounts = process->isolation.mounts; > n = mounts->nelts; > mnt = mounts->elts; > > for (i = 0; i < n; i++) { > nxt_fs_unmount(mnt[i].dst); > } > } > > #endif > > > #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) > > /* > * pivot_root(2) can only be safely used with containers, otherwise it can > * umount(2) the global root filesystem and screw up the machine. > */ > > static nxt_int_t > nxt_process_pivot_root(nxt_task_t *task, const char *path) > { > /* > * This implementation makes use of a kernel trick that works for ages > * and now documented in Linux kernel 5. > * https://lore.kernel.org/linux-man/87r24piwhm.fsf@x220.int.ebiederm.org/T/ > */ > > if (nxt_slow_path(mount("", "/", "", MS_SLAVE|MS_REC, "") != 0)) { > nxt_alert(task, "failed to make / a slave mount %E", nxt_errno); > return NXT_ERROR; > } > > if (nxt_slow_path(nxt_process_private_mount(task, path) != NXT_OK)) { > return NXT_ERROR; > } > > if (nxt_slow_path(mount(path, path, "bind", MS_BIND|MS_REC, "") != 0)) { > nxt_alert(task, "error bind mounting rootfs %E", nxt_errno); > return NXT_ERROR; > } > > if (nxt_slow_path(chdir(path) != 0)) { > nxt_alert(task, "failed to chdir(%s) %E", path, nxt_errno); > return NXT_ERROR; > } > > if (nxt_slow_path(nxt_pivot_root(".", ".") != 0)) { > nxt_alert(task, "failed to pivot_root %E", nxt_errno); > return NXT_ERROR; > } > > /* > * Make oldroot a slave mount to avoid unmounts getting propagated to the > * host. > */ > if (nxt_slow_path(mount("", ".", "", MS_SLAVE | MS_REC, NULL) != 0)) { > nxt_alert(task, "failed to bind mount rootfs %E", nxt_errno); > return NXT_ERROR; > } > > if (nxt_slow_path(umount2(".", MNT_DETACH) != 0)) { > nxt_alert(task, "failed to umount old root directory %E", nxt_errno); > return NXT_ERROR; > } > > return NXT_OK; > } > > > static nxt_int_t > nxt_process_private_mount(nxt_task_t *task, const char *rootfs) > { > char *parent_mnt; > FILE *procfile; > u_char **mounts; > size_t len; > uint8_t *shared; > nxt_int_t ret, index, nmounts; > struct mntent *ent; > > static const char *mount_path = "/proc/self/mounts"; > > ret = NXT_ERROR; > ent = NULL; > shared = NULL; > procfile = NULL; > parent_mnt = NULL; > > nmounts = 256; > > mounts = nxt_malloc(nmounts * sizeof(uintptr_t)); > if (nxt_slow_path(mounts == NULL)) { > goto fail; > } > > shared = nxt_malloc(nmounts); > if (nxt_slow_path(shared == NULL)) { > goto fail; > } > > procfile = setmntent(mount_path, "r"); > if (nxt_slow_path(procfile == NULL)) { > nxt_alert(task, "failed to open %s %E", mount_path, nxt_errno); > > goto fail; > } > > index = 0; > > again: > > for ( ; index < nmounts; index++) { > ent = getmntent(procfile); > if (ent == NULL) { > nmounts = index; > break; > } > > mounts[index] = (u_char *) strdup(ent->mnt_dir); > shared[index] = hasmntopt(ent, "shared") != NULL; > } > > if (ent != NULL) { > /* there are still entries to be read */ > > nmounts *= 2; > mounts = nxt_realloc(mounts, nmounts); > if (nxt_slow_path(mounts == NULL)) { > goto fail; > } > > shared = nxt_realloc(shared, nmounts); > if (nxt_slow_path(shared == NULL)) { > goto fail; > } > > goto again; > } > > for (index = 0; index < nmounts; index++) { > if (nxt_strcmp(mounts[index], rootfs) == 0) { > parent_mnt = (char *) rootfs; > break; > } > } > > if (parent_mnt == NULL) { > len = nxt_strlen(rootfs); > > parent_mnt = nxt_malloc(len + 1); > if (parent_mnt == NULL) { > goto fail; > } > > nxt_memcpy(parent_mnt, rootfs, len); > parent_mnt[len] = '\0'; > > if (parent_mnt[len - 1] == '/') { > parent_mnt[len - 1] = '\0'; > len--; > } > > for ( ;; ) { > for (index = 0; index < nmounts; index++) { > if (nxt_strcmp(mounts[index], parent_mnt) == 0) { > goto found; > } > } > > if (len == 1 && parent_mnt[0] == '/') { > nxt_alert(task, "parent mount not found"); > goto fail; > } > > /* parent dir */ > while (parent_mnt[len - 1] != '/' && len > 0) { > len--; > } > > if (nxt_slow_path(len == 0)) { > nxt_alert(task, "parent mount not found"); > goto fail; > } > > if (len == 1) { > parent_mnt[len] = '\0'; /* / */ > } else { > parent_mnt[len - 1] = '\0'; /* / */ > } > } > } > > found: > > if (shared[index]) { > if (nxt_slow_path(mount("", parent_mnt, "", MS_PRIVATE, "") != 0)) { > nxt_alert(task, "mount(\"\", \"%s\", MS_PRIVATE) %E", parent_mnt, > nxt_errno); > > goto fail; > } > } > > ret = NXT_OK; > > fail: > > if (procfile != NULL) { > endmntent(procfile); > } > > if (mounts != NULL) { > for (index = 0; index < nmounts; index++) { > nxt_free(mounts[index]); > } > > nxt_free(mounts); > } > > if (shared != NULL) { > nxt_free(shared); > } > > if (parent_mnt != NULL && parent_mnt != rootfs) { > nxt_free(parent_mnt); > } > > return ret; > } > > > static int > nxt_pivot_root(const char *new_root, const char *old_root) > { > return syscall(__NR_pivot_root, new_root, old_root); > } > > #endif > > > static nxt_int_t