From 0684aea7453186e6f90ce4b6b8c5bcca68f0d1b9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Vr=C3=A1til?= Date: Wed, 12 Sep 2018 17:05:31 +0200 Subject: [PATCH] exec: fix potential deadlock after fork() POSIX forbids calling functions which are not thread-safe like setenv() after fork() in multi-threaded programs. It happens to work just fine with some libc implementations, but it causes a deadlock in the child process with uClibc for example. The proper way to pass new environment variables to the child process is to update parent's environment before the fork(), so that the child inherits the updated environment and then undo the changes in the parent process again. Signed-off-by: Florian Forster --- src/exec.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/exec.c b/src/exec.c index a4de6730..a38026ef 100644 --- a/src/exec.c +++ b/src/exec.c @@ -273,6 +273,19 @@ static void set_environment(void) /* {{{ */ #endif } /* }}} void set_environment */ +static void unset_environment(void) /* {{{ */ +{ +#ifdef HAVE_SETENV + unsetenv("COLLECTD_INTERVAL"); + unsetenv("COLLECTD_HOSTNAME"); +#else + snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL"); + putenv(env_interval); + snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME"); + putenv(env_hostname); +#endif +} /* }}} void unset_environment */ + __attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid, int gid, int egid) /* {{{ */ { @@ -481,6 +494,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, goto failed; } + set_environment(); + pid = fork(); if (pid < 0) { ERROR("exec plugin: fork failed: %s", @@ -516,8 +531,6 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, close(fd_pipe_err[1]); } - set_environment(); - /* Unblock all signals */ reset_signal_mask(); @@ -525,6 +538,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, /* does not return */ } + unset_environment(); + close(fd_pipe_in[0]); close(fd_pipe_out[1]); close(fd_pipe_err[1]); @@ -547,6 +562,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, return pid; failed: + unset_environment(); + close_pipe(fd_pipe_in); close_pipe(fd_pipe_out); close_pipe(fd_pipe_err); -- 2.11.0