pid_t singularity_fork(unsigned int flags) { int priv_fork = 1; prepare_fork(); if ( flags == 0 || geteuid() == 0 ) { priv_fork = 0; } singularity_message(VERBOSE2, "Forking child process\n"); if ( priv_fork == 1 ) { singularity_priv_escalate(); } child_pid = fork_ns(flags); if ( priv_fork == 1 ) { singularity_priv_drop(); } if ( child_pid == 0 ) { singularity_message(VERBOSE2, "Hello from child process\n"); prepare_pipes_child(); singularity_wait_for_go_ahead(); return(child_pid); } else if ( child_pid > 0 ) { singularity_message(VERBOSE2, "Hello from parent process\n"); prepare_pipes_parent(); /* Set signal mask to block all signals while we set up sig actions */ sigset_t blocked_mask, old_mask; sigfillset(&blocked_mask); sigprocmask(SIG_SETMASK, &blocked_mask, &old_mask); /* Now that we can't receive any signals, install signal handlers for all signals we want to catch */ install_generic_signal_handle(); install_sigchld_signal_handle(); /* Set signal mask back to the original mask, unblocking the blocked signals */ sigprocmask(SIG_SETMASK, &old_mask, NULL); /* Set fds[n].fd to the read pipes created earlier */ 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; /* Drop privs if we're SUID */ if ( singularity_suid_enabled() ) { singularity_message(DEBUG, "Dropping permissions\n"); singularity_priv_drop(); } /* Allow child process to continue */ singularity_signal_go_ahead(0); return(child_pid); } else { singularity_message(ERROR, "Failed to fork child process: %s\n", strerror(errno)); ABORT(255); } }
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); } }