int main(int argc, char **argv) { struct image_object image; singularity_config_init(); singularity_suid_init(); singularity_priv_init(); singularity_registry_init(); singularity_priv_drop(); singularity_runtime_autofs(); if ( singularity_registry_get("WRITABLE") != NULL ) { singularity_message(VERBOSE3, "Instantiating writable container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDWR); } else { singularity_message(VERBOSE3, "Instantiating read only container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDONLY); } if ( is_owner(CONTAINER_MOUNTDIR, 0) != 0 ) { singularity_message(ERROR, "Root must own container mount directory: %s\n", CONTAINER_MOUNTDIR); ABORT(255); } singularity_runtime_ns(SR_NS_MNT); singularity_image_mount(&image, CONTAINER_MOUNTDIR); singularity_runtime_overlayfs(); singularity_priv_drop_perm(); envar_set("SINGULARITY_MOUNTPOINT", CONTAINER_FINALDIR, 1); if ( argc > 1 ) { singularity_message(VERBOSE, "Running command: %s\n", argv[1]); singularity_message(DEBUG, "Calling exec...\n"); execvp(argv[1], &argv[1]); // Flawfinder: ignore (Yes flawfinder, we are exec'ing) singularity_message(ERROR, "Exec failed: %s: %s\n", argv[1], strerror(errno)); ABORT(255); } else { singularity_message(INFO, "%s is mounted at: %s\n\n", singularity_image_name(&image), CONTAINER_FINALDIR); envar_set("PS1", "Singularity> ", 1); execl("/bin/sh", "/bin/sh", NULL); // Flawfinder: ignore (Yes flawfinder, this is what we want, sheesh, so demanding!) singularity_message(ERROR, "Exec of /bin/sh failed: %s\n", strerror(errno)); ABORT(255); } return(0); }
int singularity_action_do(int argc, char **argv) { singularity_priv_drop_perm(); singularity_message(DEBUG, "Trying to change directory to where we started\n"); char *target_pwd = envar_path("SINGULARITY_TARGET_PWD"); if (!target_pwd || (chdir(target_pwd) < 0)) { if ( chdir(cwd_path) < 0 ) { char *homedir; singularity_message(DEBUG, "Failed changing directory to: %s\n", cwd_path); singularity_message(VERBOSE2, "Changing to home directory\n"); singularity_message(DEBUG, "Obtaining user's homedir\n"); homedir = get_homedir(NULL); if ( ( homedir != NULL ) && ( chdir(homedir) < 0 ) ) { singularity_message(WARNING, "Could not chdir to home directory: %s\n", homedir); } } } free(target_pwd); if ( action == ACTION_SHELL ) { singularity_message(DEBUG, "Running action: shell\n"); action_shell_do(argc, argv); } else if ( action == ACTION_EXEC ) { singularity_message(DEBUG, "Running action: exec\n"); action_exec_do(argc, argv); } else if ( action == ACTION_RUN ) { singularity_message(DEBUG, "Running action: run\n"); action_run_do(argc, argv); } else if ( action == ACTION_TEST ) { singularity_message(DEBUG, "Running action: test\n"); action_test_do(argc, argv); } else if ( action == ACTION_START ) { singularity_message(DEBUG, "Running action: start\n"); action_start_do(argc, argv); } else if ( action == ACTION_STOP ) { singularity_message(DEBUG, "Running action: stop\n"); action_stop_do(argc, argv); } singularity_message(ERROR, "Called singularity_action_do() without singularity_action_init()\n"); return(-1); }
int main(int argc, char **argv) { int i, cleanupd_fd; struct tempfile *stdout_log, *stderr_log, *singularity_debug; struct image_object image; pid_t child; siginfo_t siginfo; struct stat filestat; singularity_config_init(); singularity_suid_init(); singularity_priv_init(); singularity_registry_init(); singularity_priv_drop(); singularity_runtime_autofs(); singularity_registry_set("UNSHARE_PID", "1"); singularity_registry_set("UNSHARE_IPC", "1"); if ( singularity_registry_get("INSTANCE_BOOT") != NULL ) { singularity_registry_set("CONTAIN", "1"); } singularity_cleanupd(); if ( singularity_registry_get("WRITABLE") != NULL ) { singularity_message(VERBOSE3, "Instantiating writable container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDWR); } else { singularity_message(VERBOSE3, "Instantiating read only container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDONLY); } singularity_runtime_ns(SR_NS_ALL); singularity_sessiondir(); singularity_image_mount(&image, CONTAINER_MOUNTDIR); action_ready(); singularity_runtime_overlayfs(); singularity_runtime_mounts(); singularity_runtime_files(); /* After this point, we are running as PID 1 inside PID NS */ singularity_message(DEBUG, "Preparing sinit daemon\n"); singularity_registry_set("ROOTFS", CONTAINER_FINALDIR); singularity_daemon_init(); singularity_message(DEBUG, "Entering chroot environment\n"); singularity_runtime_enter(); singularity_priv_drop_perm(); if ( envclean() != 0 ) { singularity_message(ERROR, "Failed sanitizing the environment\n"); ABORT(255); } if ( chdir("/") < 0 ) { singularity_message(ERROR, "Can't change directory to /\n"); } setsid(); umask(0); cleanupd_fd = atoi(singularity_registry_get("CLEANUPD_FD")); if ( singularity_registry_get("INSTANCE_BOOT") != NULL ) { int pipes[2]; if ( pipe2(pipes, O_CLOEXEC) < 0 ) { singularity_signal_go_ahead(255); return(0); } if ( fork() == 0 ) { /* wait a broken pipe which mean exec success */ struct pollfd pfd; pfd.fd = pipes[0]; pfd.events = POLLRDHUP; close(pipes[1]); while( poll(&pfd, 1, 1000) >= 0 ) { if ( pfd.revents == POLLHUP ) break; } singularity_signal_go_ahead(0); /* wait /sbin/init install signal handler */ usleep(20000); return(0); } else { close(pipes[0]); if ( is_exec("/sbin/init") == 0 ) { argv[1] = NULL; if ( execv("/sbin/init", argv) < 0 ) { // Flawfinder: ignore singularity_message(ERROR, "Exec of /sbin/init failed\n"); } } else { singularity_message(ERROR, "/sbin/init not present in container\n"); } /* send exit status and implicitly kill polling child */ singularity_signal_go_ahead(255); return(0); } } /* set program name */ if ( prctl(PR_SET_NAME, "sinit", 0, 0, 0) < 0 ) { singularity_message(ERROR, "Failed to set program name\n"); ABORT(255); } singularity_install_signal_handler(); /* Close all open fd's that may be present besides daemon info file fd */ singularity_message(DEBUG, "Closing open fd's\n"); for( i = sysconf(_SC_OPEN_MAX); i > 2; i-- ) { if ( i != cleanupd_fd ) { if ( fstat(i, &filestat) == 0 ) { if ( S_ISFIFO(filestat.st_mode) != 0 ) { continue; } } close(i); } } singularity_debug = make_logfile("singularity-debug"); stdout_log = make_logfile("stdout"); stderr_log = make_logfile("stderr"); for( i = 0; i <= 2; i++ ) { close(i); } if ( chdir("/") < 0 ) { singularity_message(ERROR, "Can't change directory to /\n"); } setsid(); umask(0); /* set program name */ if ( prctl(PR_SET_NAME, "sinit", 0, 0, 0) < 0 ) { singularity_message(ERROR, "Failed to set program name\n"); ABORT(255); } child = fork(); if ( child == 0 ) { /* Make standard output and standard error files to log stdout & stderr into */ if ( stdout_log != NULL ) { if ( -1 == dup2(stdout_log->fd, 1) ) { singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno)); ABORT(255); } } if ( stderr_log != NULL ) { if ( -1 == dup2(stderr_log->fd, 2) ) { singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno)); ABORT(255); } } /* Unblock signals and execute startscript */ singularity_unblock_signals(); if ( is_exec("/.singularity.d/actions/start") == 0 ) { singularity_message(DEBUG, "Exec'ing /.singularity.d/actions/start\n"); if ( execv("/.singularity.d/actions/start", argv) < 0 ) { // Flawfinder: ignore singularity_message(ERROR, "Failed to execv() /.singularity.d/actions/start: %s\n", strerror(errno)); ABORT(CHILD_FAILED); } } else { singularity_message(VERBOSE, "Instance start script not found\n"); kill(1, SIGCONT); } } else if ( child > 0 ) { if ( singularity_debug != NULL ) { if ( -1 == dup2(singularity_debug->fd, 2) ) { singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno)); ABORT(255); } } singularity_message(DEBUG, "Waiting for signals\n"); /* send a SIGALRM if start script doesn't send SIGCONT within 1 seconds */ alarm(1); while (1) { if ( singularity_handle_signals(&siginfo) < 0 ) { singularity_signal_go_ahead(255); break; } if ( siginfo.si_signo == SIGCHLD ) { singularity_message(DEBUG, "Child exited\n"); if ( siginfo.si_pid == 2 && siginfo.si_status == CHILD_FAILED ) { singularity_signal_go_ahead(CHILD_FAILED); break; } } else if ( siginfo.si_signo == SIGCONT && siginfo.si_pid == 2 ) { /* start script correctly exec */ singularity_signal_go_ahead(0); started = 1; } else if ( siginfo.si_signo == SIGALRM && started == 0 ) { /* don't receive SIGCONT, start script modified/replaced ? */ singularity_message(ERROR, "Start script doesn't send SIGCONT\n"); singularity_signal_go_ahead(255); break; } } } else { singularity_message(ERROR, "Failed to execute start script\n"); singularity_signal_go_ahead(255); } return(0); }
pid_t singularity_fork(void) { int pipes[2]; // From: signal_pre_fork() if ( pipe2(pipes, O_CLOEXEC) < 0 ) { singularity_message(ERROR, "Failed to create watchdog communication pipes: %s\n", strerror(errno)); ABORT(255); } watchdog_rpipe = pipes[0]; watchdog_wpipe = pipes[1]; prepare_fork(); // Fork child singularity_message(VERBOSE2, "Forking child process\n"); child_pid = fork(); if ( child_pid == 0 ) { singularity_message(VERBOSE2, "Hello from child process\n"); if (watchdog_wpipe != -1) { singularity_message(DEBUG, "Closing watchdog write pipe\n"); close(watchdog_wpipe); } watchdog_wpipe = -1; wait_for_go_ahead(); singularity_message(DEBUG, "Child process is returning control to process thread\n"); return(0); } else if ( child_pid > 0 ) { singularity_message(VERBOSE2, "Hello from parent process\n"); // From: setup_signal_handler() sigset_t blocked_mask, old_mask, empty_mask; sigfillset(&blocked_mask); sigemptyset(&empty_mask); sigprocmask(SIG_SETMASK, &blocked_mask, &old_mask); struct sigaction action; action.sa_sigaction = &handle_signal; action.sa_flags = SA_SIGINFO|SA_RESTART; // All our handlers are signal safe. action.sa_mask = empty_mask; struct pollfd fds[3]; int retval; int child_ok = 1; singularity_message(DEBUG, "Assigning sigaction()s\n"); if ( -1 == sigaction(SIGINT, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGINT signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGQUIT, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGQUIT signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGTERM, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGTERM signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGHUP, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGHUP signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGUSR1, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGUSR1 signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGUSR2, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGUSR2 signal handler: %s\n", strerror(errno)); ABORT(255); } action.sa_sigaction = &handle_sigchld; if ( -1 == sigaction(SIGCHLD, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGCHLD signal handler: %s\n", strerror(errno)); ABORT(255); } singularity_message(DEBUG, "Creating generic signal pipes\n"); if ( -1 == pipe2(pipes, O_CLOEXEC) ) { singularity_message(ERROR, "Failed to create communication pipes: %s\n", strerror(errno)); ABORT(255); } generic_signal_rpipe = pipes[0]; generic_signal_wpipe = pipes[1]; singularity_message(DEBUG, "Creating sigchld signal pipes\n"); if ( -1 == pipe2(pipes, O_CLOEXEC) ) { singularity_message(ERROR, "Failed to create communication pipes: %s\n", strerror(errno)); ABORT(255); } sigchld_signal_rpipe = pipes[0]; sigchld_signal_wpipe = pipes[1]; sigprocmask(SIG_SETMASK, &old_mask, NULL); fds[0].fd = sigchld_signal_rpipe; fds[0].events = POLLIN; fds[0].revents = 0; fds[1].fd = generic_signal_rpipe; fds[1].events = POLLIN; fds[1].revents = 0; fds[2].fd = watchdog_rpipe; fds[2].events = POLLIN; fds[2].revents = 0; // At this point, we have nothing to do but wait on some external action. // We should never again need to increase our privileges. Drop privs // permanently and then indicate the child can proceed. if ( singularity_priv_is_suid() == 0 ) { singularity_message(DEBUG, "Reached drop_perm in fork.c\n"); singularity_priv_drop_perm(); } signal_go_ahead(0); do { singularity_message(DEBUG, "Waiting on signal from watchdog\n"); while ( -1 == (retval = poll(fds, watchdog_rpipe == -1 ? 2 : 3, -1)) && errno == EINTR ) {} if ( -1 == retval ) { singularity_message(ERROR, "Failed to wait for file descriptors: %s\n", strerror(errno)); ABORT(255); } if (fds[0].revents) { child_ok = 0; } if (fds[1].revents) { char signum = SIGKILL; while (-1 == (retval = read(generic_signal_rpipe, &signum, 1)) && errno == EINTR) {} // Flawfinder: ignore if (-1 == retval) { singularity_message(ERROR, "Failed to read from signal handler pipe: %s\n", strerror(errno)); ABORT(255); } kill(child_pid, signum); } if (watchdog_rpipe != -1 && fds[2].revents) { // Parent died. Immediately kill child. NOTE that this only // works if the child has also dropped privileges. kill(child_pid, SIGKILL); close(watchdog_rpipe); watchdog_rpipe = -1; } } while ( child_ok ); singularity_message(DEBUG, "Parent process is exiting\n"); return(child_pid); } else { singularity_message(ERROR, "Failed to fork child process\n"); ABORT(255); } }
static int setup_container(spank_t spank) { int rc; struct image_object image; char *command = NULL; if ((rc = setup_container_environment(spank)) != 0) { return rc; } /* * Ugg, singularity_* calls tend to call ABORT(255), which translates to * exit(255), all over the place. The slurm SPANK hook API may not * expect such sudden death of the pending slurm task. I've left * a bunch of following "return rc;" commented out, as the failure * conditions from singularity_* calls isn't clear to me. */ // Before we do anything, check privileges and drop permission singularity_priv_init(); singularity_priv_drop(); singularity_message(VERBOSE, "Running Slurm/Singularity integration " "plugin\n"); if ((rc = singularity_config_init()) != 0) { return rc; } singularity_priv_init(); //TODO singularity_suid_init(argv); singularity_registry_init(); singularity_priv_userns(); singularity_priv_drop(); singularity_cleanupd(); singularity_runtime_ns(SR_NS_ALL); singularity_sessiondir(); image = singularity_image_init(singularity_registry_get("IMAGE")); if ( singularity_registry_get("WRITABLE") == NULL ) { singularity_image_open(&image, O_RDONLY); } else { singularity_image_open(&image, O_RDWR); } singularity_image_check(&image); singularity_image_bind(&image); singularity_image_mount(&image, singularity_runtime_rootfs(NULL)); action_ready(singularity_runtime_rootfs(NULL)); singularity_runtime_overlayfs(); singularity_runtime_mounts(); singularity_runtime_files(); singularity_runtime_enter(); singularity_runtime_environment(); singularity_priv_drop_perm(); if ((rc = setup_container_cwd()) < 0) { singularity_message(ERROR, "Could not obtain current directory.\n"); return rc; } envar_set("SINGULARITY_CONTAINER", singularity_image_name(&image), 1); // Legacy PS1 support envar_set("SINGULARITY_NAME", singularity_image_name(&image), 1); envar_set("SINGULARITY_SHELL", singularity_registry_get("SHELL"), 1); command = singularity_registry_get("COMMAND"); singularity_message(LOG, "USER=%s, IMAGE='%s', COMMAND='%s'\n", singularity_priv_getuser(), singularity_image_name(&image), singularity_registry_get("COMMAND")); // At this point, the current process is in the runtime container environment. // Return control flow back to Slurm: when execv is invoked, it'll be done from // within the container. return 0; }