[Libguestfs] [PATCH nbdkit 8/9] eval, sh: Set $tmpdir before running the command, instead of globally.

Richard W.M. Jones
Wed, 15 Apr 2020 16:16:49 -0000

The $tmpdir environment variable is used by the eval and sh plugins to
communicate the path to the temporary directory created by the plugin
for shell scripts to use for temporary files.

Previously we set this environment variable globally (in .load()), but
this means the environment variable can be leaked into undesirable
places, eg. into the --run script:

  $ nbdkit sh - --run 'echo tmpdir: $tmpdir' </dev/null
  tmpdir: /tmp/nbdkitshco6MC9

By setting it only just before running the shell command it should
only be visible there.  Note also we no longer use setenv(3), but
instead we manipulate environ.

After this change:

  $ ./nbdkit sh - --run 'echo tmpdir: $tmpdir' </dev/null
  tmpdir:
---
 plugins/sh/call.h   |  2 ++
 plugins/eval/eval.c |  7 +------
 plugins/sh/call.c   | 11 +++++++++++
 plugins/sh/sh.c     |  7 +------
 4 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/plugins/sh/call.h b/plugins/sh/call.h
index 6aa70e56..78305d1e 100644
--- a/plugins/sh/call.h
+++ b/plugins/sh/call.h
@@ -49,4 +49,6 @@ extern exit_code call_write (const char *wbuf, size_t wbuflen,
                              const char **argv)
   __attribute__((__nonnull__ (1, 3)));

+extern char tmpdir[];
+
 #endif /* NBDKIT_CALL_H */
diff --git a/plugins/eval/eval.c b/plugins/eval/eval.c
index f09e49f3..3bc7f2a6 100644
--- a/plugins/eval/eval.c
+++ b/plugins/eval/eval.c
@@ -50,7 +50,7 @@
 #include "call.h"
 #include "methods.h"

-static char tmpdir[] = "/tmp/nbdkitevalXXXXXX";
+char tmpdir[] = "/tmp/nbdkitevalXXXXXX";
 static char *missing;

 static const char *known_methods[] = {
@@ -218,11 +218,6 @@ eval_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 ("eval: load: tmpdir: %s", tmpdir);

diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index 2d99a120..b0aaf754 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -106,6 +106,7 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin */
        const char **argv)                /* script + parameters */
 {
   const char *argv0 = argv[0]; /* script name, used in error messages */
+  CLEANUP_FREE_STRING_LIST char **env = NULL;
   pid_t pid = -1;
   int status;
   int ret = ERROR;
@@ -122,6 +123,11 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin
*/

   debug_call (argv);

+  /* Copy the environment, and add $tmpdir. */
+  env = copy_environ (environ, "tmpdir", tmpdir, NULL);
+  if (env == NULL)
+    goto error;
+
 #ifdef HAVE_PIPE2
   if (pipe2 (in_fd, O_CLOEXEC) == -1) {
     nbdkit_error ("%s: pipe2: %m", argv0);
@@ -184,6 +190,11 @@ 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);

+    /* Note the assignment of environ avoids using execvpe which is a
+     * GNU extension.  See also:
+     *
https://github.com/libguestfs/libnbd/commit/dc64ac5cdd0bc80ca4e18935ad0e8801d11a8644
+     */
+    environ = env;
     execvp (argv[0], (char **) argv);
     perror (argv[0]);
     _exit (EXIT_FAILURE);
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index c8a321f1..deb01201 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -50,7 +50,7 @@
 #include "call.h"
 #include "methods.h"

-static char tmpdir[] = "/tmp/nbdkitshXXXXXX";
+char tmpdir[] = "/tmp/nbdkitshXXXXXX";
 static char *script;
 static char *magic_config_key;

@@ -71,11 +71,6 @@ 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);
 }
--
2.25.0