mail: deobfuscate launch_helper()

13 bytes are not worth the risk of doing something iffy after vfork().
Let's have much clearer code there.

function                                             old     new   delta
launch_helper                                        175     188     +13

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2020-12-17 12:51:58 +01:00
parent b6237c0657
commit b0e7cb4c3f

View File

@ -10,35 +10,35 @@
#include "libbb.h" #include "libbb.h"
#include "mail.h" #include "mail.h"
// generic signal handler // common signal handler
static void signal_handler(int signo) static void signal_handler(int signo)
{ {
#define err signo
if (SIGALRM == signo) { if (SIGALRM == signo) {
bb_simple_error_msg_and_die("timed out"); bb_simple_error_msg_and_die("timed out");
} }
// SIGCHLD. reap zombies // SIGCHLD. reap the zombie if we expect one
if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) { if (G.helper_pid == 0)
if (WIFSIGNALED(err)) return;
bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err)); #define status signo
if (WIFEXITED(err)) { if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) {
G.helper_pid = 0; G.helper_pid = 0;
if (WEXITSTATUS(err)) if (WIFSIGNALED(status))
bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err)); 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 status
#undef err
} }
void FAST_FUNC launch_helper(const char **argv) void FAST_FUNC launch_helper(const char **argv)
{ {
// setup vanilla unidirectional pipes interchange pid_t pid;
int i; struct fd_pair child_out;
int pipes[4]; struct fd_pair child_in;
xpipe(pipes); xpiped_pair(child_out);
xpipe(pipes + 2); xpiped_pair(child_in);
// NB: handler must be installed before vfork // NB: handler must be installed before vfork
bb_signals(0 bb_signals(0
@ -46,25 +46,23 @@ void FAST_FUNC launch_helper(const char **argv)
+ (1 << SIGALRM) + (1 << SIGALRM)
, signal_handler); , signal_handler);
G.helper_pid = xvfork(); G.helper_pid = pid = xvfork();
if (pid == 0) {
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) {
// child // 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 // if parent dies, get SIGTERM
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
// try to execute connection helper // try to execute connection helper
// NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
BB_EXECVP_or_die((char**)argv); 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 // parent goes on
} }