[Libguestfs] [nbdkit PATCH 2/3] sh: Avoid setenv after fork

Richard W.M. Jones rjones at redhat.com
Fri Aug 2 07:41:43 UTC 2019


On Thu, Aug 01, 2019 at 10:42:58PM -0500, Eric Blake wrote:
> setenv() is not async-signal-safe and as such should not be used
> between fork/exec of a multi-threaded app: if one thread is
> manipulating the current environment (which may entail obtaining a
> malloc() mutex) when another thread calls fork(), the resulting
> child's attempt to use setenv() could deadlock or see a broken environ
> because the thread owning the lock no longer exists to release it.
> Besides, it is more efficient to update the environment exactly once
> in the parent, rather than after every fork().
> 
> While at it, check for (unlikely) failure of setenv.
> 
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
>  plugins/sh/call.c | 3 ---
>  plugins/sh/sh.c   | 6 ++++++
>  2 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/plugins/sh/call.c b/plugins/sh/call.c
> index 871de5c6..9b8b48e2 100644
> --- a/plugins/sh/call.c
> +++ b/plugins/sh/call.c
> @@ -127,9 +127,6 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin */
>      /* Restore SIGPIPE back to SIG_DFL, since shell can't undo SIG_IGN */
>      signal (SIGPIPE, SIG_DFL);
> 
> -    /* Set $tmpdir for the script. */
> -    setenv ("tmpdir", tmpdir, 1);
> -
>      execvp (argv[0], (char **) argv);
>      perror (argv[0]);
>      _exit (EXIT_FAILURE);
> diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
> index 737c38cf..e3d3c2f1 100644
> --- a/plugins/sh/sh.c
> +++ b/plugins/sh/sh.c
> @@ -60,6 +60,12 @@ sh_load (void)
>      nbdkit_error ("mkdtemp: /tmp: %m");
>      exit (EXIT_FAILURE);
>    }
> +  /* Set $tmpdir for the script. */
> +  if (setenv ("tmpdir", tmpdir, 1) == -1) {
> +    nbdkit_error ("setenv: tmpdir=%s: %m", tmpdir);
> +    exit (EXIT_FAILURE);
> +  }
> +
>    nbdkit_debug ("sh: load: tmpdir: %s", tmpdir);
>  }

This sets $tmpdir in the whole nbdkit process ... which may or may not
be a problem.  It's probably not a problem in reality, but I wonder if
it's better to to use ‘execvpe’ (or more portably but more difficult
to use ‘execve’) to set the environment in the exec call?  I guess
we'd have to copy and extend environ in the parent since we want to
pass existing environment variables through.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html




More information about the Libguestfs mailing list