Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP3:GA
flatpak.14328
CVE-2021-21261.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2021-21261.patch of Package flatpak.14328
diff -urp flatpak-1.2.3.orig/common/flatpak-bwrap.c flatpak-1.2.3/common/flatpak-bwrap.c --- flatpak-1.2.3.orig/common/flatpak-bwrap.c 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/common/flatpak-bwrap.c 2022-08-25 17:43:15.996674658 -0500 @@ -108,6 +108,18 @@ flatpak_bwrap_add_arg (FlatpakBwrap *bwr g_ptr_array_add (bwrap->argv, g_strdup (arg)); } +/* + * flatpak_bwrap_take_arg: + * @arg: (transfer full): Take ownership of this argument + * + * Add @arg to @bwrap's argv, taking ownership of the pointer. + */ +void +flatpak_bwrap_take_arg (FlatpakBwrap *bwrap, char *arg) +{ + g_ptr_array_add (bwrap->argv, arg); +} + void flatpak_bwrap_finish (FlatpakBwrap *bwrap) { @@ -273,6 +285,37 @@ flatpak_bwrap_add_bind_arg (FlatpakBwrap } } +/* + * Convert bwrap->envp into a series of --setenv arguments for bwrap(1), + * assumed to be applied to an empty environment. Reset envp to be an + * empty environment. + */ +void +flatpak_bwrap_envp_to_args (FlatpakBwrap *bwrap) +{ + gsize i; + + for (i = 0; bwrap->envp[i] != NULL; i++) + { + char *key_val = bwrap->envp[i]; + char *eq = strchr (key_val, '='); + + if (eq) + { + flatpak_bwrap_add_arg (bwrap, "--setenv"); + flatpak_bwrap_take_arg (bwrap, g_strndup (key_val, eq - key_val)); + flatpak_bwrap_add_arg (bwrap, eq + 1); + } + else + { + g_warn_if_reached (); + } + } + + g_strfreev (g_steal_pointer (&bwrap->envp)); + bwrap->envp = g_strdupv (flatpak_bwrap_empty_env); +} + gboolean flatpak_bwrap_bundle_args (FlatpakBwrap *bwrap, int start, diff -urp flatpak-1.2.3.orig/common/flatpak-bwrap-private.h flatpak-1.2.3/common/flatpak-bwrap-private.h --- flatpak-1.2.3.orig/common/flatpak-bwrap-private.h 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/common/flatpak-bwrap-private.h 2022-08-25 17:43:15.996674658 -0500 @@ -43,6 +43,8 @@ void flatpak_bwrap_unset_env (F const char *variable); void flatpak_bwrap_add_arg (FlatpakBwrap *bwrap, const char *arg); +void flatpak_bwrap_take_arg (FlatpakBwrap *bwrap, + char *arg); void flatpak_bwrap_add_noinherit_fd (FlatpakBwrap *bwrap, int fd); void flatpak_bwrap_add_fd (FlatpakBwrap *bwrap, @@ -73,6 +75,7 @@ void flatpak_bwrap_add_bind_arg const char *type, const char *src, const char *dest); +void flatpak_bwrap_envp_to_args (FlatpakBwrap *bwrap); gboolean flatpak_bwrap_bundle_args (FlatpakBwrap *bwrap, int start, int end, diff -urp flatpak-1.2.3.orig/common/flatpak-context.c flatpak-1.2.3/common/flatpak-context.c --- flatpak-1.2.3.orig/common/flatpak-context.c 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/common/flatpak-context.c 2022-08-25 17:43:15.996674658 -0500 @@ -1040,6 +1040,65 @@ option_env_cb (const gchar *option_name, } static gboolean +option_env_fd_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + FlatpakContext *context = data; + g_autoptr(GBytes) env_block = NULL; + gsize remaining; + const char *p; + guint64 fd; + gchar *endptr; + + fd = g_ascii_strtoull (value, &endptr, 10); + + if (endptr == NULL || *endptr != '\0' || fd > G_MAXINT) + return glnx_throw (error, "Not a valid file descriptor: %s", value); + + env_block = glnx_fd_readall_bytes ((int) fd, NULL, error); + + if (env_block == NULL) + return FALSE; + + p = g_bytes_get_data (env_block, &remaining); + + /* env_block might not be \0-terminated */ + while (remaining > 0) + { + size_t len = strnlen (p, remaining); + const char *equals; + + g_assert (len <= remaining); + + equals = memchr (p, '=', len); + + if (equals == NULL || equals == p) + return glnx_throw (error, + "Environment variable must be given in the form VARIABLE=VALUE, not %.*s", (int) len, p); + + flatpak_context_set_env_var (context, + g_strndup (p, equals - p), + g_strndup (equals + 1, len - (equals - p) - 1)); + p += len; + remaining -= len; + + if (remaining > 0) + { + g_assert (*p == '\0'); + p += 1; + remaining -= 1; + } + } + + if (fd >= 3) + close (fd); + + return TRUE; +} + +static gboolean option_own_name_cb (const gchar *option_name, const gchar *value, gpointer data, @@ -1206,6 +1265,7 @@ static GOptionEntry context_options[] = { "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]") }, { "nofilesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_nofilesystem_cb, N_("Don't expose filesystem to app"), N_("FILESYSTEM") }, { "env", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_env_cb, N_("Set environment variable"), N_("VAR=VALUE") }, + { "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") }, { "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") }, { "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") }, { "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") }, diff -urp flatpak-1.2.3.orig/common/flatpak-run.c flatpak-1.2.3/common/flatpak-run.c --- flatpak-1.2.3.orig/common/flatpak-run.c 2022-08-25 13:21:23.359479491 -0500 +++ flatpak-1.2.3/common/flatpak-run.c 2022-08-25 17:43:15.996674658 -0500 @@ -1128,15 +1128,6 @@ flatpak_run_add_environment_args (Flatpa flatpak_run_add_system_dbus_args (bwrap, proxy_arg_bwrap, context, flags); flatpak_run_add_a11y_dbus_args (bwrap, proxy_arg_bwrap, context, flags); - if (g_environ_getenv (bwrap->envp, "LD_LIBRARY_PATH") != NULL) - { - /* LD_LIBRARY_PATH is overridden for setuid helper, so pass it as cmdline arg */ - flatpak_bwrap_add_args (bwrap, - "--setenv", "LD_LIBRARY_PATH", g_environ_getenv (bwrap->envp, "LD_LIBRARY_PATH"), - NULL); - flatpak_bwrap_unset_env (bwrap, "LD_LIBRARY_PATH"); - } - /* Must run this before spawning the dbus proxy, to ensure it ends up in the app cgroup */ if (!flatpak_run_in_transient_unit (app_id, &my_error)) @@ -3362,6 +3353,8 @@ flatpak_run_app (const char *app_ref command = default_command; } + flatpak_bwrap_envp_to_args (bwrap); + if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error)) return FALSE; @@ -3389,6 +3382,12 @@ flatpak_run_app (const char *app_ref if (flags & FLATPAK_RUN_FLAG_DO_NOT_REAP) spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD; + /* flatpak_bwrap_envp_to_args() moved the environment variables to + * be set into --setenv instructions in argv, so the environment + * in which the bwrap command runs must be empty. */ + g_assert (bwrap->envp != NULL); + g_assert (bwrap->envp[0] == NULL); + if (!g_spawn_async (NULL, (char **) bwrap->argv->pdata, bwrap->envp, @@ -3413,6 +3412,13 @@ flatpak_run_app (const char *app_ref /* Ensure we unset O_CLOEXEC */ flatpak_bwrap_child_setup_cb (bwrap->fds); + + /* flatpak_bwrap_envp_to_args() moved the environment variables to + * be set into --setenv instructions in argv, so the environment + * in which the bwrap command runs must be empty. */ + g_assert (bwrap->envp != NULL); + g_assert (bwrap->envp[0] == NULL); + if (execvpe (flatpak_get_bwrap (), (char **) bwrap->argv->pdata, bwrap->envp) == -1) { g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno), diff -urp flatpak-1.2.3.orig/doc/flatpak-build-finish.xml flatpak-1.2.3/doc/flatpak-build-finish.xml --- flatpak-1.2.3.orig/doc/flatpak-build-finish.xml 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/doc/flatpak-build-finish.xml 2022-08-25 17:43:15.996674658 -0500 @@ -282,6 +282,24 @@ key=v1;v2; </varlistentry> <varlistentry> + <term><option>--env-fd=<replaceable>FD</replaceable></option></term> + + <listitem><para> + Read environment variables from the file descriptor + <replaceable>FD</replaceable>, and set them as if + via <option>--env</option>. This can be used to avoid + environment variables and their values becoming visible + to other users. + </para><para> + Each environment variable is in the form + <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable> + followed by a zero byte. This is the same format used by + <literal>env -0</literal> and + <filename>/proc/*/environ</filename>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><option>--own-name=NAME</option></term> <listitem><para> diff -urp flatpak-1.2.3.orig/doc/flatpak-build.xml flatpak-1.2.3/doc/flatpak-build.xml --- flatpak-1.2.3.orig/doc/flatpak-build.xml 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/doc/flatpak-build.xml 2022-08-25 17:43:15.996674658 -0500 @@ -284,6 +284,24 @@ key=v1;v2; </varlistentry> <varlistentry> + <term><option>--env-fd=<replaceable>FD</replaceable></option></term> + + <listitem><para> + Read environment variables from the file descriptor + <replaceable>FD</replaceable>, and set them as if + via <option>--env</option>. This can be used to avoid + environment variables and their values becoming visible + to other users. + </para><para> + Each environment variable is in the form + <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable> + followed by a zero byte. This is the same format used by + <literal>env -0</literal> and + <filename>/proc/*/environ</filename>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><option>--own-name=NAME</option></term> <listitem><para> diff -urp flatpak-1.2.3.orig/doc/flatpak-override.xml flatpak-1.2.3/doc/flatpak-override.xml --- flatpak-1.2.3.orig/doc/flatpak-override.xml 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/doc/flatpak-override.xml 2022-08-25 17:43:16.000674684 -0500 @@ -258,6 +258,24 @@ key=v1;v2; </varlistentry> <varlistentry> + <term><option>--env-fd=<replaceable>FD</replaceable></option></term> + + <listitem><para> + Read environment variables from the file descriptor + <replaceable>FD</replaceable>, and set them as if + via <option>--env</option>. This can be used to avoid + environment variables and their values becoming visible + to other users. + </para><para> + Each environment variable is in the form + <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable> + followed by a zero byte. This is the same format used by + <literal>env -0</literal> and + <filename>/proc/*/environ</filename>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><option>--own-name=NAME</option></term> <listitem><para> diff -urp flatpak-1.2.3.orig/doc/flatpak-run.xml flatpak-1.2.3/doc/flatpak-run.xml --- flatpak-1.2.3.orig/doc/flatpak-run.xml 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/doc/flatpak-run.xml 2022-08-25 17:43:16.000674684 -0500 @@ -392,6 +392,24 @@ key=v1;v2; </varlistentry> <varlistentry> + <term><option>--env-fd=<replaceable>FD</replaceable></option></term> + + <listitem><para> + Read environment variables from the file descriptor + <replaceable>FD</replaceable>, and set them as if + via <option>--env</option>. This can be used to avoid + environment variables and their values becoming visible + to other users. + </para><para> + Each environment variable is in the form + <replaceable>VAR</replaceable>=<replaceable>VALUE</replaceable> + followed by a zero byte. This is the same format used by + <literal>env -0</literal> and + <filename>/proc/*/environ</filename>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><option>--own-name=NAME</option></term> <listitem><para> diff -urp flatpak-1.2.3.orig/portal/flatpak-portal.c flatpak-1.2.3/portal/flatpak-portal.c --- flatpak-1.2.3.orig/portal/flatpak-portal.c 2022-08-25 13:22:07.539751774 -0500 +++ flatpak-1.2.3/portal/flatpak-portal.c 2022-08-25 18:17:07.426247509 -0500 @@ -26,10 +26,12 @@ #include <string.h> #include <signal.h> #include <sys/ioctl.h> +#include <fcntl.h> #include <gio/gio.h> #include <gio/gunixfdlist.h> #include "flatpak-portal-dbus.h" #include "flatpak-portal.h" +#include "flatpak-utils-private.h" #include "flatpak-portal-app-info.h" #include "flatpak-portal-error.h" @@ -167,6 +169,7 @@ typedef struct int fd_map_len; gboolean set_tty; int tty; + int env_fd; } ChildSetupData; static void @@ -177,6 +180,9 @@ child_setup_func (gpointer user_data) sigset_t set; int i; + if (data->env_fd != -1) + fcntl (data->env_fd, F_SETFD, 0); + /* Unblock all signals */ sigemptyset (&set); if (pthread_sigmask (SIG_SETMASK, &set, NULL) == -1) @@ -323,6 +329,9 @@ handle_spawn (PortalFlatpak *obj g_auto(GStrv) sandbox_expose_ro = NULL; gboolean sandboxed; gboolean devel; + g_autoptr(GString) env_string = g_string_new (""); + + child_setup_data.env_fd = -1; app_info = g_object_get_data (G_OBJECT (invocation), "app-info"); g_assert (app_info != NULL); @@ -525,7 +534,49 @@ handle_spawn (PortalFlatpak *obj else { for (i = 0; extra_args != NULL && extra_args[i] != NULL; i++) - g_ptr_array_add (flatpak_argv, g_strdup (extra_args[i])); + { + if (g_str_has_prefix (extra_args[i], "--env=")) + { + const char *var_val = extra_args[i] + strlen ("--env="); + + if (var_val[0] == '\0' || var_val[0] == '=') + { + g_warning ("Environment variable in extra-args has empty name"); + continue; + } + + if (strchr (var_val, '=') == NULL) + { + g_warning ("Environment variable in extra-args has no value"); + continue; + } + + g_string_append (env_string, var_val); + g_string_append_c (env_string, '\0'); + } + else + { + g_ptr_array_add (flatpak_argv, g_strdup (extra_args[i])); + } + } + } + + if (env_string->len > 0) + { + g_auto(GLnxTmpfile) env_tmpf = { 0, }; + + if (!flatpak_buffer_to_sealed_memfd_or_tmpfile (&env_tmpf, "environ", + env_string->str, + env_string->len, &error)) + { + g_dbus_method_invocation_return_gerror (invocation, error); + return TRUE; + } + + child_setup_data.env_fd = glnx_steal_fd (&env_tmpf.fd); + g_ptr_array_add (flatpak_argv, + g_strdup_printf ("--env-fd=%d", + child_setup_data.env_fd)); } if (devel) diff -urp flatpak-1.2.3.orig/portal/Makefile.am.inc flatpak-1.2.3/portal/Makefile.am.inc --- flatpak-1.2.3.orig/portal/Makefile.am.inc 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/portal/Makefile.am.inc 2022-08-25 18:25:56.817791195 -0500 @@ -34,6 +34,12 @@ flatpak_portal_SOURCES = \ BUILT_SOURCES += $(nodist_flatpak_portal_SOURCES) CLEANFILES += $(nodist_flatpak_portal_SOURCES) -flatpak_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) -flatpak_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) -DFLATPAK_COMPILATION +flatpak_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) libflatpak-common.la libflatpak-common.la libglnx.la +flatpak_portal_CFLAGS = \ + $(AM_CFLAGS) \ + $(BASE_CFLAGS) \ + $(OSTREE_CFLAGS) \ + $(SOUP_CFLAGS) \ + $(JSON_CFLAGS) \ + -DFLATPAK_COMPILATION flatpak_portal_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/portal diff -urp flatpak-1.2.3.orig/tests/test-override.sh flatpak-1.2.3/tests/test-override.sh --- flatpak-1.2.3.orig/tests/test-override.sh 2019-02-11 07:44:28.000000000 -0600 +++ flatpak-1.2.3/tests/test-override.sh 2022-08-25 17:43:16.000674684 -0500 @@ -10,7 +10,7 @@ reset_overrides () { assert_file_empty info } -echo "1..13" +echo "1..15" setup_repo install_repo @@ -63,14 +63,80 @@ reset_overrides ${FLATPAK} override --user --env=FOO=BAR org.test.Hello ${FLATPAK} override --user --env=BAR= org.test.Hello +# TODO: A future commit will add a way to avoid this ever being present in argv +${FLATPAK} override --user --env=SECRET_TOKEN=3047225e-5e38-4357-b21c-eac83b7e8ea6 org.test.Hello +# TMPDIR and TZDIR are filtered out by ld.so for setuid processes, +# so setting these gives us a way to verify that we can pass them through +# a setuid bwrap (without special-casing them, as we previously did for +# TMPDIR). +${FLATPAK} override --user --env=TMPDIR=/nonexistent/tmp org.test.Hello +${FLATPAK} override --user --env=TZDIR=/nonexistent/tz org.test.Hello ${FLATPAK} override --user --show org.test.Hello > override assert_file_has_content override "^\[Environment\]$" assert_file_has_content override "^FOO=BAR$" assert_file_has_content override "^BAR=$" +assert_file_has_content override "^SECRET_TOKEN=3047225e-5e38-4357-b21c-eac83b7e8ea6$" +assert_file_has_content override "^TMPDIR=/nonexistent/tmp$" +assert_file_has_content override "^TZDIR=/nonexistent/tz$" echo "ok override --env" +if skip_one_without_bwrap "sandbox environment variables"; then + : +else + ${FLATPAK} run --command=bash org.test.Hello \ + -c 'echo "FOO=$FOO"; echo "BAR=$BAR"; echo "SECRET_TOKEN=$SECRET_TOKEN"; echo "TMPDIR=$TMPDIR"; echo "TZDIR=$TZDIR"' > out + assert_file_has_content out '^FOO=BAR$' + assert_file_has_content out '^BAR=$' + assert_file_has_content out '^SECRET_TOKEN=3047225e-5e38-4357-b21c-eac83b7e8ea6$' + # The variables that would be filtered out by a setuid bwrap get set + assert_file_has_content out '^TZDIR=/nonexistent/tz$' + assert_file_has_content out '^TMPDIR=/nonexistent/tmp$' + ${FLATPAK} run --command=cat org.test.Hello -- /proc/1/cmdline > out + # The secret doesn't end up in bubblewrap's cmdline where other users + # could see it + assert_not_file_has_content out 3047225e-5e38-4357-b21c-eac83b7e8ea6 + + ok "sandbox environment variables" +fi + +reset_overrides + +if skip_one_without_bwrap "temporary environment variables"; then + : +else + ${FLATPAK} override --user --env=FOO=wrong org.test.Hello + ${FLATPAK} override --user --env=BAR=wrong org.test.Hello + ${FLATPAK} override --user --env=SECRET_TOKEN=wrong org.test.Hello + ${FLATPAK} override --user --env=TMPDIR=/nonexistent/wrong org.test.Hello + ${FLATPAK} override --user --env=TZDIR=/nonexistent/wrong org.test.Hello + ${FLATPAK} override --user --show org.test.Hello > override + + ${FLATPAK} run --command=bash \ + --env=FOO=BAR \ + --env=BAR= \ + --env=SECRET_TOKEN=3047225e-5e38-4357-b21c-eac83b7e8ea6 \ + --env=TMPDIR=/nonexistent/tmp \ + --env=TZDIR=/nonexistent/tz \ + org.test.Hello \ + -c 'echo "FOO=$FOO"; echo "BAR=$BAR"; echo "SECRET_TOKEN=$SECRET_TOKEN"; echo "TMPDIR=$TMPDIR"; echo "TZDIR=$TZDIR"' > out + # The versions from `flatpak run` overrule `flatpak override` + assert_file_has_content out '^FOO=BAR$' + assert_file_has_content out '^BAR=$' + assert_file_has_content out '^SECRET_TOKEN=3047225e-5e38-4357-b21c-eac83b7e8ea6$' + assert_file_has_content out '^TZDIR=/nonexistent/tz$' + assert_file_has_content out '^TMPDIR=/nonexistent/tmp$' + ${FLATPAK} run --command=cat org.test.Hello -- /proc/1/cmdline > out + # The secret doesn't end up in bubblewrap's cmdline where other users + # could see it + assert_not_file_has_content out 3047225e-5e38-4357-b21c-eac83b7e8ea6 + + ok "temporary environment variables" +fi + +reset_overrides + ${FLATPAK} override --user --filesystem=home org.test.Hello ${FLATPAK} override --user --filesystem=xdg-desktop/foo:create org.test.Hello ${FLATPAK} override --user --filesystem=xdg-config:ro org.test.Hello
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor