mail: deobfuscate launch_helper()
No binary (build failed)
—
(log yok)
| @@ -10,35 +10,35 @@ | |
| #include "libbb.h" | |
| #include "mail.h" | |
| - | // generic signal handler |
| + | // common signal handler |
| static void signal_handler(int signo) | |
| { | |
| - | #define err signo |
| if (SIGALRM == signo) { | |
| bb_simple_error_msg_and_die("timed out"); | |
| } | |
| - | // SIGCHLD. reap zombies |
| - | if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) { |
| - | if (WIFSIGNALED(err)) |
| - | bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err)); |
| - | if (WIFEXITED(err)) { |
| - | G.helper_pid = 0; |
| - | if (WEXITSTATUS(err)) |
| - | bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err)); |
| - | } |
| + | // SIGCHLD. reap the zombie if we expect one |
| + | if (G.helper_pid == 0) |
| + | return; |
| + | #define status signo |
| + | if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) { |
| + | G.helper_pid = 0; |
| + | if (WIFSIGNALED(status)) |
| + | bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(status)); |
| + | if (WIFEXITED(status) && WEXITSTATUS(status) != 0) |
| + | bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(status)); |
| } | |
| - | #undef err |
| + | #undef status |
| } | |
| void FAST_FUNC launch_helper(const char **argv) | |
| { | |
| - | // setup vanilla unidirectional pipes interchange |
| - | int i; |
| - | int pipes[4]; |
| + | pid_t pid; |
| + | struct fd_pair child_out; |
| + | struct fd_pair child_in; |
| - | xpipe(pipes); |
| - | xpipe(pipes + 2); |
| + | xpiped_pair(child_out); |
| + | xpiped_pair(child_in); |
| // NB: handler must be installed before vfork | |
| bb_signals(0 | |
| @@ -46,25 +46,23 @@ void FAST_FUNC launch_helper(const char **argv) | |
| + (1 << SIGALRM) | |
| , signal_handler); | |
| - | G.helper_pid = xvfork(); |
| - | |
| - | i = (!G.helper_pid) * 2; // for parent:0, for child:2 |
| - | close(pipes[i + 1]); // 1 or 3 - closing one write end |
| - | close(pipes[2 - i]); // 2 or 0 - closing one read end |
| - | xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end |
| - | xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end |
| - | // End result: |
| - | // parent stdout [3] -> child stdin [2] |
| - | // child stdout [1] -> parent stdin [0] |
| - | |
| - | if (!G.helper_pid) { |
| + | G.helper_pid = pid = xvfork(); |
| + | if (pid == 0) { |
| // child | |
| + | close(child_in.wr); |
| + | close(child_out.rd); |
| + | xmove_fd(child_in.rd, STDIN_FILENO); |
| + | xmove_fd(child_out.wr, STDOUT_FILENO); |
| // if parent dies, get SIGTERM | |
| prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); | |
| // try to execute connection helper | |
| // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec | |
| BB_EXECVP_or_die((char**)argv); | |
| } | |
| + | close(child_out.wr); |
| + | close(child_in.rd); |
| + | xmove_fd(child_out.rd, STDIN_FILENO); |
| + | xmove_fd(child_in.wr, STDOUT_FILENO); |
| // parent goes on | |
| } | |