Exemplo n.º 1
0
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);
    }    
}
Exemplo n.º 2
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);
    }
}