int main(int argc, char *argv[]) { int c; unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS; char ttyname0[256], ttyname1[256], ttyname2[256]; int status; int ret; int pid; char *default_args[] = {"/bin/sh", NULL}; char buf[1]; int pipe1[2], // child tells parent it has unshared pipe2[2]; // parent tells child it is mapped and may proceed memset(ttyname0, '\0', sizeof(ttyname0)); memset(ttyname1, '\0', sizeof(ttyname1)); memset(ttyname2, '\0', sizeof(ttyname2)); if (isatty(0)) { ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0)); if (ret < 0) { perror("unable to open stdin."); exit(1); } ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1)); if (ret < 0) { printf("Warning: unable to open stdout, continuing."); memset(ttyname1, '\0', sizeof(ttyname1)); } ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2)); if (ret < 0) { printf("Warning: unable to open stderr, continuing."); memset(ttyname2, '\0', sizeof(ttyname2)); } } lxc_list_init(&active_map); while ((c = getopt(argc, argv, "m:h")) != EOF) { switch (c) { case 'm': if (parse_map(optarg)) usage(argv[0]); break; case 'h': default: usage(argv[0]); } }; if (lxc_list_empty(&active_map)) { if (find_default_map()) { fprintf(stderr, "You have no allocated subuids or subgids\n"); exit(1); } } argv = &argv[optind]; argc = argc - optind; if (argc < 1) { argv = default_args; argc = 1; } if (pipe(pipe1) < 0 || pipe(pipe2) < 0) { perror("pipe"); exit(1); } if ((pid = fork()) == 0) { // Child. close(pipe1[0]); close(pipe2[1]); opentty(ttyname0, 0); opentty(ttyname1, 1); opentty(ttyname2, 2); ret = unshare(flags); if (ret < 0) { perror("unshare"); return 1; } buf[0] = '1'; if (write(pipe1[1], buf, 1) < 1) { perror("write pipe"); exit(1); } if (read(pipe2[0], buf, 1) < 1) { perror("read pipe"); exit(1); } if (buf[0] != '1') { fprintf(stderr, "parent had an error, child exiting\n"); exit(1); } close(pipe1[1]); close(pipe2[0]); return do_child((void*)argv); } close(pipe1[1]); close(pipe2[0]); if (read(pipe1[0], buf, 1) < 1) { perror("read pipe"); exit(1); } buf[0] = '1'; if (lxc_map_ids(&active_map, pid)) { fprintf(stderr, "error mapping child\n"); ret = 0; } if (write(pipe2[1], buf, 1) < 0) { perror("write to pipe"); exit(1); } if ((ret = waitpid(pid, &status, __WALL)) < 0) { printf("waitpid() returns %d, errno %d\n", ret, errno); exit(1); } exit(WEXITSTATUS(status)); }
int main(int argc, char *argv[]) { int c, pid, ret, status; char buf[1]; int pipe_fds1[2], /* child tells parent it has unshared */ pipe_fds2[2]; /* parent tells child it is mapped and may proceed */ unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS; char ttyname0[256] = {0}, ttyname1[256] = {0}, ttyname2[256] = {0}; char *default_args[] = {"/bin/sh", NULL}; lxc_log_fd = STDERR_FILENO; if (isatty(STDIN_FILENO)) { ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0)); if (ret < 0) { CMD_SYSERROR("Failed to open stdin"); _exit(EXIT_FAILURE); } ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1)); if (ret < 0) { CMD_SYSINFO("Failed to open stdout. Continuing"); ttyname1[0] = '\0'; } ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2)); if (ret < 0) { CMD_SYSINFO("Failed to open stderr. Continuing"); ttyname2[0] = '\0'; } } lxc_list_init(&active_map); while ((c = getopt(argc, argv, "m:h")) != EOF) { switch (c) { case 'm': ret = parse_map(optarg); if (ret < 0) { usage(argv[0]); _exit(EXIT_FAILURE); } break; case 'h': usage(argv[0]); _exit(EXIT_SUCCESS); default: usage(argv[0]); _exit(EXIT_FAILURE); } }; if (lxc_list_empty(&active_map)) { ret = find_default_map(); if (ret < 0) { fprintf(stderr, "Failed to find subuid or subgid allocation\n"); _exit(EXIT_FAILURE); } } argv = &argv[optind]; argc = argc - optind; if (argc < 1) argv = default_args; ret = pipe2(pipe_fds1, O_CLOEXEC); if (ret < 0) { CMD_SYSERROR("Failed to open new pipe"); _exit(EXIT_FAILURE); } ret = pipe2(pipe_fds2, O_CLOEXEC); if (ret < 0) { CMD_SYSERROR("Failed to open new pipe"); close(pipe_fds1[0]); close(pipe_fds1[1]); _exit(EXIT_FAILURE); } pid = fork(); if (pid < 0) { close(pipe_fds1[0]); close(pipe_fds1[1]); close(pipe_fds2[0]); close(pipe_fds2[1]); _exit(EXIT_FAILURE); } if (pid == 0) { close(pipe_fds1[0]); close(pipe_fds2[1]); opentty(ttyname0, STDIN_FILENO); opentty(ttyname1, STDOUT_FILENO); opentty(ttyname2, STDERR_FILENO); ret = unshare(flags); if (ret < 0) { CMD_SYSERROR("Failed to unshare mount and user namespace"); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } buf[0] = '1'; ret = lxc_write_nointr(pipe_fds1[1], buf, 1); if (ret != 1) { CMD_SYSERROR("Failed to write to pipe file descriptor %d", pipe_fds1[1]); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } ret = lxc_read_nointr(pipe_fds2[0], buf, 1); if (ret != 1) { CMD_SYSERROR("Failed to read from pipe file descriptor %d", pipe_fds2[0]); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } close(pipe_fds1[1]); close(pipe_fds2[0]); if (buf[0] != '1') { fprintf(stderr, "Received unexpected value from parent process\n"); _exit(EXIT_FAILURE); } ret = do_child((void *)argv); if (ret < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); } close(pipe_fds1[1]); close(pipe_fds2[0]); ret = lxc_read_nointr(pipe_fds1[0], buf, 1); if (ret <= 0) CMD_SYSERROR("Failed to read from pipe file descriptor %d", pipe_fds1[0]); buf[0] = '1'; ret = lxc_map_ids(&active_map, pid); if (ret < 0) fprintf(stderr, "Failed to write id mapping for child process\n"); ret = lxc_write_nointr(pipe_fds2[1], buf, 1); if (ret < 0) { CMD_SYSERROR("Failed to write to pipe file descriptor %d", pipe_fds2[1]); _exit(EXIT_FAILURE); } ret = waitpid(pid, &status, __WALL); if (ret < 0) { CMD_SYSERROR("Failed to wait on child process"); _exit(EXIT_FAILURE); } _exit(WEXITSTATUS(status)); }