static void start_child(int pipenum, jmp_buf *env, int syncpipe[2], struct nsenter_config *config) { int len; int childpid; char buf[PATH_MAX]; uint8_t syncbyte = 1; // We must fork to actually enter the PID namespace, use CLONE_PARENT // so the child can have the right parent, and we don't need to forward // the child's exit code or resend its death signal. childpid = clone_parent(env, config->cloneflags); if (childpid < 0) { pr_perror("Unable to fork"); exit(1); } // update uid_map and gid_map for the child process if they // were provided update_process_uidmap(childpid, config->uidmap, config->uidmap_len); update_process_gidmap(childpid, config->is_setgroup, config->gidmap, config->gidmap_len); // Send the sync signal to the child close(syncpipe[0]); syncbyte = 1; if (write(syncpipe[1], &syncbyte, 1) != 1) { pr_perror("failed to write sync byte to child"); exit(1); } // Send the child pid back to our parent len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", childpid); if ((len < 0) || (write(pipenum, buf, len) != len)) { pr_perror("Unable to send a child pid"); kill(childpid, SIGKILL); exit(1); } exit(0); }
void nsexec() { char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" }; const int num = sizeof(namespaces) / sizeof(char *); jmp_buf env; char buf[PATH_MAX], *val; int i, tfd, child, len, consolefd = -1; pid_t pid; char *console; val = getenv("_LIBCONTAINER_INITPID"); if (val == NULL) return; pid = atoi(val); snprintf(buf, sizeof(buf), "%d", pid); if (strcmp(val, buf)) { pr_perror("Unable to parse _LIBCONTAINER_INITPID"); exit(1); } console = getenv("_LIBCONTAINER_CONSOLE_PATH"); if (console != NULL) { consolefd = open(console, O_RDWR); if (consolefd < 0) { pr_perror("Failed to open console %s", console); exit(1); } } /* Check that the specified process exists */ snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid); tfd = open(buf, O_DIRECTORY | O_RDONLY); if (tfd == -1) { pr_perror("Failed to open \"%s\"", buf); exit(1); } for (i = 0; i < num; i++) { struct stat st; int fd; /* Symlinks on all namespaces exist for dead processes, but they can't be opened */ if (fstatat(tfd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) { // Ignore nonexistent namespaces. if (errno == ENOENT) continue; } fd = openat(tfd, namespaces[i], O_RDONLY); if (fd == -1) { pr_perror("Failed to open ns file %s for ns %s", buf, namespaces[i]); exit(1); } // Set the namespace. if (setns(fd, 0) == -1) { pr_perror("Failed to setns for %s", namespaces[i]); exit(1); } close(fd); } if (setjmp(env) == 1) { if (setsid() == -1) { pr_perror("setsid failed"); exit(1); } if (consolefd != -1) { if (ioctl(consolefd, TIOCSCTTY, 0) == -1) { pr_perror("ioctl TIOCSCTTY failed"); exit(1); } if (dup2(consolefd, STDIN_FILENO) != STDIN_FILENO) { pr_perror("Failed to dup 0"); exit(1); } if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) { pr_perror("Failed to dup 1"); exit(1); } if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) { pr_perror("Failed to dup 2"); exit(1); } } // Finish executing, let the Go runtime take over. return; } child = clone_parent(&env); if (child < 0) { pr_perror("Unable to fork"); exit(1); } len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child); if (write(3, buf, len) != len) { pr_perror("Unable to send a child pid"); kill(child, SIGKILL); exit(1); } exit(0); }