From b15a1ae5e84e4cbe3602f363a2ce20b24438848e Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 13 Jan 2021 11:54:48 +0000
Subject: [PATCH] runtime: Use bwrap->envp to run readlink

Previously, pv_capture_output() always inherited pressure-vessel-wrap's
own environment, and bwrap->envp was ignored.

Thanks to @mawww on Github for spotting this.

Fixes: f584a55c "runtime: Don't assume container's env is in the PATH"
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 pressure-vessel/runtime.c     |  5 +++--
 pressure-vessel/utils.c       |  3 ++-
 pressure-vessel/utils.h       |  1 +
 tests/pressure-vessel/utils.c | 37 ++++++++++++++++++++++++++++++-----
 4 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index cb22c91bb..7737e6e4e 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -318,7 +318,7 @@ runtime_architecture_init (RuntimeArchitecture *self,
    * assume that this is the same as whether we can run them
    * on the host, if different. */
   argv[0] = self->capsule_capture_libs;
-  self->ld_so = pv_capture_output (argv, NULL);
+  self->ld_so = pv_capture_output (argv, NULL, NULL);
 
   if (self->ld_so == NULL)
     {
@@ -2843,7 +2843,8 @@ pv_runtime_get_ld_so (PvRuntime *self,
       flatpak_bwrap_finish (temp_bwrap);
 
       *ld_so_in_runtime = pv_capture_output (
-          (const char * const *) temp_bwrap->argv->pdata, NULL);
+          (const char * const *) temp_bwrap->argv->pdata,
+          (const char * const *) temp_bwrap->envp, NULL);
     }
 
   return TRUE;
diff --git a/pressure-vessel/utils.c b/pressure-vessel/utils.c
index ba28e4c13..5cb4950d6 100644
--- a/pressure-vessel/utils.c
+++ b/pressure-vessel/utils.c
@@ -170,6 +170,7 @@ pv_search_path_append (GString *search_path,
 
 gchar *
 pv_capture_output (const char * const * argv,
+                   const char * const * envp,
                    GError **error)
 {
   gsize len;
@@ -199,7 +200,7 @@ pv_capture_output (const char * const * argv,
    * that are not close-on-execute will get leaked into the child. */
   if (!g_spawn_sync (NULL,  /* cwd */
                      (char **) argv,
-                     NULL,  /* env */
+                     (char **) envp,
                      (G_SPAWN_SEARCH_PATH |
                       G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
                      NULL, NULL,
diff --git a/pressure-vessel/utils.h b/pressure-vessel/utils.h
index d15b52af3..5d647afa0 100644
--- a/pressure-vessel/utils.h
+++ b/pressure-vessel/utils.h
@@ -49,6 +49,7 @@ void pv_search_path_append (GString *search_path,
                             const gchar *item);
 
 gchar *pv_capture_output (const char * const * argv,
+                          const char * const * envp,
                           GError **error);
 
 gpointer pv_hash_table_get_arbitrary_key (GHashTable *table);
diff --git a/tests/pressure-vessel/utils.c b/tests/pressure-vessel/utils.c
index 3376ff503..5508fb04f 100644
--- a/tests/pressure-vessel/utils.c
+++ b/tests/pressure-vessel/utils.c
@@ -87,24 +87,25 @@ test_capture_output (Fixture *f,
 {
   const gchar * argv[] =
   {
-    "printf", "hello\\n", NULL
+    "printf", "hello\\n", NULL, NULL,
   };
   g_autofree gchar *output = NULL;
   g_autoptr(GError) error = NULL;
+  g_auto(GStrv) envp = g_get_environ ();
 
-  output = pv_capture_output (argv, &error);
+  output = pv_capture_output (argv, NULL, &error);
   g_assert_cmpstr (output, ==, "hello");
   g_assert_no_error (error);
   g_clear_pointer (&output, g_free);
 
   argv[1] = "hello\\nworld";    /* deliberately no trailing newline */
-  output = pv_capture_output (argv, &error);
+  output = pv_capture_output (argv, NULL, &error);
   g_assert_no_error (error);
   g_assert_cmpstr (output, ==, "hello\nworld");
   g_clear_pointer (&output, g_free);
 
   argv[0] = "/nonexistent/doesnotexist";
-  output = pv_capture_output (argv, &error);
+  output = pv_capture_output (argv, NULL, &error);
   g_assert_nonnull (error);
 
   if (error->domain == G_SPAWN_ERROR
@@ -129,10 +130,36 @@ test_capture_output (Fixture *f,
 
   argv[0] = "false";
   argv[1] = NULL;
-  output = pv_capture_output (argv, &error);
+  output = pv_capture_output (argv, NULL, &error);
   g_assert_error (error, G_SPAWN_EXIT_ERROR, 1);
   g_assert_cmpstr (output, ==, NULL);
   g_clear_error (&error);
+
+  argv[0] = "sh";
+  argv[1] = "-euc";
+  argv[2] = "echo \"$PATH\"";
+  output = pv_capture_output (argv, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpstr (output, ==, g_getenv ("PATH"));
+  g_clear_pointer (&output, g_free);
+
+  envp = g_environ_setenv (envp, "FOO", "bar", TRUE);
+  argv[0] = "sh";
+  argv[1] = "-euc";
+  argv[2] = "echo \"${FOO-unset}\"";
+  output = pv_capture_output (argv, (const char * const *) envp, &error);
+  g_assert_no_error (error);
+  g_assert_cmpstr (output, ==, "bar");
+  g_clear_pointer (&output, g_free);
+
+  envp = g_environ_unsetenv (envp, "FOO");
+  argv[0] = "sh";
+  argv[1] = "-euc";
+  argv[2] = "echo \"${FOO-unset}\"";
+  output = pv_capture_output (argv, (const char * const *) envp, &error);
+  g_assert_no_error (error);
+  g_assert_cmpstr (output, ==, "unset");
+  g_clear_pointer (&output, g_free);
 }
 
 static void
-- 
GitLab