Blame SOURCES/flatpak-1.0.9-fix-CVE-2021-21261.patch

bf4f97
From 9b25bed85a693c0979cf92925ca080310fe566b1 Mon Sep 17 00:00:00 2001
bf4f97
From: Simon McVittie <smcv@collabora.com>
bf4f97
Date: Tue, 12 Jan 2021 12:21:31 +0000
bf4f97
Subject: [PATCH 1/5] run: Convert all environment variables into bwrap
bf4f97
 arguments
bf4f97
bf4f97
This avoids some of them being filtered out by a setuid bwrap. It also
bf4f97
means that if they came from an untrusted source, they cannot be used
bf4f97
to inject arbitrary code into a non-setuid bwrap via mechanisms like
bf4f97
LD_PRELOAD.
bf4f97
bf4f97
Because they get bundled into a memfd or temporary file, they do not
bf4f97
actually appear in argv, ensuring that they remain inaccessible to
bf4f97
processes running under a different uid (which is important if their
bf4f97
values are tokens or other secrets).
bf4f97
bf4f97
[Backported to 1.2.x for Debian 10 security update.]
bf4f97
bf4f97
Signed-off-by: Simon McVittie <smcv@collabora.com>
bf4f97
Part-of: https://github.com/flatpak/flatpak/security/advisories/GHSA-4ppf-fxf6-vxg2
bf4f97
---
bf4f97
 common/flatpak-bwrap-private.h |  3 +++
bf4f97
 common/flatpak-bwrap.c         | 43 ++++++++++++++++++++++++++++++++++
bf4f97
 common/flatpak-run.c           | 24 ++++++++++++-------
bf4f97
 3 files changed, 61 insertions(+), 9 deletions(-)
bf4f97
bf4f97
diff --git a/common/flatpak-bwrap-private.h b/common/flatpak-bwrap-private.h
bf4f97
index 2a633d30..b6f3df9f 100644
bf4f97
--- a/common/flatpak-bwrap-private.h
bf4f97
+++ b/common/flatpak-bwrap-private.h
bf4f97
@@ -43,6 +43,8 @@ void          flatpak_bwrap_unset_env (FlatpakBwrap *bwrap,
bf4f97
                                        const char   *variable);
bf4f97
 void          flatpak_bwrap_add_arg (FlatpakBwrap *bwrap,
bf4f97
                                      const char   *arg);
bf4f97
+void          flatpak_bwrap_take_arg (FlatpakBwrap *bwrap,
bf4f97
+                                      char         *arg);
bf4f97
 void          flatpak_bwrap_add_noinherit_fd (FlatpakBwrap *bwrap,
bf4f97
                                               int           fd);
bf4f97
 void          flatpak_bwrap_add_fd (FlatpakBwrap *bwrap,
bf4f97
@@ -73,6 +75,7 @@ void          flatpak_bwrap_add_bind_arg (FlatpakBwrap *bwrap,
bf4f97
                                           const char   *type,
bf4f97
                                           const char   *src,
bf4f97
                                           const char   *dest);
bf4f97
+void          flatpak_bwrap_envp_to_args (FlatpakBwrap *bwrap);
bf4f97
 gboolean      flatpak_bwrap_bundle_args (FlatpakBwrap *bwrap,
bf4f97
                                          int           start,
bf4f97
                                          int           end,
bf4f97
diff --git a/common/flatpak-bwrap.c b/common/flatpak-bwrap.c
bf4f97
index 826fd621..0194db84 100644
bf4f97
--- a/common/flatpak-bwrap.c
bf4f97
+++ b/common/flatpak-bwrap.c
bf4f97
@@ -108,6 +108,18 @@ flatpak_bwrap_add_arg (FlatpakBwrap *bwrap, const char *arg)
bf4f97
   g_ptr_array_add (bwrap->argv, g_strdup (arg));
bf4f97
 }
bf4f97
 
bf4f97
+/*
bf4f97
+ * flatpak_bwrap_take_arg:
bf4f97
+ * @arg: (transfer full): Take ownership of this argument
bf4f97
+ *
bf4f97
+ * Add @arg to @bwrap's argv, taking ownership of the pointer.
bf4f97
+ */
bf4f97
+void
bf4f97
+flatpak_bwrap_take_arg (FlatpakBwrap *bwrap, char *arg)
bf4f97
+{
bf4f97
+  g_ptr_array_add (bwrap->argv, arg);
bf4f97
+}
bf4f97
+
bf4f97
 void
bf4f97
 flatpak_bwrap_finish (FlatpakBwrap *bwrap)
bf4f97
 {
bf4f97
@@ -273,6 +285,37 @@ flatpak_bwrap_add_bind_arg (FlatpakBwrap *bwrap,
bf4f97
     }
bf4f97
 }
bf4f97
 
bf4f97
+/*
bf4f97
+ * Convert bwrap->envp into a series of --setenv arguments for bwrap(1),
bf4f97
+ * assumed to be applied to an empty environment. Reset envp to be an
bf4f97
+ * empty environment.
bf4f97
+ */
bf4f97
+void
bf4f97
+flatpak_bwrap_envp_to_args (FlatpakBwrap *bwrap)
bf4f97
+{
bf4f97
+  gsize i;
bf4f97
+
bf4f97
+  for (i = 0; bwrap->envp[i] != NULL; i++)
bf4f97
+    {
bf4f97
+      char *key_val = bwrap->envp[i];
bf4f97
+      char *eq = strchr (key_val, '=');
bf4f97
+
bf4f97
+      if (eq)
bf4f97
+        {
bf4f97
+          flatpak_bwrap_add_arg (bwrap, "--setenv");
bf4f97
+          flatpak_bwrap_take_arg (bwrap, g_strndup (key_val, eq - key_val));
bf4f97
+          flatpak_bwrap_add_arg (bwrap, eq + 1);
bf4f97
+        }
bf4f97
+      else
bf4f97
+        {
bf4f97
+          g_warn_if_reached ();
bf4f97
+        }
bf4f97
+    }
bf4f97
+
bf4f97
+  g_strfreev (g_steal_pointer (&bwrap->envp));
bf4f97
+  bwrap->envp = g_strdupv (flatpak_bwrap_empty_env);
bf4f97
+}
bf4f97
+
bf4f97
 gboolean
bf4f97
 flatpak_bwrap_bundle_args (FlatpakBwrap *bwrap,
bf4f97
                            int           start,
bf4f97
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
bf4f97
index 08bfe54a..ea5571bd 100644
bf4f97
--- a/common/flatpak-run.c
bf4f97
+++ b/common/flatpak-run.c
bf4f97
@@ -1120,15 +1120,6 @@ flatpak_run_add_environment_args (FlatpakBwrap    *bwrap,
bf4f97
   flatpak_run_add_system_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
bf4f97
   flatpak_run_add_a11y_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
bf4f97
 
bf4f97
-  if (g_environ_getenv (bwrap->envp, "LD_LIBRARY_PATH") != NULL)
bf4f97
-    {
bf4f97
-      /* LD_LIBRARY_PATH is overridden for setuid helper, so pass it as cmdline arg */
bf4f97
-      flatpak_bwrap_add_args (bwrap,
bf4f97
-                              "--setenv", "LD_LIBRARY_PATH", g_environ_getenv (bwrap->envp, "LD_LIBRARY_PATH"),
bf4f97
-                              NULL);
bf4f97
-      flatpak_bwrap_unset_env (bwrap, "LD_LIBRARY_PATH");
bf4f97
-    }
bf4f97
-
bf4f97
   /* Must run this before spawning the dbus proxy, to ensure it
bf4f97
      ends up in the app cgroup */
bf4f97
   if (!flatpak_run_in_transient_unit (app_id, &my_error))
bf4f97
@@ -3139,6 +3130,8 @@ flatpak_run_app (const char     *app_ref,
bf4f97
       command = default_command;
bf4f97
     }
bf4f97
 
bf4f97
+  flatpak_bwrap_envp_to_args (bwrap);
bf4f97
+
bf4f97
   if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
bf4f97
     return FALSE;
bf4f97
 
bf4f97
@@ -3161,6 +3154,12 @@ flatpak_run_app (const char     *app_ref,
bf4f97
       char pid_str[64];
bf4f97
       g_autofree char *pid_path = NULL;
bf4f97
 
bf4f97
+      /* flatpak_bwrap_envp_to_args() moved the environment variables to
bf4f97
+       * be set into --setenv instructions in argv, so the environment
bf4f97
+       * in which the bwrap command runs must be empty. */
bf4f97
+      g_assert (bwrap->envp != NULL);
bf4f97
+      g_assert (bwrap->envp[0] == NULL);
bf4f97
+
bf4f97
       if (!g_spawn_async (NULL,
bf4f97
                           (char **) bwrap->argv->pdata,
bf4f97
                           bwrap->envp,
bf4f97
@@ -3185,6 +3184,13 @@ flatpak_run_app (const char     *app_ref,
bf4f97
 
bf4f97
       /* Ensure we unset O_CLOEXEC */
bf4f97
       flatpak_bwrap_child_setup_cb (bwrap->fds);
bf4f97
+
bf4f97
+      /* flatpak_bwrap_envp_to_args() moved the environment variables to
bf4f97
+       * be set into --setenv instructions in argv, so the environment
bf4f97
+       * in which the bwrap command runs must be empty. */
bf4f97
+      g_assert (bwrap->envp != NULL);
bf4f97
+      g_assert (bwrap->envp[0] == NULL);
bf4f97
+
bf4f97
       if (execvpe (flatpak_get_bwrap (), (char **) bwrap->argv->pdata, bwrap->envp) == -1)
bf4f97
         {
bf4f97
           g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
bf4f97
-- 
bf4f97
2.29.2
bf4f97
bf4f97
bf4f97
From 260ae2c2ed5066762ba108f95210a9d9a66b99d4 Mon Sep 17 00:00:00 2001
bf4f97
From: Simon McVittie <smcv@collabora.com>
bf4f97
Date: Mon, 11 Jan 2021 14:51:36 +0000
bf4f97
Subject: [PATCH 2/5] common: Move flatpak_buffer_to_sealed_memfd_or_tmpfile to
bf4f97
 its own file
bf4f97
bf4f97
We'll need this to use it in flatpak-portal without pulling the rest of
bf4f97
the common/ directory.
bf4f97
bf4f97
[Part of a 1.2.x backport of GHSA-4ppf-fxf6-vxg2 for Debian 10.]
bf4f97
bf4f97
Signed-off-by: Simon McVittie <smcv@collabora.com>
bf4f97
---
bf4f97
 common/Makefile.am.inc               |  2 +
bf4f97
 common/flatpak-utils-memfd-private.h | 32 ++++++++++
bf4f97
 common/flatpak-utils-memfd.c         | 90 ++++++++++++++++++++++++++++
bf4f97
 common/flatpak-utils-private.h       |  1 +
bf4f97
 common/flatpak-utils.c               | 50 ----------------
bf4f97
 5 files changed, 125 insertions(+), 50 deletions(-)
bf4f97
 create mode 100644 common/flatpak-utils-memfd-private.h
bf4f97
 create mode 100644 common/flatpak-utils-memfd.c
bf4f97
bf4f97
diff --git a/common/Makefile.am.inc b/common/Makefile.am.inc
bf4f97
index f3966903..794bd4e3 100644
bf4f97
--- a/common/Makefile.am.inc
bf4f97
+++ b/common/Makefile.am.inc
bf4f97
@@ -96,6 +96,8 @@ libflatpak_common_la_SOURCES = \
bf4f97
 	common/flatpak-utils.c \
bf4f97
 	common/flatpak-utils-http.c \
bf4f97
 	common/flatpak-utils-http-private.h \
bf4f97
+	common/flatpak-utils-memfd.c \
bf4f97
+	common/flatpak-utils-memfd-private.h \
bf4f97
 	common/flatpak-utils-private.h \
bf4f97
 	common/flatpak-chain-input-stream.c \
bf4f97
 	common/flatpak-chain-input-stream-private.h \
bf4f97
diff --git a/common/flatpak-utils-memfd-private.h b/common/flatpak-utils-memfd-private.h
bf4f97
new file mode 100644
bf4f97
index 00000000..c0e985f0
bf4f97
--- /dev/null
bf4f97
+++ b/common/flatpak-utils-memfd-private.h
bf4f97
@@ -0,0 +1,32 @@
bf4f97
+/*
bf4f97
+ * Copyright © 2014 Red Hat, Inc
bf4f97
+ *
bf4f97
+ * This program is free software; you can redistribute it and/or
bf4f97
+ * modify it under the terms of the GNU Lesser General Public
bf4f97
+ * License as published by the Free Software Foundation; either
bf4f97
+ * version 2.1 of the License, or (at your option) any later version.
bf4f97
+ *
bf4f97
+ * This library is distributed in the hope that it will be useful,
bf4f97
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
bf4f97
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
bf4f97
+ * Lesser General Public License for more details.
bf4f97
+ *
bf4f97
+ * You should have received a copy of the GNU Lesser General Public
bf4f97
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
bf4f97
+ *
bf4f97
+ * Authors:
bf4f97
+ *       Alexander Larsson <alexl@redhat.com>
bf4f97
+ */
bf4f97
+
bf4f97
+#ifndef __FLATPAK_UTILS_MEMFD_H__
bf4f97
+#define __FLATPAK_UTILS_MEMFD_H__
bf4f97
+
bf4f97
+#include "libglnx/libglnx.h"
bf4f97
+
bf4f97
+gboolean flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
bf4f97
+                                                    const char  *name,
bf4f97
+                                                    const char  *str,
bf4f97
+                                                    size_t       len,
bf4f97
+                                                    GError     **error);
bf4f97
+
bf4f97
+#endif /* __FLATPAK_UTILS_MEMFD_H__ */
bf4f97
diff --git a/common/flatpak-utils-memfd.c b/common/flatpak-utils-memfd.c
bf4f97
new file mode 100644
bf4f97
index 00000000..9a0730f8
bf4f97
--- /dev/null
bf4f97
+++ b/common/flatpak-utils-memfd.c
bf4f97
@@ -0,0 +1,90 @@
bf4f97
+/*
bf4f97
+ * Copyright © 2014 Red Hat, Inc
bf4f97
+ *
bf4f97
+ * This program is free software; you can redistribute it and/or
bf4f97
+ * modify it under the terms of the GNU Lesser General Public
bf4f97
+ * License as published by the Free Software Foundation; either
bf4f97
+ * version 2.1 of the License, or (at your option) any later version.
bf4f97
+ *
bf4f97
+ * This library is distributed in the hope that it will be useful,
bf4f97
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
bf4f97
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bf4f97
+ * Lesser General Public License for more details.
bf4f97
+ *
bf4f97
+ * You should have received a copy of the GNU Lesser General Public
bf4f97
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
bf4f97
+ *
bf4f97
+ * Authors:
bf4f97
+ *       Alexander Larsson <alexl@redhat.com>
bf4f97
+ */
bf4f97
+
bf4f97
+#include "config.h"
bf4f97
+
bf4f97
+#include "flatpak-utils-memfd-private.h"
bf4f97
+
bf4f97
+#include "valgrind-private.h"
bf4f97
+
bf4f97
+#include <string.h>
bf4f97
+#include <stdlib.h>
bf4f97
+#include <stdio.h>
bf4f97
+#include <errno.h>
bf4f97
+#include <unistd.h>
bf4f97
+#include <fcntl.h>
bf4f97
+#include <string.h>
bf4f97
+#include <sys/stat.h>
bf4f97
+#include <sys/file.h>
bf4f97
+#include <sys/mman.h>
bf4f97
+#include <sys/types.h>
bf4f97
+#include <sys/utsname.h>
bf4f97
+#include <sys/ioctl.h>
bf4f97
+#include <termios.h>
bf4f97
+
bf4f97
+/* If memfd_create() is available, generate a sealed memfd with contents of
bf4f97
+ * @str. Otherwise use an O_TMPFILE @tmpf in anonymous mode, write @str to
bf4f97
+ * @tmpf, and lseek() back to the start. See also similar uses in e.g.
bf4f97
+ * rpm-ostree for running dracut.
bf4f97
+ */
bf4f97
+gboolean
bf4f97
+flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
bf4f97
+                                           const char  *name,
bf4f97
+                                           const char  *str,
bf4f97
+                                           size_t       len,
bf4f97
+                                           GError     **error)
bf4f97
+{
bf4f97
+  if (len == -1)
bf4f97
+    len = strlen (str);
bf4f97
+  glnx_autofd int memfd = memfd_create (name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
bf4f97
+  int fd; /* Unowned */
bf4f97
+  if (memfd != -1)
bf4f97
+    {
bf4f97
+      fd = memfd;
bf4f97
+    }
bf4f97
+  else
bf4f97
+    {
bf4f97
+      /* We use an anonymous fd (i.e. O_EXCL) since we don't want
bf4f97
+       * the target container to potentially be able to re-link it.
bf4f97
+       */
bf4f97
+      if (!G_IN_SET (errno, ENOSYS, EOPNOTSUPP))
bf4f97
+        return glnx_throw_errno_prefix (error, "memfd_create");
bf4f97
+      if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
bf4f97
+        return FALSE;
bf4f97
+      fd = tmpf->fd;
bf4f97
+    }
bf4f97
+  if (ftruncate (fd, len) < 0)
bf4f97
+    return glnx_throw_errno_prefix (error, "ftruncate");
bf4f97
+  if (glnx_loop_write (fd, str, len) < 0)
bf4f97
+    return glnx_throw_errno_prefix (error, "write");
bf4f97
+  if (lseek (fd, 0, SEEK_SET) < 0)
bf4f97
+    return glnx_throw_errno_prefix (error, "lseek");
bf4f97
+  if (memfd != -1)
bf4f97
+    {
bf4f97
+      /* Valgrind doesn't currently handle G_ADD_SEALS, so lets not seal when debugging... */
bf4f97
+      if ((!RUNNING_ON_VALGRIND) &&
bf4f97
+          fcntl (memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) < 0)
bf4f97
+        return glnx_throw_errno_prefix (error, "fcntl(F_ADD_SEALS)");
bf4f97
+      /* The other values can stay default */
bf4f97
+      tmpf->fd = glnx_steal_fd (&memfd);
bf4f97
+      tmpf->initialized = TRUE;
bf4f97
+    }
bf4f97
+  return TRUE;
bf4f97
+}
bf4f97
diff --git a/common/flatpak-utils-private.h b/common/flatpak-utils-private.h
bf4f97
index 8ed25f5a..3e2bcef7 100644
bf4f97
--- a/common/flatpak-utils-private.h
bf4f97
+++ b/common/flatpak-utils-private.h
bf4f97
@@ -32,6 +32,7 @@
bf4f97
 #include "flatpak-context-private.h"
bf4f97
 #include "flatpak-error.h"
bf4f97
 #include "flatpak-utils-http-private.h"
bf4f97
+#include "flatpak-utils-memfd-private.h"
bf4f97
 #include <ostree.h>
bf4f97
 #include <json-glib/json-glib.h>
bf4f97
 
bf4f97
diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c
bf4f97
index 0c8eaa9d..698f943d 100644
bf4f97
--- a/common/flatpak-utils.c
bf4f97
+++ b/common/flatpak-utils.c
bf4f97
@@ -2280,56 +2280,6 @@ flatpak_file_rename (GFile        *from,
bf4f97
   return TRUE;
bf4f97
 }
bf4f97
 
bf4f97
-/* If memfd_create() is available, generate a sealed memfd with contents of
bf4f97
- * @str. Otherwise use an O_TMPFILE @tmpf in anonymous mode, write @str to
bf4f97
- * @tmpf, and lseek() back to the start. See also similar uses in e.g.
bf4f97
- * rpm-ostree for running dracut.
bf4f97
- */
bf4f97
-gboolean
bf4f97
-flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
bf4f97
-                                           const char  *name,
bf4f97
-                                           const char  *str,
bf4f97
-                                           size_t       len,
bf4f97
-                                           GError     **error)
bf4f97
-{
bf4f97
-  if (len == -1)
bf4f97
-    len = strlen (str);
bf4f97
-  glnx_autofd int memfd = memfd_create (name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
bf4f97
-  int fd; /* Unowned */
bf4f97
-  if (memfd != -1)
bf4f97
-    {
bf4f97
-      fd = memfd;
bf4f97
-    }
bf4f97
-  else
bf4f97
-    {
bf4f97
-      /* We use an anonymous fd (i.e. O_EXCL) since we don't want
bf4f97
-       * the target container to potentially be able to re-link it.
bf4f97
-       */
bf4f97
-      if (!G_IN_SET (errno, ENOSYS, EOPNOTSUPP))
bf4f97
-        return glnx_throw_errno_prefix (error, "memfd_create");
bf4f97
-      if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
bf4f97
-        return FALSE;
bf4f97
-      fd = tmpf->fd;
bf4f97
-    }
bf4f97
-  if (ftruncate (fd, len) < 0)
bf4f97
-    return glnx_throw_errno_prefix (error, "ftruncate");
bf4f97
-  if (glnx_loop_write (fd, str, len) < 0)
bf4f97
-    return glnx_throw_errno_prefix (error, "write");
bf4f97
-  if (lseek (fd, 0, SEEK_SET) < 0)
bf4f97
-    return glnx_throw_errno_prefix (error, "lseek");
bf4f97
-  if (memfd != -1)
bf4f97
-    {
bf4f97
-      /* Valgrind doesn't currently handle G_ADD_SEALS, so lets not seal when debugging... */
bf4f97
-      if ((!RUNNING_ON_VALGRIND) &&
bf4f97
-          fcntl (memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) < 0)
bf4f97
-        return glnx_throw_errno_prefix (error, "fcntl(F_ADD_SEALS)");
bf4f97
-      /* The other values can stay default */
bf4f97
-      tmpf->fd = glnx_steal_fd (&memfd);
bf4f97
-      tmpf->initialized = TRUE;
bf4f97
-    }
bf4f97
-  return TRUE;
bf4f97
-}
bf4f97
-
bf4f97
 gboolean
bf4f97
 flatpak_open_in_tmpdir_at (int             tmpdir_fd,
bf4f97
                            int             mode,
bf4f97
-- 
bf4f97
2.29.2
bf4f97
bf4f97
bf4f97
From ae30b3e44ed8cf16534afabef851f07005c83be1 Mon Sep 17 00:00:00 2001
bf4f97
From: Simon McVittie <smcv@collabora.com>
bf4f97
Date: Sun, 10 Jan 2021 16:18:58 +0000
bf4f97
Subject: [PATCH 3/5] context: Add --env-fd option
bf4f97
bf4f97
This allows environment variables to be added to the context without
bf4f97
making their values visible to processes running under a different uid,
bf4f97
which might be significant if the variable's value is a token or some
bf4f97
other secret value.
bf4f97
bf4f97
Signed-off-by: Simon McVittie <smcv@collabora.com>
bf4f97
Part-of: https://github.com/flatpak/flatpak/security/advisories/GHSA-4ppf-fxf6-vxg2
bf4f97
---
bf4f97
 common/flatpak-context.c     | 60 ++++++++++++++++++++++++++++++++++++
bf4f97
 doc/flatpak-build-finish.xml | 18 +++++++++++
bf4f97
 doc/flatpak-build.xml        | 18 +++++++++++
bf4f97
 doc/flatpak-override.xml     | 18 +++++++++++
bf4f97
 doc/flatpak-run.xml          | 18 +++++++++++
bf4f97
 5 files changed, 132 insertions(+)
bf4f97
bf4f97
diff --git a/common/flatpak-context.c b/common/flatpak-context.c
bf4f97
index 7289368d..b597bd1e 100644
bf4f97
--- a/common/flatpak-context.c
bf4f97
+++ b/common/flatpak-context.c
bf4f97
@@ -1039,6 +1039,65 @@ option_env_cb (const gchar *option_name,
bf4f97
   return TRUE;
bf4f97
 }
bf4f97
 
bf4f97
+static gboolean
bf4f97
+option_env_fd_cb (const gchar *option_name,
bf4f97
+                  const gchar *value,
bf4f97
+                  gpointer     data,
bf4f97
+                  GError     **error)
bf4f97
+{
bf4f97
+  FlatpakContext *context = data;
bf4f97
+  g_autoptr(GBytes) env_block = NULL;
bf4f97
+  gsize remaining;
bf4f97
+  const char *p;
bf4f97
+  guint64 fd;
bf4f97
+  gchar *endptr;
bf4f97
+
bf4f97
+  fd = g_ascii_strtoull (value, &endptr, 10);
bf4f97
+
bf4f97
+  if (endptr == NULL || *endptr != '\0' || fd > G_MAXINT)
bf4f97
+    return glnx_throw (error, "Not a valid file descriptor: %s", value);
bf4f97
+
bf4f97
+  env_block = glnx_fd_readall_bytes ((int) fd, NULL, error);
bf4f97
+
bf4f97
+  if (env_block == NULL)
bf4f97
+    return FALSE;
bf4f97
+
bf4f97
+  p = g_bytes_get_data (env_block, &remaining);
bf4f97
+
bf4f97
+  /* env_block might not be \0-terminated */
bf4f97
+  while (remaining > 0)
bf4f97
+    {
bf4f97
+      size_t len = strnlen (p, remaining);
bf4f97
+      const char *equals;
bf4f97
+
bf4f97
+      g_assert (len <= remaining);
bf4f97
+
bf4f97
+      equals = memchr (p, '=', len);
bf4f97
+
bf4f97
+      if (equals == NULL || equals == p)
bf4f97
+        return glnx_throw (error,
bf4f97
+                           "Environment variable must be given in the form VARIABLE=VALUE, not %.*s", (int) len, p);
bf4f97
+
bf4f97
+      flatpak_context_set_env_var (context,
bf4f97
+                                   g_strndup (p, equals - p),
bf4f97
+                                   g_strndup (equals + 1, len - (equals - p) - 1));
bf4f97
+      p += len;
bf4f97
+      remaining -= len;
bf4f97
+
bf4f97
+      if (remaining > 0)
bf4f97
+        {
bf4f97
+          g_assert (*p == '\0');
bf4f97
+          p += 1;
bf4f97
+          remaining -= 1;
bf4f97
+        }
bf4f97
+    }
bf4f97
+
bf4f97
+  if (fd >= 3)
bf4f97
+    close (fd);
bf4f97
+
bf4f97
+  return TRUE;
bf4f97
+}
bf4f97
+
bf4f97
 static gboolean
bf4f97
 option_own_name_cb (const gchar *option_name,
bf4f97
                     const gchar *value,
bf4f97
@@ -1206,6 +1265,7 @@ static GOptionEntry context_options[] = {
bf4f97
   { "filesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_filesystem_cb, N_("Expose filesystem to app (:ro for read-only)"), N_("FILESYSTEM[:ro]") },
bf4f97
   { "nofilesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_nofilesystem_cb, N_("Don't expose filesystem to app"), N_("FILESYSTEM") },
bf4f97
   { "env", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_env_cb, N_("Set environment variable"), N_("VAR=VALUE") },
bf4f97
+  { "env-fd", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_env_fd_cb, N_("Read environment variables in env -0 format from FD"), N_("FD") },
bf4f97
   { "own-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_own_name_cb, N_("Allow app to own name on the session bus"), N_("DBUS_NAME") },
bf4f97
   { "talk-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_talk_name_cb, N_("Allow app to talk to name on the session bus"), N_("DBUS_NAME") },
bf4f97
   { "system-own-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_system_own_name_cb, N_("Allow app to own name on the system bus"), N_("DBUS_NAME") },
bf4f97
diff --git a/doc/flatpak-build-finish.xml b/doc/flatpak-build-finish.xml
bf4f97
index efe39521..d3de7d93 100644
bf4f97
--- a/doc/flatpak-build-finish.xml
bf4f97
+++ b/doc/flatpak-build-finish.xml
bf4f97
@@ -276,6 +276,24 @@ key=v1;v2;
bf4f97
                 </para></listitem>
bf4f97
             </varlistentry>
bf4f97
 
bf4f97
+            <varlistentry>
bf4f97
+                <term><option>--env-fd=<replaceable>FD</replaceable></option></term>
bf4f97
+
bf4f97
+                <listitem><para>
bf4f97
+                    Read environment variables from the file descriptor
bf4f97
+                    <replaceable>FD</replaceable>, and set them as if
bf4f97
+                    via <option>--env</option>. This can be used to avoid
bf4f97
+                    environment variables and their values becoming visible
bf4f97
+                    to other users.
bf4f97
+                </para><para>
bf4f97
+                    Each environment variable is in the form
bf4f97
+                    <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable>
bf4f97
+                    followed by a zero byte. This is the same format used by
bf4f97
+                    <literal>env -0</literal> and
bf4f97
+                    <filename>/proc/*/environ</filename>.
bf4f97
+                </para></listitem>
bf4f97
+            </varlistentry>
bf4f97
+
bf4f97
             <varlistentry>
bf4f97
                 <term><option>--own-name=NAME</option></term>
bf4f97
 
bf4f97
diff --git a/doc/flatpak-build.xml b/doc/flatpak-build.xml
bf4f97
index 539314e1..488eef8a 100644
bf4f97
--- a/doc/flatpak-build.xml
bf4f97
+++ b/doc/flatpak-build.xml
bf4f97
@@ -283,6 +283,24 @@ key=v1;v2;
bf4f97
                 </para></listitem>
bf4f97
             </varlistentry>
bf4f97
 
bf4f97
+            <varlistentry>
bf4f97
+                <term><option>--env-fd=<replaceable>FD</replaceable></option></term>
bf4f97
+
bf4f97
+                <listitem><para>
bf4f97
+                    Read environment variables from the file descriptor
bf4f97
+                    <replaceable>FD</replaceable>, and set them as if
bf4f97
+                    via <option>--env</option>. This can be used to avoid
bf4f97
+                    environment variables and their values becoming visible
bf4f97
+                    to other users.
bf4f97
+                </para><para>
bf4f97
+                    Each environment variable is in the form
bf4f97
+                    <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable>
bf4f97
+                    followed by a zero byte. This is the same format used by
bf4f97
+                    <literal>env -0</literal> and
bf4f97
+                    <filename>/proc/*/environ</filename>.
bf4f97
+                </para></listitem>
bf4f97
+            </varlistentry>
bf4f97
+
bf4f97
             <varlistentry>
bf4f97
                 <term><option>--own-name=NAME</option></term>
bf4f97
 
bf4f97
diff --git a/doc/flatpak-override.xml b/doc/flatpak-override.xml
bf4f97
index c91875cc..60fa58c5 100644
bf4f97
--- a/doc/flatpak-override.xml
bf4f97
+++ b/doc/flatpak-override.xml
bf4f97
@@ -257,6 +257,24 @@ key=v1;v2;
bf4f97
                 </para></listitem>
bf4f97
             </varlistentry>
bf4f97
 
bf4f97
+            <varlistentry>
bf4f97
+                <term><option>--env-fd=<replaceable>FD</replaceable></option></term>
bf4f97
+
bf4f97
+                <listitem><para>
bf4f97
+                    Read environment variables from the file descriptor
bf4f97
+                    <replaceable>FD</replaceable>, and set them as if
bf4f97
+                    via <option>--env</option>. This can be used to avoid
bf4f97
+                    environment variables and their values becoming visible
bf4f97
+                    to other users.
bf4f97
+                </para><para>
bf4f97
+                    Each environment variable is in the form
bf4f97
+                    <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable>
bf4f97
+                    followed by a zero byte. This is the same format used by
bf4f97
+                    <literal>env -0</literal> and
bf4f97
+                    <filename>/proc/*/environ</filename>.
bf4f97
+                </para></listitem>
bf4f97
+            </varlistentry>
bf4f97
+
bf4f97
             <varlistentry>
bf4f97
                 <term><option>--own-name=NAME</option></term>
bf4f97
 
bf4f97
diff --git a/doc/flatpak-run.xml b/doc/flatpak-run.xml
bf4f97
index 23503e11..8e1a3fd5 100644
bf4f97
--- a/doc/flatpak-run.xml
bf4f97
+++ b/doc/flatpak-run.xml
bf4f97
@@ -360,6 +360,24 @@ key=v1;v2;
bf4f97
                 </para></listitem>
bf4f97
             </varlistentry>
bf4f97
 
bf4f97
+            <varlistentry>
bf4f97
+                <term><option>--env-fd=<replaceable>FD</replaceable></option></term>
bf4f97
+
bf4f97
+                <listitem><para>
bf4f97
+                    Read environment variables from the file descriptor
bf4f97
+                    <replaceable>FD</replaceable>, and set them as if
bf4f97
+                    via <option>--env</option>. This can be used to avoid
bf4f97
+                    environment variables and their values becoming visible
bf4f97
+                    to other users.
bf4f97
+                </para><para>
bf4f97
+                    Each environment variable is in the form
bf4f97
+                    <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable>
bf4f97
+                    followed by a zero byte. This is the same format used by
bf4f97
+                    <literal>env -0</literal> and
bf4f97
+                    <filename>/proc/*/environ</filename>.
bf4f97
+                </para></listitem>
bf4f97
+            </varlistentry>
bf4f97
+
bf4f97
             <varlistentry>
bf4f97
                 <term><option>--own-name=NAME</option></term>
bf4f97
 
bf4f97
-- 
bf4f97
2.29.2
bf4f97
bf4f97
bf4f97
From b781c377efb1c1782ac38019eba2ef17258ddaeb Mon Sep 17 00:00:00 2001
bf4f97
From: Simon McVittie <smcv@collabora.com>
bf4f97
Date: Tue, 12 Jan 2021 12:25:59 +0000
bf4f97
Subject: [PATCH 4/5] portal: Convert --env in extra-args into --env-fd
bf4f97
bf4f97
This hides overridden variables from the command-line, which means
bf4f97
processes running under other uids can't see them in /proc/*/cmdline,
bf4f97
which might be important if they contain secrets.
bf4f97
bf4f97
[Backported to 1.2.x for Debian 10 security update]
bf4f97
bf4f97
Signed-off-by: Simon McVittie <smcv@collabora.com>
bf4f97
Part-of: https://github.com/flatpak/flatpak/security/advisories/GHSA-4ppf-fxf6-vxg2
bf4f97
---
bf4f97
 portal/Makefile.am.inc  |  4 ++-
bf4f97
 portal/flatpak-portal.c | 65 ++++++++++++++++++++++++++++++++++++++++-
bf4f97
 2 files changed, 67 insertions(+), 2 deletions(-)
bf4f97
bf4f97
diff --git a/portal/Makefile.am.inc b/portal/Makefile.am.inc
bf4f97
index 119c1cf9..ef1f5da3 100644
bf4f97
--- a/portal/Makefile.am.inc
bf4f97
+++ b/portal/Makefile.am.inc
bf4f97
@@ -29,11 +29,13 @@ flatpak_portal_SOURCES = \
bf4f97
 	portal/flatpak-portal-app-info.h		\
bf4f97
 	common/flatpak-portal-error.c	\
bf4f97
 	common/flatpak-portal-error.h	\
bf4f97
+	common/flatpak-utils-memfd.c \
bf4f97
+	common/flatpak-utils-memfd-private.h \
bf4f97
 	$(NULL)
bf4f97
 
bf4f97
 BUILT_SOURCES += $(nodist_flatpak_portal_SOURCES)
bf4f97
 CLEANFILES += $(nodist_flatpak_portal_SOURCES)
bf4f97
 
bf4f97
-flatpak_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS)
bf4f97
+flatpak_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS) libglnx.la
bf4f97
 flatpak_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) -DFLATPAK_COMPILATION
bf4f97
 flatpak_portal_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/portal
bf4f97
diff --git a/portal/flatpak-portal.c b/portal/flatpak-portal.c
bf4f97
index ef52fc30..84338959 100644
bf4f97
--- a/portal/flatpak-portal.c
bf4f97
+++ b/portal/flatpak-portal.c
bf4f97
@@ -32,6 +32,14 @@
bf4f97
 #include "flatpak-portal.h"
bf4f97
 #include "flatpak-portal-app-info.h"
bf4f97
 #include "flatpak-portal-error.h"
bf4f97
+#include "flatpak-utils-memfd-private.h"
bf4f97
+
bf4f97
+/* Syntactic sugar added in newer GLib, which makes the error paths more
bf4f97
+ * clearly correct */
bf4f97
+#ifndef G_DBUS_METHOD_INVOCATION_HANDLED
bf4f97
+# define G_DBUS_METHOD_INVOCATION_HANDLED TRUE
bf4f97
+# define G_DBUS_METHOD_INVOCATION_UNHANDLED FALSE
bf4f97
+#endif
bf4f97
 
bf4f97
 #define IDLE_TIMEOUT_SECS 10 * 60
bf4f97
 
bf4f97
@@ -166,8 +174,15 @@ typedef struct
bf4f97
   int         fd_map_len;
bf4f97
   gboolean    set_tty;
bf4f97
   int         tty;
bf4f97
+  int         env_fd;
bf4f97
 } ChildSetupData;
bf4f97
 
bf4f97
+static void
bf4f97
+drop_cloexec (int fd)
bf4f97
+{
bf4f97
+  fcntl (fd, F_SETFD, 0);
bf4f97
+}
bf4f97
+
bf4f97
 static void
bf4f97
 child_setup_func (gpointer user_data)
bf4f97
 {
bf4f97
@@ -176,6 +191,9 @@ child_setup_func (gpointer user_data)
bf4f97
   sigset_t set;
bf4f97
   int i;
bf4f97
 
bf4f97
+  if (data->env_fd != -1)
bf4f97
+    drop_cloexec (data->env_fd);
bf4f97
+
bf4f97
   /* Unblock all signals */
bf4f97
   sigemptyset (&set);
bf4f97
   if (pthread_sigmask (SIG_SETMASK, &set, NULL) == -1)
bf4f97
@@ -321,6 +339,9 @@ handle_spawn (PortalFlatpak         *object,
bf4f97
   g_auto(GStrv) sandbox_expose = NULL;
bf4f97
   g_auto(GStrv) sandbox_expose_ro = NULL;
bf4f97
   gboolean sandboxed;
bf4f97
+  g_autoptr(GString) env_string = g_string_new ("");
bf4f97
+
bf4f97
+  child_setup_data.env_fd = -1;
bf4f97
 
bf4f97
   app_info = g_object_get_data (G_OBJECT (invocation), "app-info");
bf4f97
   g_assert (app_info != NULL);
bf4f97
@@ -505,7 +526,49 @@ handle_spawn (PortalFlatpak         *object,
bf4f97
   else
bf4f97
     {
bf4f97
       for (i = 0; extra_args != NULL && extra_args[i] != NULL; i++)
bf4f97
-        g_ptr_array_add (flatpak_argv, g_strdup (extra_args[i]));
bf4f97
+        {
bf4f97
+          if (g_str_has_prefix (extra_args[i], "--env="))
bf4f97
+            {
bf4f97
+              const char *var_val = extra_args[i] + strlen ("--env=");
bf4f97
+
bf4f97
+              if (var_val[0] == '\0' || var_val[0] == '=')
bf4f97
+                {
bf4f97
+                  g_warning ("Environment variable in extra-args has empty name");
bf4f97
+                  continue;
bf4f97
+                }
bf4f97
+
bf4f97
+              if (strchr (var_val, '=') == NULL)
bf4f97
+                {
bf4f97
+                  g_warning ("Environment variable in extra-args has no value");
bf4f97
+                  continue;
bf4f97
+                }
bf4f97
+
bf4f97
+              g_string_append (env_string, var_val);
bf4f97
+              g_string_append_c (env_string, '\0');
bf4f97
+            }
bf4f97
+          else
bf4f97
+            {
bf4f97
+              g_ptr_array_add (flatpak_argv, g_strdup (extra_args[i]));
bf4f97
+            }
bf4f97
+        }
bf4f97
+    }
bf4f97
+
bf4f97
+  if (env_string->len > 0)
bf4f97
+    {
bf4f97
+      g_auto(GLnxTmpfile) env_tmpf  = { 0, };
bf4f97
+
bf4f97
+      if (!flatpak_buffer_to_sealed_memfd_or_tmpfile (&env_tmpf, "environ",
bf4f97
+                                                      env_string->str,
bf4f97
+                                                      env_string->len, &error))
bf4f97
+        {
bf4f97
+          g_dbus_method_invocation_return_gerror (invocation, error);
bf4f97
+          return G_DBUS_METHOD_INVOCATION_HANDLED;
bf4f97
+        }
bf4f97
+
bf4f97
+      child_setup_data.env_fd = glnx_steal_fd (&env_tmpf.fd);
bf4f97
+      g_ptr_array_add (flatpak_argv,
bf4f97
+                       g_strdup_printf ("--env-fd=%d",
bf4f97
+                                        child_setup_data.env_fd));
bf4f97
     }
bf4f97
 
bf4f97
   /* Inherit launcher network access from launcher, unless
bf4f97
-- 
bf4f97
2.29.2
bf4f97
bf4f97
bf4f97
From a83ebc5f82b83c7b4f26895769f4d1d3f0c083f6 Mon Sep 17 00:00:00 2001
bf4f97
From: Simon McVittie <smcv@collabora.com>
bf4f97
Date: Sun, 10 Jan 2021 16:25:29 +0000
bf4f97
Subject: [PATCH 5/5] portal: Do not use caller-supplied variables in
bf4f97
 environment
bf4f97
bf4f97
If the caller specifies a variable that can be used to inject arbitrary
bf4f97
code into processes, we must not allow it to enter the environment
bf4f97
block used to run `flatpak run`, which runs unsandboxed.
bf4f97
bf4f97
This change requires the previous commit "context: Add --env-fd option",
bf4f97
which adds infrastructure used here.
bf4f97
bf4f97
To be secure, this change also requires the previous commit
bf4f97
"run: Convert all environment variables into bwrap arguments", which
bf4f97
protects a non-setuid bwrap(1) from the same attack.
bf4f97
bf4f97
Signed-off-by: Simon McVittie <smcv@collabora.com>
bf4f97
Part-of: https://github.com/flatpak/flatpak/security/advisories/GHSA-4ppf-fxf6-vxg2
bf4f97
---
bf4f97
 portal/flatpak-portal.c | 28 +++++++++++++++++++++++++++-
bf4f97
 1 file changed, 27 insertions(+), 1 deletion(-)
bf4f97
bf4f97
diff --git a/portal/flatpak-portal.c b/portal/flatpak-portal.c
bf4f97
index 84338959..ed2baf5c 100644
bf4f97
--- a/portal/flatpak-portal.c
bf4f97
+++ b/portal/flatpak-portal.c
bf4f97
@@ -506,6 +506,13 @@ handle_spawn (PortalFlatpak         *object,
bf4f97
   else
bf4f97
     env = g_get_environ ();
bf4f97
 
bf4f97
+  /* Let the environment variables given by the caller override the ones
bf4f97
+   * from extra_args. Don't add them to @env, because they are controlled
bf4f97
+   * by our caller, which might be trying to use them to inject code into
bf4f97
+   * flatpak(1); add them to the environment block instead.
bf4f97
+   *
bf4f97
+   * We don't use --env= here, so that if the values are something that
bf4f97
+   * should not be exposed to other uids, they can remain confidential. */
bf4f97
   n_envs = g_variant_n_children (arg_envs);
bf4f97
   for (i = 0; i < n_envs; i++)
bf4f97
     {
bf4f97
@@ -513,7 +520,26 @@ handle_spawn (PortalFlatpak         *object,
bf4f97
       const char *val = NULL;
bf4f97
       g_variant_get_child (arg_envs, i, "{&s&s}", &var, &val;;
bf4f97
 
bf4f97
-      env = g_environ_setenv (env, var, val, TRUE);
bf4f97
+      if (var[0] == '\0')
bf4f97
+        {
bf4f97
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
bf4f97
+                                                 G_DBUS_ERROR_INVALID_ARGS,
bf4f97
+                                                 "Environment variable cannot have empty name");
bf4f97
+          return G_DBUS_METHOD_INVOCATION_HANDLED;
bf4f97
+        }
bf4f97
+
bf4f97
+      if (strchr (var, '=') != NULL)
bf4f97
+        {
bf4f97
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
bf4f97
+                                                 G_DBUS_ERROR_INVALID_ARGS,
bf4f97
+                                                 "Environment variable name cannot contain '='");
bf4f97
+          return G_DBUS_METHOD_INVOCATION_HANDLED;
bf4f97
+        }
bf4f97
+
bf4f97
+      g_string_append (env_string, var);
bf4f97
+      g_string_append_c (env_string, '=');
bf4f97
+      g_string_append (env_string, val);
bf4f97
+      g_string_append_c (env_string, '\0');
bf4f97
     }
bf4f97
 
bf4f97
   g_ptr_array_add (flatpak_argv, g_strdup ("flatpak"));
bf4f97
-- 
bf4f97
2.29.2
bf4f97