Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
1dd69bf453
!94 [sync] PR-89: Fix CVE-2024-42472
From: @openeuler-sync-bot 
Reviewed-by: @lyn1001 
Signed-off-by: @lyn1001
2024-08-21 01:08:42 +00:00
wk333
3ebf716878 Fix CVE-2024-42472
(cherry picked from commit 60bd47da2a72d8ded218daca556c3a57e920b67b)
2024-08-19 14:57:49 +08:00
openeuler-ci-bot
51db3c693d
!79 Fix CVE-2024-32462
From: @wk333 
Reviewed-by: @lyn1001 
Signed-off-by: @lyn1001
2024-04-19 06:48:28 +00:00
wk333
4fc0a614c1 Fix CVE-2024-32462 2024-04-13 02:05:46 +08:00
openeuler-ci-bot
b76cb2636d
!70 [sync] PR-68: Fix CVE-2023-28100 and CVE-2023-28101 and Fix several memory leaks
From: @openeuler-sync-bot 
Reviewed-by: @caodongxia 
Signed-off-by: @caodongxia
2024-03-29 01:53:24 +00:00
starlet-dx
c06772b78d Fix CVE-2023-28100 and CVE-2023-28101 and Fix several memory leaks
(cherry picked from commit 6fe17b7f232e7c9530c41cff1c634d3cbad5ef28)
2024-03-29 09:00:50 +08:00
openeuler-ci-bot
748a464156
!54 Fix CVE-2021-43860
Merge pull request !54 from dongyuzhen/master
2022-01-30 02:47:28 +00:00
dongyuzhen
b078926f3a Fix CVE-2021-43860 2022-01-29 18:56:01 +08:00
openeuler-ci-bot
ee03d27738
!48 fix CVE-2022-21682
Merge pull request !48 from shirely/master
2022-01-25 11:29:09 +00:00
shirely16
a4560027db Fix CVE-2022-21682 2022-01-25 15:18:55 +08:00
16 changed files with 3111 additions and 1 deletions

394
CVE-2023-28100-pre1.patch Normal file
View File

@ -0,0 +1,394 @@
From 4206d681c5c52691dec0074e3f8c32dab1953a94 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Fri, 21 May 2021 17:41:31 +0100
Subject: [PATCH] test-context: Exercise some corner cases for merging
filesystems
Signed-off-by: Simon McVittie <smcv@collabora.com>
Co-authored-by: Alexander Larsson <alexl@redhat.com>
(cherry picked from commit fab0f8ed7c52fc58e6c550d123ede9621c760ca7)
[smcv: Also backport the scaffolding to create this test-case]
---
tests/Makefile.am.inc | 11 +-
tests/test-context.c | 343 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 353 insertions(+), 1 deletion(-)
create mode 100644 tests/test-context.c
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index 53d6403e4c..0fb650cb38 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -66,6 +66,10 @@ testcommon_LDADD = \
$(NULL)
testcommon_SOURCES = tests/testcommon.c
+test_context_CFLAGS = $(testcommon_CFLAGS)
+test_context_LDADD = $(testcommon_LDADD)
+test_context_SOURCES = tests/test-context.c
+
test_exports_CFLAGS = $(testcommon_CFLAGS)
test_exports_LDADD = $(testcommon_LDADD)
test_exports_SOURCES = tests/test-exports.c
@@ -252,7 +256,12 @@ test_scripts = ${TEST_MATRIX}
dist_test_scripts = ${TEST_MATRIX_DIST}
dist_installed_test_extra_scripts += ${TEST_MATRIX_EXTRA_DIST}
-test_programs = testlibrary testcommon test-exports
+test_programs = \
+ test-context \
+ test-exports \
+ testcommon \
+ testlibrary \
+ $(NULL)
test_extra_programs = tests/httpcache tests/test-update-portal tests/test-portal-impl tests/test-authenticator tests/list-unused
@VALGRIND_CHECK_RULES@
diff --git a/tests/test-context.c b/tests/test-context.c
new file mode 100644
index 0000000000..c128a83fae
--- /dev/null
+++ b/tests/test-context.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright © 2021 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include <glib.h>
+#include "flatpak.h"
+#include "flatpak-context-private.h"
+#include "flatpak-run-private.h"
+#include "flatpak-utils-private.h"
+
+/* g_str_has_prefix as a GEqualFunc */
+static gboolean
+str_has_prefix (gconstpointer candidate,
+ gconstpointer pattern)
+{
+ return g_str_has_prefix (candidate, pattern);
+}
+
+static void context_parse_args (FlatpakContext *context,
+ ...) G_GNUC_NULL_TERMINATED;
+
+static void
+context_parse_args (FlatpakContext *context,
+ ...)
+{
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GOptionContext) oc = NULL;
+ g_autoptr(GOptionGroup) group = NULL;
+ g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free);
+ g_auto(GStrv) argv = NULL;
+ const char *arg;
+ va_list ap;
+
+ g_ptr_array_add (args, g_strdup ("argv[0]"));
+
+ va_start (ap, context);
+
+ while ((arg = va_arg (ap, const char *)) != NULL)
+ g_ptr_array_add (args, g_strdup (arg));
+
+ va_end (ap);
+
+ g_ptr_array_add (args, NULL);
+ argv = (GStrv) g_ptr_array_free (g_steal_pointer (&args), FALSE);
+
+ oc = g_option_context_new ("");
+ group = flatpak_context_get_options (context);
+ g_option_context_add_group (oc, group);
+ g_option_context_parse_strv (oc, &argv, &local_error);
+ g_assert_no_error (local_error);
+}
+
+static void
+test_context_merge_fs (void)
+{
+ /*
+ * We want to arrive at the same result regardless of whether we:
+ * - start from lowest precedence, and successively merge higher
+ * precedences into it, discarding them when done;
+ * - successively merge highest precedence into second-highest, and
+ * then discard highest
+ */
+ enum { LOWEST_FIRST, HIGHEST_FIRST, INVALID } merge_order;
+
+ for (merge_order = LOWEST_FIRST; merge_order < INVALID; merge_order++)
+ {
+ g_autoptr(FlatpakContext) lowest = flatpak_context_new ();
+ g_autoptr(FlatpakContext) middle = flatpak_context_new ();
+ g_autoptr(FlatpakContext) highest = flatpak_context_new ();
+ gpointer value;
+
+ context_parse_args (lowest,
+ "--filesystem=/one",
+ NULL);
+ context_parse_args (middle,
+ "--nofilesystem=host:reset",
+ "--filesystem=/two",
+ NULL);
+ context_parse_args (highest,
+ "--nofilesystem=host",
+ "--filesystem=/three",
+ NULL);
+
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL));
+
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/three", NULL, NULL));
+
+ g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "host-reset", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/one", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/two", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ if (merge_order == LOWEST_FIRST)
+ {
+ flatpak_context_merge (lowest, middle);
+
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL));
+
+ flatpak_context_merge (lowest, highest);
+ }
+ else
+ {
+ flatpak_context_merge (middle, highest);
+
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ flatpak_context_merge (lowest, middle);
+ }
+
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ }
+
+ for (merge_order = LOWEST_FIRST; merge_order < INVALID; merge_order++)
+ {
+ g_autoptr(FlatpakContext) lowest = flatpak_context_new ();
+ g_autoptr(FlatpakContext) mid_low = flatpak_context_new ();
+ g_autoptr(FlatpakContext) mid_high = flatpak_context_new ();
+ g_autoptr(FlatpakContext) highest = flatpak_context_new ();
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GKeyFile) metakey = g_key_file_new ();
+ g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free);
+ g_autofree char *filesystems = NULL;
+ gpointer value;
+
+ context_parse_args (lowest,
+ "--filesystem=/one",
+ NULL);
+ context_parse_args (mid_low,
+ "--nofilesystem=host:reset",
+ "--filesystem=/two",
+ NULL);
+ context_parse_args (mid_high,
+ "--filesystem=host",
+ "--filesystem=/three",
+ NULL);
+ context_parse_args (highest,
+ "--nofilesystem=host",
+ "--filesystem=/four",
+ NULL);
+
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL));
+
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/three", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/four", NULL, NULL));
+
+ g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/one", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/two", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/four", NULL, NULL));
+
+ g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/one", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/two", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/three", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "/four", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ if (merge_order == LOWEST_FIRST)
+ {
+ flatpak_context_merge (lowest, mid_low);
+
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL));
+
+ flatpak_context_merge (lowest, mid_high);
+
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL));
+
+ flatpak_context_merge (lowest, highest);
+ }
+ else
+ {
+ flatpak_context_merge (mid_high, highest);
+
+ g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/one", NULL, NULL));
+ g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/two", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/four", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ flatpak_context_merge (mid_low, mid_high);
+
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/four", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ flatpak_context_merge (lowest, mid_low);
+ }
+
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE);
+ g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL));
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, &value));
+ g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+
+ flatpak_context_save_metadata (lowest, FALSE, metakey);
+ filesystems = g_key_file_get_value (metakey,
+ FLATPAK_METADATA_GROUP_CONTEXT,
+ FLATPAK_METADATA_KEY_FILESYSTEMS,
+ &local_error);
+ g_assert_no_error (local_error);
+ g_test_message ("%s=%s", FLATPAK_METADATA_KEY_FILESYSTEMS, filesystems);
+ /* !host:reset is serialized first */
+ g_assert_true (g_str_has_prefix (filesystems, "!host:reset;"));
+ /* The rest are serialized in arbitrary order */
+ g_assert_nonnull (strstr (filesystems, ";!host;"));
+ g_assert_null (strstr (filesystems, "/one"));
+ g_assert_nonnull (strstr (filesystems, ";/two;"));
+ g_assert_nonnull (strstr (filesystems, ";/three;"));
+ g_assert_nonnull (strstr (filesystems, ";/four;"));
+
+ flatpak_context_to_args (lowest, args);
+ /* !host:reset is serialized first */
+ g_assert_cmpuint (args->len, >, 0);
+ g_assert_cmpstr (g_ptr_array_index (args, 0), ==,
+ "--nofilesystem=host:reset");
+ /* The rest are serialized in arbitrary order */
+ g_assert_true (g_ptr_array_find_with_equal_func (args, "--nofilesystem=host", g_str_equal, NULL));
+ g_assert_false (g_ptr_array_find_with_equal_func (args, "--filesystem=/one", str_has_prefix, NULL));
+ g_assert_false (g_ptr_array_find_with_equal_func (args, "--nofilesystem=/one", str_has_prefix, NULL));
+ g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/two", g_str_equal, NULL));
+ g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/three", g_str_equal, NULL));
+ g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/four", g_str_equal, NULL));
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/context/merge-fs", test_context_merge_fs);
+
+ return g_test_run ();
+}

231
CVE-2023-28100-pre2.patch Normal file
View File

@ -0,0 +1,231 @@
From b83fb81d1a66fe4ea31fd9c36ca425705eaaca99 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 21 Oct 2021 17:39:08 +0100
Subject: [PATCH] tests: Add try-syscall helper
This exercises various syscalls. It's heavily based on the one from
<https://github.com/containers/bubblewrap/pull/459>, but with the
addition of a mode to output the numeric values of various expected
errno codes, which are not otherwise available to shell scripts.
Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 4ce251882c488953ca6e3734f00c5dbe2e1e3e7a)
(cherry picked from commit f82e2a45777e6f370b9d3be787a84cddc3ed0575)
---
.gitignore | 1 +
tests/Makefile.am.inc | 14 +++-
tests/try-syscall.c | 173 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 187 insertions(+), 1 deletion(-)
create mode 100644 tests/try-syscall.c
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index 3632591a04..2548080254 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -99,6 +99,10 @@ tests_test_authenticator_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) \
tests_test_authenticator_LDADD = $(AM_LDADD) $(BASE_LIBS) libflatpak-common.la libflatpak-common-base.la libglnx.la
tests_test_authenticator_SOURCES = tests/test-authenticator.c
+tests_try_syscall_CFLAGS = $(AM_CFLAGS)
+tests_try_syscall_LDADD = $(AM_LDADD)
+tests_try_syscall_SOURCES = tests/try-syscall.c
+
tests_list_unused_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(APPSTREAM_GLIB_CFLAGS) \
-DFLATPAK_COMPILATION \
-DLOCALEDIR=\"$(localedir)\"
@@ -263,7 +267,15 @@ test_programs = \
testcommon \
testlibrary \
$(NULL)
-test_extra_programs = tests/httpcache tests/test-update-portal tests/test-portal-impl tests/test-authenticator tests/list-unused
+
+test_extra_programs = \
+ tests/httpcache \
+ tests/list-unused \
+ tests/test-authenticator \
+ tests/test-portal-impl \
+ tests/test-update-portal \
+ tests/try-syscall \
+ $(NULL)
@VALGRIND_CHECK_RULES@
VALGRIND_SUPPRESSIONS_FILES=tests/flatpak.supp tests/glib.supp
diff --git a/tests/try-syscall.c b/tests/try-syscall.c
new file mode 100644
index 0000000000..84a0ca6673
--- /dev/null
+++ b/tests/try-syscall.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 Simon McVittie
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ *
+ * Try one or more system calls that might have been blocked by a
+ * seccomp filter. Return the last value of errno seen.
+ *
+ * In general, we pass a bad fd or pointer to each syscall that will
+ * accept one, so that it will fail with EBADF or EFAULT without side-effects.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define MISSING_SYSCALL_BASE 4000
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define MISSING_SYSCALL_BASE 5000
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define MISSING_SYSCALL_BASE 6000
+# else
+# error "Unknown MIPS ABI"
+# endif
+#endif
+
+#if defined(__ia64__)
+# define MISSING_SYSCALL_BASE 1024
+#endif
+
+#if defined(__alpha__)
+# define MISSING_SYSCALL_BASE 110
+#endif
+
+#if defined(__x86_64__) && defined(__ILP32__)
+# define MISSING_SYSCALL_BASE 0x40000000
+#endif
+
+/*
+ * MISSING_SYSCALL_BASE:
+ *
+ * Number to add to the syscall numbers of recently-added syscalls
+ * to get the appropriate syscall for the current ABI.
+ */
+#ifndef MISSING_SYSCALL_BASE
+# define MISSING_SYSCALL_BASE 0
+#endif
+
+#ifndef __NR_clone3
+# define __NR_clone3 (MISSING_SYSCALL_BASE + 435)
+#endif
+
+/*
+ * The size of clone3's parameter (as of 2021)
+ */
+#define SIZEOF_STRUCT_CLONE_ARGS ((size_t) 88)
+
+/*
+ * An invalid pointer that will cause syscalls to fail with EFAULT
+ */
+#define WRONG_POINTER ((char *) 1)
+
+int
+main (int argc, char **argv)
+{
+ int errsv = 0;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "print-errno-values") == 0)
+ {
+ printf ("EBADF=%d\n", EBADF);
+ printf ("EFAULT=%d\n", EFAULT);
+ printf ("ENOENT=%d\n", ENOENT);
+ printf ("ENOSYS=%d\n", ENOSYS);
+ printf ("EPERM=%d\n", EPERM);
+ }
+ else if (strcmp (arg, "chmod") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EFAULT */
+ if (chmod (WRONG_POINTER, 0700) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else if (strcmp (arg, "chroot") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EFAULT */
+ if (chroot (WRONG_POINTER) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else if (strcmp (arg, "clone3") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EFAULT */
+ if (syscall (__NR_clone3, WRONG_POINTER, SIZEOF_STRUCT_CLONE_ARGS) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else if (strcmp (arg, "ioctl TIOCNOTTY") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EBADF */
+ if (ioctl (-1, TIOCNOTTY) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else if (strcmp (arg, "ioctl TIOCSTI") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EBADF */
+ if (ioctl (-1, TIOCSTI, WRONG_POINTER) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+#ifdef __LP64__
+ else if (strcmp (arg, "ioctl TIOCSTI CVE-2019-10063") == 0)
+ {
+ unsigned long not_TIOCSTI = (0x123UL << 32) | (unsigned long) TIOCSTI;
+
+ /* If not blocked by seccomp, this will fail with EBADF */
+ if (syscall (__NR_ioctl, -1, not_TIOCSTI, WRONG_POINTER) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+#endif
+ else if (strcmp (arg, "listen") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EBADF */
+ if (listen (-1, 42) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else if (strcmp (arg, "prctl") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EFAULT */
+ if (prctl (PR_GET_CHILD_SUBREAPER, WRONG_POINTER, 0, 0, 0) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "Unsupported syscall \"%s\"\n", arg);
+ errsv = ENOENT;
+ }
+ }
+
+ return errsv;
+}

142
CVE-2023-28100-pre3.patch Normal file
View File

@ -0,0 +1,142 @@
From e7880e25b9d400feeaacb82f115fae676ce6c65d Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 21 Oct 2021 17:41:08 +0100
Subject: [PATCH] tests: Add basic test coverage for our seccomp filters
In particular, this checks that CVE-2017-5226, CVE-2019-10063 and
CVE-2021-41133 are still prevented.
Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 7c5aec474caef7aa004286cc9359611ad21d227b)
(cherry picked from commit ff0f5a15b26dac28c8efd88c8d47e51751df8043)
---
tests/Makefile-test-matrix.am.inc | 1 +
tests/Makefile.am.inc | 1 +
tests/test-seccomp.sh | 94 +++++++++++++++++++++++++++++++
3 files changed, 96 insertions(+)
create mode 100755 tests/test-seccomp.sh
diff --git a/tests/Makefile-test-matrix.am.inc b/tests/Makefile-test-matrix.am.inc
index f56c169e60..e1ec09ffb0 100644
--- a/tests/Makefile-test-matrix.am.inc
+++ b/tests/Makefile-test-matrix.am.inc
@@ -43,6 +43,7 @@ TEST_MATRIX_DIST= \
tests/test-override.sh \
tests/test-auth.sh \
tests/test-unused.sh \
+ tests/test-seccomp.sh \
$(NULL)
TEST_MATRIX_EXTRA_DIST= \
tests/test-run.sh \
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index 2548080254..fd13c0cd3d 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -237,6 +237,7 @@ TEST_MATRIX_SOURCE = \
tests/test-unused.sh \
tests/test-summaries.sh{user+system} \
tests/test-subset.sh{user+system} \
+ tests/test-seccomp.sh \
$(NULL)
update-test-matrix:
diff --git a/tests/test-seccomp.sh b/tests/test-seccomp.sh
new file mode 100755
index 0000000000..72b0dad231
--- /dev/null
+++ b/tests/test-seccomp.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# Copyright 2021 Collabora Ltd.
+# SPDX-License-Identifier: LGPL-2.0-or-later
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+skip_without_bwrap
+
+echo "1..16"
+
+setup_repo
+install_repo
+
+cp -a "$G_TEST_BUILDDIR/try-syscall" "$test_tmpdir/try-syscall"
+
+# How this works:
+# try-syscall tries to make various syscalls, some benign, some not.
+#
+# The parameters are chosen to make them fail with EBADF or EFAULT if
+# not blocked. If they are blocked, we get ENOSYS or EPERM. If the syscall
+# is impossible for a particular architecture, we get ENOENT.
+#
+# The exit status is an errno value, which we can compare with the expected
+# errno value.
+
+eval "$("$test_tmpdir/try-syscall" print-errno-values)"
+
+try_syscall () {
+ ${FLATPAK} run \
+ --filesystem="$test_tmpdir" \
+ --command="$test_tmpdir/try-syscall" \
+ $extra_argv \
+ org.test.Hello "$@"
+}
+
+for extra_argv in "" "--allow=multiarch"; do
+ echo "# testing with extra argv: '$extra_argv'"
+
+ echo "# chmod (benign)"
+ e=0
+ try_syscall chmod || e="$?"
+ assert_streq "$e" "$EFAULT"
+ ok "chmod not blocked"
+
+ echo "# chroot (harmful)"
+ e=0
+ try_syscall chroot || e="$?"
+ assert_streq "$e" "$EPERM"
+ ok "chroot blocked with EPERM"
+
+ echo "# clone3 (harmful)"
+ e=0
+ try_syscall clone3 || e="$?"
+ # This is either ENOSYS because the kernel genuinely doesn't implement it,
+ # or because we successfully blocked it. We can't tell which.
+ assert_streq "$e" "$ENOSYS"
+ ok "clone3 blocked with ENOSYS (CVE-2021-41133)"
+
+ echo "# ioctl TIOCNOTTY (benign)"
+ e=0
+ try_syscall "ioctl TIOCNOTTY" || e="$?"
+ assert_streq "$e" "$EBADF"
+ ok "ioctl TIOCNOTTY not blocked"
+
+ echo "# ioctl TIOCSTI (CVE-2017-5226)"
+ e=0
+ try_syscall "ioctl TIOCSTI" || e="$?"
+ assert_streq "$e" "$EPERM"
+ ok "ioctl TIOCSTI blocked (CVE-2017-5226)"
+
+ echo "# ioctl TIOCSTI (trying to repeat CVE-2019-10063)"
+ e=0
+ try_syscall "ioctl TIOCSTI CVE-2019-10063" || e="$?"
+ if test "$e" = "$ENOENT"; then
+ echo "ok # SKIP Cannot replicate CVE-2019-10063 on 32-bit architecture"
+ else
+ assert_streq "$e" "$EPERM"
+ ok "ioctl TIOCSTI with high bits blocked (CVE-2019-10063)"
+ fi
+
+ echo "# listen (benign)"
+ e=0
+ try_syscall "listen" || e="$?"
+ assert_streq "$e" "$EBADF"
+ ok "listen not blocked"
+
+ echo "# prctl (benign)"
+ e=0
+ try_syscall "prctl" || e="$?"
+ assert_streq "$e" "$EFAULT"
+ ok "prctl not blocked"
+done

85
CVE-2023-28100.patch Normal file
View File

@ -0,0 +1,85 @@
From a9bf18040cc075a70657c6090a59d7f6fe78f893 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@debian.org>
Date: Wed, 15 Mar 2023 09:58:56 +0000
Subject: [PATCH] run: Prevent TIOCLINUX ioctl, the same as TIOCSTI
The TIOCLINUX ioctl is only available on Linux virtual consoles such as
/dev/tty1. It has several Linux-specific functions, one of which is a
copy/paste operation which can be used for attacks similar to TIOCSTI.
This vulnerability does not affect typical graphical terminal emulators
such as xterm, gnome-terminal and Konsole, and Flatpak is primarily
designed to be run from a Wayland or X11 graphical environment, so this
is relatively unlikely to be a practical problem.
CVE-2023-28100, GHSA-7qpw-3vjv-xrqp
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-7qpw-3vjv-xrqp
Signed-off-by: Simon McVittie <smcv@debian.org>
---
common/flatpak-run.c | 4 ++++
tests/test-seccomp.sh | 8 +++++++-
tests/try-syscall.c | 9 +++++++++
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
index 1c43ca7205..c4dcaca9e6 100644
--- a/common/flatpak-run.c
+++ b/common/flatpak-run.c
@@ -2872,6 +2872,10 @@ setup_seccomp (FlatpakBwrap *bwrap,
/* Don't allow faking input to the controlling tty (CVE-2017-5226) */
{SCMP_SYS (ioctl), EPERM, &SCMP_A1 (SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int) TIOCSTI)},
+ /* In the unlikely event that the controlling tty is a Linux virtual
+ * console (/dev/tty2 or similar), copy/paste operations have an effect
+ * similar to TIOCSTI (CVE-2023-28100) */
+ {SCMP_SYS (ioctl), EPERM, &SCMP_A1 (SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int) TIOCLINUX)},
/* seccomp can't look into clone3()'s struct clone_args to check whether
* the flags are OK, so we have no choice but to block clone3().
diff --git a/tests/test-seccomp.sh b/tests/test-seccomp.sh
index 72b0dad231..be6fb085d0 100755
--- a/tests/test-seccomp.sh
+++ b/tests/test-seccomp.sh
@@ -8,7 +8,7 @@ set -euo pipefail
skip_without_bwrap
-echo "1..16"
+echo "1..18"
setup_repo
install_repo
@@ -80,6 +80,12 @@ for extra_argv in "" "--allow=multiarch"; do
ok "ioctl TIOCSTI with high bits blocked (CVE-2019-10063)"
fi
+ echo "# ioctl TIOCLINUX (CVE-2023-28100)"
+ e=0
+ try_syscall "ioctl TIOCLINUX" || e="$?"
+ assert_streq "$e" "$EPERM"
+ ok "ioctl TIOCLINUX blocked"
+
echo "# listen (benign)"
e=0
try_syscall "listen" || e="$?"
diff --git a/tests/try-syscall.c b/tests/try-syscall.c
index 84a0ca6673..9dab899ba3 100644
--- a/tests/try-syscall.c
+++ b/tests/try-syscall.c
@@ -144,6 +144,15 @@ main (int argc, char **argv)
}
}
#endif
+ else if (strcmp (arg, "ioctl TIOCLINUX") == 0)
+ {
+ /* If not blocked by seccomp, this will fail with EBADF */
+ if (ioctl (-1, TIOCLINUX, WRONG_POINTER) != 0)
+ {
+ errsv = errno;
+ perror (arg);
+ }
+ }
else if (strcmp (arg, "listen") == 0)
{
/* If not blocked by seccomp, this will fail with EBADF */

320
CVE-2023-28101-1.patch Normal file
View File

@ -0,0 +1,320 @@
From acd627a2fabe9856947399044dbf7aa79247c75b Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Date: Sat, 4 Mar 2023 16:23:37 -0600
Subject: [PATCH] Ensure special characters in permissions and metadata are
escaped
This prevents someone from placing special characters in order to
manipulate the appearance of the permissions list.
CVE-2023-28101, GHSA-h43h-fwqx-mpp8
Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
---
app/flatpak-builtins-info.c | 8 +++-
app/flatpak-builtins-remote-info.c | 5 +-
app/flatpak-cli-transaction.c | 12 +++--
common/flatpak-utils-private.h | 11 +++++
common/flatpak-utils.c | 77 ++++++++++++++++++++++++++++++
tests/make-test-app.sh | 8 ++++
tests/test-info.sh | 14 ++++--
tests/testcommon.c | 39 +++++++++++++++
8 files changed, 164 insertions(+), 10 deletions(-)
diff --git a/app/flatpak-builtins-info.c b/app/flatpak-builtins-info.c
index c13d2d89eb..35d49c446a 100644
--- a/app/flatpak-builtins-info.c
+++ b/app/flatpak-builtins-info.c
@@ -400,7 +400,9 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
if (!g_file_load_contents (file, cancellable, &data, &data_size, NULL, error))
return FALSE;
- g_print ("%s", data);
+ flatpak_print_escaped_string (data,
+ FLATPAK_ESCAPE_ALLOW_NEWLINES
+ | FLATPAK_ESCAPE_DO_NOT_QUOTE);
}
if (opt_show_permissions || opt_file_access)
@@ -421,7 +423,9 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
if (contents == NULL)
return FALSE;
- g_print ("%s", contents);
+ flatpak_print_escaped_string (contents,
+ FLATPAK_ESCAPE_ALLOW_NEWLINES
+ | FLATPAK_ESCAPE_DO_NOT_QUOTE);
}
if (opt_file_access)
diff --git a/app/flatpak-builtins-remote-info.c b/app/flatpak-builtins-remote-info.c
index 20705a97ca..0ab05b7ca4 100644
--- a/app/flatpak-builtins-remote-info.c
+++ b/app/flatpak-builtins-remote-info.c
@@ -441,7 +441,10 @@ flatpak_builtin_remote_info (int argc, char **argv, GCancellable *cancellable, G
if (opt_show_metadata)
{
- g_print ("%s", xa_metadata ? xa_metadata : "");
+ if (xa_metadata != NULL)
+ flatpak_print_escaped_string (xa_metadata,
+ FLATPAK_ESCAPE_ALLOW_NEWLINES
+ | FLATPAK_ESCAPE_DO_NOT_QUOTE);
if (xa_metadata == NULL || !g_str_has_suffix (xa_metadata, "\n"))
g_print ("\n");
}
diff --git a/app/flatpak-cli-transaction.c b/app/flatpak-cli-transaction.c
index a258f905c4..b915bedd04 100644
--- a/app/flatpak-cli-transaction.c
+++ b/app/flatpak-cli-transaction.c
@@ -894,12 +894,16 @@ print_perm_line (int idx,
int cols)
{
g_autoptr(GString) res = g_string_new (NULL);
+ g_autofree char *escaped_first_perm = NULL;
int i;
- g_string_append_printf (res, " [%d] %s", idx, (char *) items->pdata[0]);
+ escaped_first_perm = flatpak_escape_string (items->pdata[0], FLATPAK_ESCAPE_DEFAULT);
+ g_string_append_printf (res, " [%d] %s", idx, escaped_first_perm);
for (i = 1; i < items->len; i++)
{
+ g_autofree char *escaped = flatpak_escape_string (items->pdata[i],
+ FLATPAK_ESCAPE_DEFAULT);
char *p;
int len;
@@ -908,10 +912,10 @@ print_perm_line (int idx,
p = res->str;
len = (res->str + strlen (res->str)) - p;
- if (len + strlen ((char *) items->pdata[i]) + 2 >= cols)
- g_string_append_printf (res, ",\n %s", (char *) items->pdata[i]);
+ if (len + strlen (escaped) + 2 >= cols)
+ g_string_append_printf (res, ",\n %s", escaped);
else
- g_string_append_printf (res, ", %s", (char *) items->pdata[i]);
+ g_string_append_printf (res, ", %s", escaped);
}
g_print ("%s\n", res->str);
diff --git a/common/flatpak-utils-private.h b/common/flatpak-utils-private.h
index 1a92154706..c1282641f9 100644
--- a/common/flatpak-utils-private.h
+++ b/common/flatpak-utils-private.h
@@ -902,6 +902,17 @@ null_safe_g_ptr_array_unref (gpointer data)
g_clear_pointer (&data, g_ptr_array_unref);
}
+typedef enum {
+ FLATPAK_ESCAPE_DEFAULT = 0,
+ FLATPAK_ESCAPE_ALLOW_NEWLINES = 1 << 0,
+ FLATPAK_ESCAPE_DO_NOT_QUOTE = 1 << 1,
+} FlatpakEscapeFlags;
+
+char * flatpak_escape_string (const char *s,
+ FlatpakEscapeFlags flags);
+void flatpak_print_escaped_string (const char *s,
+ FlatpakEscapeFlags flags);
+
#define FLATPAK_MESSAGE_ID "c7b39b1e006b464599465e105b361485"
#endif /* __FLATPAK_UTILS_H__ */
diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c
index 3a5adb82ee..0b91ae3f91 100644
--- a/common/flatpak-utils.c
+++ b/common/flatpak-utils.c
@@ -8613,4 +8613,81 @@ flatpak_dconf_path_is_similar (const char *path1,
return (path1[i1] == '\0');
}
+static gboolean
+is_char_safe (gunichar c)
+{
+ return g_unichar_isgraph (c) || c == ' ';
+}
+
+static gboolean
+should_hex_escape (gunichar c,
+ FlatpakEscapeFlags flags)
+{
+ if ((flags & FLATPAK_ESCAPE_ALLOW_NEWLINES) && c == '\n')
+ return FALSE;
+ return !is_char_safe (c);
+}
+
+static void
+append_hex_escaped_character (GString *result,
+ gunichar c)
+{
+ if (c <= 0xFF)
+ g_string_append_printf (result, "\\x%02X", c);
+ else if (c <= 0xFFFF)
+ g_string_append_printf (result, "\\u%04X", c);
+ else
+ g_string_append_printf (result, "\\U%08X", c);
+}
+
+char *
+flatpak_escape_string (const char *s,
+ FlatpakEscapeFlags flags)
+{
+ g_autoptr(GString) res = g_string_new ("");
+ gboolean did_escape = FALSE;
+
+ while (*s)
+ {
+ gunichar c = g_utf8_get_char_validated (s, -1);
+ if (c == (gunichar)-2 || c == (gunichar)-1)
+ {
+ /* Need to convert to unsigned first, to avoid negative chars becoming
+ huge gunichars. */
+ append_hex_escaped_character (res, (unsigned char)*s++);
+ did_escape = TRUE;
+ continue;
+ }
+ else if (should_hex_escape (c, flags))
+ {
+ append_hex_escaped_character (res, c);
+ did_escape = TRUE;
+ }
+ else if (c == '\\' || (!(flags & FLATPAK_ESCAPE_DO_NOT_QUOTE) && c == '\''))
+ {
+ g_string_append_printf (res, "\\%c", (char) c);
+ did_escape = TRUE;
+ }
+ else
+ g_string_append_unichar (res, c);
+
+ s = g_utf8_find_next_char (s, NULL);
+ }
+
+ if (did_escape && !(flags & FLATPAK_ESCAPE_DO_NOT_QUOTE))
+ {
+ g_string_prepend_c (res, '\'');
+ g_string_append_c (res, '\'');
+ }
+
+ return g_string_free (g_steal_pointer (&res), FALSE);
+}
+
+void
+flatpak_print_escaped_string (const char *s,
+ FlatpakEscapeFlags flags)
+{
+ g_autofree char *escaped = flatpak_escape_string (s, flags);
+ g_print ("%s", escaped);
+}
diff --git a/tests/make-test-app.sh b/tests/make-test-app.sh
index 731160535c..125e97f6b5 100755
--- a/tests/make-test-app.sh
+++ b/tests/make-test-app.sh
@@ -40,6 +40,14 @@ required-flatpak=$REQUIRED_VERSION
EOF
fi
+if [ x${INCLUDE_SPECIAL_CHARACTER-} != x ]; then
+TAB=$'\t'
+cat >> ${DIR}/metadata <<EOF
+[Environment]
+A=x${TAB}y
+EOF
+fi
+
cat >> ${DIR}/metadata <<EOF
[Extension $APP_ID.Locale]
directory=share/runtime/locale
diff --git a/tests/test-info.sh b/tests/test-info.sh
index 4a247bdb48..2158c11b10 100644
--- a/tests/test-info.sh
+++ b/tests/test-info.sh
@@ -6,9 +6,9 @@ set -euo pipefail
skip_revokefs_without_fuse
-echo "1..7"
+echo "1..8"
-setup_repo
+INCLUDE_SPECIAL_CHARACTER=1 setup_repo
install_repo
COMMIT=`${FLATPAK} ${U} info --show-commit org.test.Hello`
@@ -19,9 +19,17 @@ assert_file_has_content info "^app/org\.test\.Hello/$(flatpak --default-arch)/ma
ok "info -rcos"
+${FLATPAK} info --show-metadata org.test.Hello > info
+
+# CVE-2023-28101
+assert_file_has_content info "name=org\.test\.Hello"
+assert_file_has_content info "^A=x\\\\x09y"
+
+ok "info --show-metadata"
+
${FLATPAK} info --show-permissions org.test.Hello > info
-assert_file_empty info
+assert_file_has_content info "^A=x\\\\x09y"
ok "info --show-permissions"
diff --git a/tests/testcommon.c b/tests/testcommon.c
index 1d217c072a..daae5e4aac 100644
--- a/tests/testcommon.c
+++ b/tests/testcommon.c
@@ -1557,6 +1557,44 @@ test_dconf_paths (void)
}
}
+typedef struct {
+ const char *in;
+ FlatpakEscapeFlags flags;
+ const char *out;
+} EscapeData;
+
+static EscapeData escapes[] = {
+ {"abc def", FLATPAK_ESCAPE_DEFAULT, "abc def"},
+ {"やあ", FLATPAK_ESCAPE_DEFAULT, "やあ"},
+ {"\033[;1m", FLATPAK_ESCAPE_DEFAULT, "'\\x1B[;1m'"},
+ // non-printable U+061C
+ {"\u061C", FLATPAK_ESCAPE_DEFAULT, "'\\u061C'"},
+ // non-printable U+1343F
+ {"\xF0\x93\x90\xBF", FLATPAK_ESCAPE_DEFAULT, "'\\U0001343F'"},
+ // invalid utf-8
+ {"\xD8\1", FLATPAK_ESCAPE_DEFAULT, "'\\xD8\\x01'"},
+ {"\b \n abc ' \\", FLATPAK_ESCAPE_DEFAULT, "'\\x08 \\x0A abc \\' \\\\'"},
+ {"\b \n abc ' \\", FLATPAK_ESCAPE_DO_NOT_QUOTE, "\\x08 \\x0A abc ' \\\\"},
+ {"abc\tdef\n\033[;1m ghi\b", FLATPAK_ESCAPE_ALLOW_NEWLINES | FLATPAK_ESCAPE_DO_NOT_QUOTE,
+ "abc\\x09def\n\\x1B[;1m ghi\\x08"},
+};
+
+/* CVE-2023-28101 */
+static void
+test_string_escape (void)
+{
+ gsize idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (escapes); idx++)
+ {
+ EscapeData *data = &escapes[idx];
+ g_autofree char *ret = NULL;
+
+ ret = flatpak_escape_string (data->in, data->flags);
+ g_assert_cmpstr (ret, ==, data->out);
+ }
+}
+
int
main (int argc, char *argv[])
{
@@ -1585,6 +1623,7 @@ main (int argc, char *argv[])
g_test_add_func ("/common/dconf-app-id", test_dconf_app_id);
g_test_add_func ("/common/dconf-paths", test_dconf_paths);
g_test_add_func ("/common/decompose-ref", test_decompose);
+ g_test_add_func ("/common/string-escape", test_string_escape);
g_test_add_func ("/app/looks-like-branch", test_looks_like_branch);
g_test_add_func ("/app/columns", test_columns);

408
CVE-2023-28101-2.patch Normal file
View File

@ -0,0 +1,408 @@
From e88eedce76f79a5573df4fc38b344bbeaf7af024 Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Date: Sat, 4 Mar 2023 21:07:03 -0600
Subject: [PATCH] Reject paths given to --filesystem/--persist with special
characters
There isn't much in the way of legit reasons for this, but it's a
potential security footgun when displaying the text.
CVE-2023-28101, GHSA-h43h-fwqx-mpp8
Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Co-authored-by: Simon McVittie <smcv@collabora.com>
---
common/flatpak-context.c | 36 ++++++++++++---
common/flatpak-utils-private.h | 3 ++
common/flatpak-utils.c | 40 ++++++++++++++++
tests/test-context.c | 84 ++++++++++++++++++++++++++++++++--
tests/testcommon.c | 41 +++++++++++++++--
5 files changed, 190 insertions(+), 14 deletions(-)
diff --git a/common/flatpak-context.c b/common/flatpak-context.c
index 9c506499a4..512a577f81 100644
--- a/common/flatpak-context.c
+++ b/common/flatpak-context.c
@@ -487,11 +487,17 @@ flatpak_context_apply_generic_policy (FlatpakContext *context,
g_ptr_array_free (new, FALSE));
}
-static void
+
+static gboolean
flatpak_context_set_persistent (FlatpakContext *context,
- const char *path)
+ const char *path,
+ GError **error)
{
+ if (!flatpak_validate_path_characters (path, error))
+ return FALSE;
+
g_hash_table_insert (context->persistent, g_strdup (path), GINT_TO_POINTER (1));
+ return TRUE;
}
static gboolean
@@ -853,6 +859,9 @@ flatpak_context_parse_filesystem (const char *filesystem_and_mode,
g_autofree char *filesystem = NULL;
char *slash;
+ if (!flatpak_validate_path_characters (filesystem_and_mode, error))
+ return FALSE;
+
filesystem = parse_filesystem_flags (filesystem_and_mode, negated, mode_out, error);
if (filesystem == NULL)
return FALSE;
@@ -1484,8 +1493,7 @@ option_persist_cb (const gchar *option_name,
{
FlatpakContext *context = data;
- flatpak_context_set_persistent (context, value);
- return TRUE;
+ return flatpak_context_set_persistent (context, value, error);
}
static gboolean option_no_desktop_deprecated;
@@ -1677,11 +1685,24 @@ flatpak_context_load_metadata (FlatpakContext *context,
{
const char *fs = parse_negated (filesystems[i], &remove);
g_autofree char *filesystem = NULL;
+ g_autoptr(GError) local_error = NULL;
FlatpakFilesystemMode mode;
if (!flatpak_context_parse_filesystem (fs, remove,
- &filesystem, &mode, NULL))
- g_debug ("Unknown filesystem type %s", filesystems[i]);
+ &filesystem, &mode, &local_error))
+ {
+ if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA))
+ {
+ /* Invalid characters, so just hard-fail. */
+ g_propagate_error (error, g_steal_pointer (&local_error));
+ return FALSE;
+ }
+ else
+ {
+ g_debug ("Unknown filesystem type %s", filesystems[i]);
+ g_clear_error (&local_error);
+ }
+ }
else
{
g_assert (mode == FLATPAK_FILESYSTEM_MODE_NONE || !remove);
@@ -1698,7 +1719,8 @@ flatpak_context_load_metadata (FlatpakContext *context,
return FALSE;
for (i = 0; persistent[i] != NULL; i++)
- flatpak_context_set_persistent (context, persistent[i]);
+ if (!flatpak_context_set_persistent (context, persistent[i], error))
+ return FALSE;
}
if (g_key_file_has_group (metakey, FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY))
diff --git a/common/flatpak-utils-private.h b/common/flatpak-utils-private.h
index c1282641f9..195023c20f 100644
--- a/common/flatpak-utils-private.h
+++ b/common/flatpak-utils-private.h
@@ -913,6 +913,9 @@ char * flatpak_escape_string (const char *s,
void flatpak_print_escaped_string (const char *s,
FlatpakEscapeFlags flags);
+gboolean flatpak_validate_path_characters (const char *path,
+ GError **error);
+
#define FLATPAK_MESSAGE_ID "c7b39b1e006b464599465e105b361485"
#endif /* __FLATPAK_UTILS_H__ */
diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c
index 0b91ae3f91..b562522e58 100644
--- a/common/flatpak-utils.c
+++ b/common/flatpak-utils.c
@@ -8641,6 +8641,14 @@ append_hex_escaped_character (GString *result,
g_string_append_printf (result, "\\U%08X", c);
}
+static char *
+escape_character (gunichar c)
+{
+ g_autoptr(GString) res = g_string_new ("");
+ append_hex_escaped_character (res, c);
+ return g_string_free (g_steal_pointer (&res), FALSE);
+}
+
char *
flatpak_escape_string (const char *s,
FlatpakEscapeFlags flags)
@@ -8691,3 +8699,35 @@ flatpak_print_escaped_string (const char *s,
g_autofree char *escaped = flatpak_escape_string (s, flags);
g_print ("%s", escaped);
}
+
+gboolean
+flatpak_validate_path_characters (const char *path,
+ GError **error)
+{
+ while (*path)
+ {
+ gunichar c = g_utf8_get_char_validated (path, -1);
+ if (c == (gunichar)-1 || c == (gunichar)-2)
+ {
+ /* Need to convert to unsigned first, to avoid negative chars becoming
+ huge gunichars. */
+ g_autofree char *escaped_char = escape_character ((unsigned char)*path);
+ g_autofree char *escaped = flatpak_escape_string (path, FLATPAK_ESCAPE_DEFAULT);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ "Non-UTF8 byte %s in path %s", escaped_char, escaped);
+ return FALSE;
+ }
+ else if (!is_char_safe (c))
+ {
+ g_autofree char *escaped_char = escape_character (c);
+ g_autofree char *escaped = flatpak_escape_string (path, FLATPAK_ESCAPE_DEFAULT);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ "Non-graphical character %s in path %s", escaped_char, escaped);
+ return FALSE;
+ }
+
+ path = g_utf8_find_next_char (path, NULL);
+ }
+
+ return TRUE;
+}
diff --git a/tests/test-context.c b/tests/test-context.c
index c128a83fae..6c15feb013 100644
--- a/tests/test-context.c
+++ b/tests/test-context.c
@@ -34,13 +34,14 @@ str_has_prefix (gconstpointer candidate,
}
static void context_parse_args (FlatpakContext *context,
+ GError **error,
...) G_GNUC_NULL_TERMINATED;
static void
context_parse_args (FlatpakContext *context,
+ GError **error,
...)
{
- g_autoptr(GError) local_error = NULL;
g_autoptr(GOptionContext) oc = NULL;
g_autoptr(GOptionGroup) group = NULL;
g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free);
@@ -50,7 +51,7 @@ context_parse_args (FlatpakContext *context,
g_ptr_array_add (args, g_strdup ("argv[0]"));
- va_start (ap, context);
+ va_start (ap, error);
while ((arg = va_arg (ap, const char *)) != NULL)
g_ptr_array_add (args, g_strdup (arg));
@@ -63,8 +64,7 @@ context_parse_args (FlatpakContext *context,
oc = g_option_context_new ("");
group = flatpak_context_get_options (context);
g_option_context_add_group (oc, group);
- g_option_context_parse_strv (oc, &argv, &local_error);
- g_assert_no_error (local_error);
+ g_option_context_parse_strv (oc, &argv, error);
}
static void
@@ -84,19 +84,26 @@ test_context_merge_fs (void)
g_autoptr(FlatpakContext) lowest = flatpak_context_new ();
g_autoptr(FlatpakContext) middle = flatpak_context_new ();
g_autoptr(FlatpakContext) highest = flatpak_context_new ();
+ g_autoptr(GError) local_error = NULL;
gpointer value;
context_parse_args (lowest,
+ &local_error,
"--filesystem=/one",
NULL);
+ g_assert_no_error (local_error);
context_parse_args (middle,
+ &local_error,
"--nofilesystem=host:reset",
"--filesystem=/two",
NULL);
+ g_assert_no_error (local_error);
context_parse_args (highest,
+ &local_error,
"--nofilesystem=host",
"--filesystem=/three",
NULL);
+ g_assert_no_error (local_error);
g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL));
g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL));
@@ -178,20 +185,28 @@ test_context_merge_fs (void)
gpointer value;
context_parse_args (lowest,
+ &local_error,
"--filesystem=/one",
NULL);
+ g_assert_no_error (local_error);
context_parse_args (mid_low,
+ &local_error,
"--nofilesystem=host:reset",
"--filesystem=/two",
NULL);
+ g_assert_no_error (local_error);
context_parse_args (mid_high,
+ &local_error,
"--filesystem=host",
"--filesystem=/three",
NULL);
+ g_assert_no_error (local_error);
context_parse_args (highest,
+ &local_error,
"--nofilesystem=host",
"--filesystem=/four",
NULL);
+ g_assert_no_error (local_error);
g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL));
g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL));
@@ -332,12 +347,73 @@ test_context_merge_fs (void)
}
}
+const char *invalid_path_args[] = {
+ "--filesystem=/\033[J:ro",
+ "--filesystem=/\033[J",
+ "--persist=\033[J",
+};
+
+/* CVE-2023-28101 */
+static void
+test_validate_path_args (void)
+{
+ gsize idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (invalid_path_args); idx++)
+ {
+ g_autoptr(FlatpakContext) context = flatpak_context_new ();
+ g_autoptr(GError) local_error = NULL;
+ const char *path = invalid_path_args[idx];
+
+ context_parse_args (context, &local_error, path, NULL);
+ g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
+ g_assert (strstr (local_error->message, "Non-graphical character"));
+ }
+}
+
+typedef struct {
+ const char *key;
+ const char *value;
+} PathValidityData;
+
+PathValidityData invalid_path_meta[] = {
+ {FLATPAK_METADATA_KEY_FILESYSTEMS, "\033[J"},
+ {FLATPAK_METADATA_KEY_PERSISTENT, "\033[J"},
+};
+
+/* CVE-2023-28101 */
+static void
+test_validate_path_meta (void)
+{
+ gsize idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (invalid_path_meta); idx++)
+ {
+ g_autoptr(FlatpakContext) context = flatpak_context_new ();
+ g_autoptr(GKeyFile) metakey = g_key_file_new ();
+ g_autoptr(GError) local_error = NULL;
+ PathValidityData *data = &invalid_path_meta[idx];
+ gboolean ret = FALSE;
+
+ g_key_file_set_string_list (metakey, FLATPAK_METADATA_GROUP_CONTEXT,
+ data->key, &data->value, 1);
+
+ ret = flatpak_context_load_metadata (context, metakey, &local_error);
+ g_assert_false (ret);
+ g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
+ g_assert (strstr (local_error->message, "Non-graphical character"));
+ }
+
+}
+
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/context/merge-fs", test_context_merge_fs);
+ g_test_add_func ("/context/validate-path-args", test_validate_path_args);
+ g_test_add_func ("/context/validate-path-meta", test_validate_path_meta);
return g_test_run ();
}
diff --git a/tests/testcommon.c b/tests/testcommon.c
index daae5e4aac..0840632575 100644
--- a/tests/testcommon.c
+++ b/tests/testcommon.c
@@ -1567,11 +1567,12 @@ static EscapeData escapes[] = {
{"abc def", FLATPAK_ESCAPE_DEFAULT, "abc def"},
{"やあ", FLATPAK_ESCAPE_DEFAULT, "やあ"},
{"\033[;1m", FLATPAK_ESCAPE_DEFAULT, "'\\x1B[;1m'"},
- // non-printable U+061C
+ /* U+061C ARABIC LETTER MARK, non-printable */
{"\u061C", FLATPAK_ESCAPE_DEFAULT, "'\\u061C'"},
- // non-printable U+1343F
+ /* U+1343F EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE, non-printable and
+ * outside BMP */
{"\xF0\x93\x90\xBF", FLATPAK_ESCAPE_DEFAULT, "'\\U0001343F'"},
- // invalid utf-8
+ /* invalid utf-8 */
{"\xD8\1", FLATPAK_ESCAPE_DEFAULT, "'\\xD8\\x01'"},
{"\b \n abc ' \\", FLATPAK_ESCAPE_DEFAULT, "'\\x08 \\x0A abc \\' \\\\'"},
{"\b \n abc ' \\", FLATPAK_ESCAPE_DO_NOT_QUOTE, "\\x08 \\x0A abc ' \\\\"},
@@ -1595,6 +1596,39 @@ test_string_escape (void)
}
}
+typedef struct {
+ const char *path;
+ gboolean ret;
+} PathValidityData;
+
+static PathValidityData paths[] = {
+ {"/a/b/../c.def", TRUE},
+ {"やあ", TRUE},
+ /* U+061C ARABIC LETTER MARK, non-printable */
+ {"\u061C", FALSE},
+ /* U+1343F EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE, non-printable and
+ * outside BMP */
+ {"\xF0\x93\x90\xBF", FALSE},
+ /* invalid utf-8 */
+ {"\xD8\1", FALSE},
+};
+
+/* CVE-2023-28101 */
+static void
+test_validate_path_characters (void)
+{
+ gsize idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (paths); idx++)
+ {
+ PathValidityData *data = &paths[idx];
+ gboolean ret = FALSE;
+
+ ret = flatpak_validate_path_characters (data->path, NULL);
+ g_assert_cmpint (ret, ==, data->ret);
+ }
+}
+
int
main (int argc, char *argv[])
{
@@ -1624,6 +1658,7 @@ main (int argc, char *argv[])
g_test_add_func ("/common/dconf-paths", test_dconf_paths);
g_test_add_func ("/common/decompose-ref", test_decompose);
g_test_add_func ("/common/string-escape", test_string_escape);
+ g_test_add_func ("/common/validate-path-characters", test_validate_path_characters);
g_test_add_func ("/app/looks-like-branch", test_looks_like_branch);
g_test_add_func ("/app/columns", test_columns);

70
CVE-2024-32462.patch Normal file
View File

@ -0,0 +1,70 @@
From 72016e3fce8fcbeab707daf4f1a02b931fcc004d Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Mon, 15 Apr 2024 16:10:36 +0200
Subject: [PATCH] When starting non-static command using bwrap use "--"
Origin: https://github.com/flatpak/flatpak/commit/72016e3fce8fcbeab707daf4f1a02b931fcc004d
This ensures that the command is not taken to be a bwrap option.
Resolves: CVE-2024-32462
Resolves: GHSA-phv6-cpc2-2fgj
Signed-off-by: Alexander Larsson <alexl@redhat.com>
[smcv: Fix DISABLE_SANDBOXED_TRIGGERS code path]
[smcv: Make flatpak_run_maybe_start_dbus_proxy() more obviously correct]
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
app/flatpak-builtins-build.c | 3 ++-
common/flatpak-dir.c | 1 +
common/flatpak-run.c | 5 ++++-
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/app/flatpak-builtins-build.c b/app/flatpak-builtins-build.c
index c0b12dbca1..761af9a1b0 100644
--- a/app/flatpak-builtins-build.c
+++ b/app/flatpak-builtins-build.c
@@ -576,7 +576,8 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
return FALSE;
- flatpak_bwrap_add_args (bwrap, command, NULL);
+ flatpak_bwrap_add_args (bwrap, "--", command, NULL);
+
flatpak_bwrap_append_argsv (bwrap,
&argv[rest_argv_start + 2],
rest_argc - 2);
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index 6e07d08e3d..296a7dfd78 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -6653,6 +6653,7 @@ flatpak_dir_run_triggers (FlatpakDir *self,
"--proc", "/proc",
"--dev", "/dev",
"--bind", basedir, basedir,
+ "--",
NULL);
#endif
flatpak_bwrap_add_args (bwrap,
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
index c4dcaca9e6..7a3900c651 100644
--- a/common/flatpak-run.c
+++ b/common/flatpak-run.c
@@ -1082,6 +1082,9 @@ add_bwrap_wrapper (FlatpakBwrap *bwrap,
if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
return FALSE;
+ /* End of options: the next argument will be the executable name */
+ flatpak_bwrap_add_arg (bwrap, "--");
+
return TRUE;
}
@@ -4175,7 +4178,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref,
if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
return FALSE;
- flatpak_bwrap_add_arg (bwrap, command);
+ flatpak_bwrap_add_args (bwrap, "--", command, NULL);
if (!add_rest_args (bwrap, app_id,
exports, (flags & FLATPAK_RUN_FLAG_FILE_FORWARDING) != 0,

225
CVE-2024-42472.patch Normal file
View File

@ -0,0 +1,225 @@
Origin:
https://github.com/flatpak/flatpak/commit/8a18137d7e80f0575e8defabf677d81e5cc3a788
https://github.com/flatpak/flatpak/commit/db3a785241fda63bf53f0ec12bb519aa5210de19
https://github.com/flatpak/flatpak/commit/847dfb88cebbdf8825332730b837489684dfb91e
https://github.com/flatpak/flatpak/commit/7c63e53bb2af0aae9097fd2edfd6a9ba9d453e97
From 7c63e53bb2af0aae9097fd2edfd6a9ba9d453e97 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 14 Aug 2024 13:44:30 +0100
Subject: [PATCH] persist directories: Pass using new bwrap --bind-fd option
Instead of passing a /proc/self/fd bind mount we use --bind-fd, which
has two advantages:
* bwrap closes the fd when used, so it doesn't leak into the started app
* bwrap ensures that what was mounted was the passed in fd (same dev/ino),
as there is a small (required) gap between symlink resolve and mount
where the target path could be replaced.
Please note that this change requires an updated version of bubblewrap.
Resolves: CVE-2024-42472, GHSA-7hgv-f2j8-xw87
[smcv: Make whitespace consistent]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
common/flatpak-context.c | 109 +++++++++++++++++++++++++++++++++++++--
configure.ac | 3 ++
tests/test-run.sh | 39 ++++++++++++++
3 files changed, 148 insertions(+), 3 deletions(-)
diff --git a/common/flatpak-context.c b/common/flatpak-context.c
index 6303c71..09dd440 100644
--- a/common/flatpak-context.c
+++ b/common/flatpak-context.c
@@ -2616,6 +2616,90 @@ flatpak_context_get_run_flags (FlatpakContext *context)
return flags;
}
+/* This creates zero or more directories unders base_fd+basedir, each
+ * being guaranteed to either exist and be a directory (no symlinks)
+ * or be created as a directory. The last directory is opened
+ * and the fd is returned.
+ */
+static gboolean
+mkdir_p_open_nofollow_at (int base_fd,
+ const char *basedir,
+ int mode,
+ const char *subdir,
+ int *out_fd,
+ GError **error)
+{
+ glnx_autofd int parent_fd = -1;
+
+ if (g_path_is_absolute (subdir))
+ {
+ const char *skipped_prefix = subdir;
+
+ while (*skipped_prefix == '/')
+ skipped_prefix++;
+
+ g_warning ("--persist=\"%s\" is deprecated, treating it as --persist=\"%s\"", subdir, skipped_prefix);
+ subdir = skipped_prefix;
+ }
+
+ g_autofree char *subdir_dirname = g_path_get_dirname (subdir);
+
+ if (strcmp (subdir_dirname, ".") == 0)
+ {
+ /* It is ok to open basedir with follow=true */
+ if (!glnx_opendirat (base_fd, basedir, TRUE, &parent_fd, error))
+ return FALSE;
+ }
+ else if (strcmp (subdir_dirname, "..") == 0)
+ {
+ return glnx_throw (error, "'..' not supported in --persist paths");
+ }
+ else
+ {
+ if (!mkdir_p_open_nofollow_at (base_fd, basedir, mode,
+ subdir_dirname, &parent_fd, error))
+ return FALSE;
+ }
+
+ g_autofree char *subdir_basename = g_path_get_basename (subdir);
+
+ if (strcmp (subdir_basename, ".") == 0)
+ {
+ *out_fd = glnx_steal_fd (&parent_fd);
+ return TRUE;
+ }
+ else if (strcmp (subdir_basename, "..") == 0)
+ {
+ return glnx_throw (error, "'..' not supported in --persist paths");
+ }
+
+ if (!glnx_shutil_mkdir_p_at (parent_fd, subdir_basename, mode, NULL, error))
+ return FALSE;
+
+ int fd = openat (parent_fd, subdir_basename, O_PATH | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
+ if (fd == -1)
+ {
+ int saved_errno = errno;
+ struct stat stat_buf;
+
+ /* If it's a symbolic link, that could be a user trying to offload
+ * large data to another filesystem, but it could equally well be
+ * a malicious or compromised app trying to exploit GHSA-7hgv-f2j8-xw87.
+ * Produce a clearer error message in this case.
+ * Unfortunately the errno we get in this case is ENOTDIR, so we have
+ * to ask again to find out whether it's really a symlink. */
+ if (saved_errno == ENOTDIR &&
+ fstatat (parent_fd, subdir_basename, &stat_buf, AT_SYMLINK_NOFOLLOW) == 0 &&
+ S_ISLNK (stat_buf.st_mode))
+ return glnx_throw (error, "Symbolic link \"%s\" not allowed to avoid sandbox escape", subdir_basename);
+
+ return glnx_throw_errno_prefix (error, "openat(%s)", subdir_basename);
+ }
+
+ *out_fd = fd;
+ return TRUE;
+}
+
void
flatpak_context_append_bwrap_filesystem (FlatpakContext *context,
FlatpakBwrap *bwrap,
@@ -2643,12 +2727,31 @@ flatpak_context_append_bwrap_filesystem (FlatpakContext *context,
while (g_hash_table_iter_next (&iter, &key, NULL))
{
const char *persist = key;
- g_autofree char *src = g_build_filename (g_get_home_dir (), ".var/app", app_id, persist, NULL);
+ g_autofree char *appdir = g_build_filename (g_get_home_dir (), ".var/app", app_id, NULL);
g_autofree char *dest = g_build_filename (g_get_home_dir (), persist, NULL);
- g_mkdir_with_parents (src, 0755);
+ g_autoptr(GError) local_error = NULL;
+
+ if (g_mkdir_with_parents (appdir, 0755) != 0)
+ {
+ g_warning ("Unable to create directory %s", appdir);
+ continue;
+ }
+
+ /* Don't follow symlinks from the persist directory, as it is under user control */
+ glnx_autofd int src_fd = -1;
+ if (!mkdir_p_open_nofollow_at (AT_FDCWD, appdir, 0755,
+ persist, &src_fd,
+ &local_error))
+ {
+ g_warning ("Failed to create persist path %s: %s", persist, local_error->message);
+ continue;
+ }
+
+ g_autofree char *src_via_proc = g_strdup_printf ("%d", src_fd);
- flatpak_bwrap_add_bind_arg (bwrap, "--bind", src, dest);
+ flatpak_bwrap_add_fd (bwrap, glnx_steal_fd (&src_fd));
+ flatpak_bwrap_add_bind_arg (bwrap, "--bind-fd", src_via_proc, dest);
}
}
diff --git a/configure.ac b/configure.ac
index 8bf37b0..0862ae5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -175,6 +175,9 @@ if test "x$BWRAP" != xfalse; then
BWRAP_VERSION=`$BWRAP --version | sed 's,.*\ \([0-9]*\.[0-9]*\.[0-9]*\)$,\1,'`
AX_COMPARE_VERSION([$SYSTEM_BWRAP_REQS],[gt],[$BWRAP_VERSION],
[AC_MSG_ERROR([You need at least version $SYSTEM_BWRAP_REQS of bubblewrap to use the system installed version])])
+ AS_IF([$BWRAP --help | grep '@<:@-@:>@-bind-fd' >/dev/null],
+ [:],
+ [AC_MSG_ERROR([$BWRAP does not list required option --bind-fd in its --help])])
AM_CONDITIONAL([WITH_SYSTEM_BWRAP], [true])
else
AC_CHECK_LIB(cap, cap_from_text, CAP_LIB=-lcap)
diff --git a/tests/test-run.sh b/tests/test-run.sh
index 3c344df..f087ff2 100644
--- a/tests/test-run.sh
+++ b/tests/test-run.sh
@@ -494,3 +494,42 @@ ${FLATPAK} ${U} info -m org.test.App > out
assert_file_has_content out "^sdk=org\.test\.Sdk/$(flatpak --default-arch)/stable$"
ok "--sdk option"
+
+rm -fr "$HOME/.var/app/org.test.Hello"
+mkdir -p "$HOME/.var/app/org.test.Hello"
+run --command=sh --persist=.persist org.test.Hello -c 'echo can-persist > .persist/rc'
+sed -e 's,^,#--persist=.persist# ,g' < "$HOME/.var/app/org.test.Hello/.persist/rc" >&2
+assert_file_has_content "$HOME/.var/app/org.test.Hello/.persist/rc" "can-persist"
+
+ok "--persist=.persist persists a directory"
+
+rm -fr "$HOME/.var/app/org.test.Hello"
+mkdir -p "$HOME/.var/app/org.test.Hello"
+# G_DEBUG= to avoid the deprecation warning being fatal
+G_DEBUG= run --command=sh --persist=/.persist org.test.Hello -c 'echo can-persist > .persist/rc'
+sed -e 's,^,#--persist=/.persist# ,g' < "$HOME/.var/app/org.test.Hello/.persist/rc" >&2
+assert_file_has_content "$HOME/.var/app/org.test.Hello/.persist/rc" "can-persist"
+
+ok "--persist=/.persist is a deprecated form of --persist=.persist"
+
+rm -fr "$HOME/.var/app/org.test.Hello"
+mkdir -p "$HOME/.var/app/org.test.Hello"
+run --command=sh --persist=. org.test.Hello -c 'echo can-persist > .persistrc'
+sed -e 's,^,#--persist=.# ,g' < "$HOME/.var/app/org.test.Hello/.persistrc" >&2
+assert_file_has_content "$HOME/.var/app/org.test.Hello/.persistrc" "can-persist"
+
+ok "--persist=. persists all files"
+
+mkdir "${TEST_DATA_DIR}/inaccessible"
+echo FOO > ${TEST_DATA_DIR}/inaccessible/secret-file
+rm -fr "$HOME/.var/app/org.test.Hello"
+mkdir -p "$HOME/.var/app/org.test.Hello"
+ln -fns "${TEST_DATA_DIR}/inaccessible" "$HOME/.var/app/org.test.Hello/persist"
+# G_DEBUG= to avoid the warnings being fatal when we reject a --persist option.
+# LC_ALL=C so we get the expected non-localized string.
+LC_ALL=C G_DEBUG= run --command=ls --persist=persist --persist=relative/../escape org.test.Hello -la ~/persist &> hello_out || true
+sed -e 's,^,#--persist=symlink# ,g' < hello_out >&2
+assert_file_has_content hello_out "not allowed to avoid sandbox escape"
+assert_not_file_has_content hello_out "secret-file"
+
+ok "--persist doesn't allow sandbox escape via a symlink (CVE-2024-42472)"
--
2.33.0

View File

@ -0,0 +1,210 @@
From 54ec1a482dfc668127eaae57f135e6a8e0bc52da Mon Sep 17 00:00:00 2001
From: Phaedrus Leeds <mwleeds@protonmail.com>
Date: Tue, 28 Dec 2021 11:48:16 -0800
Subject: [PATCH] Add test for metadata validation
This tests for invalid metadata, missing xa.metadata and mismatched
values in xa.metadata and the real metadata, including the embedded
null leading to the hidden permissions of CVE-2021-43860.
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/54ec1a482dfc668127eaae57f135e6a8e0bc52da
---
tests/Makefile-test-matrix.am.inc | 1 +
tests/Makefile.am.inc | 1 +
tests/test-metadata-validation.sh | 158 ++++++++++++++++++++++++++++++
3 files changed, 160 insertions(+)
create mode 100644 tests/test-metadata-validation.sh
diff --git a/tests/Makefile-test-matrix.am.inc b/tests/Makefile-test-matrix.am.inc
index 30b402d..eef5a7e 100644
--- a/tests/Makefile-test-matrix.am.inc
+++ b/tests/Makefile-test-matrix.am.inc
@@ -36,6 +36,7 @@ TEST_MATRIX_DIST= \
tests/test-build-update-repo.sh \
tests/test-http-utils.sh \
tests/test-default-remotes.sh \
+ tests/test-metadata-validation.sh \
tests/test-extensions.sh \
tests/test-oci.sh \
tests/test-override.sh \
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index 2458445..53d6403 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -216,6 +216,7 @@ TEST_MATRIX_SOURCE = \
tests/test-repo.sh{{user+system+system-norevokefs}+{{user+system},oldsummary}} \
tests/test-sideload.sh{user+system} \
tests/test-default-remotes.sh \
+ tests/test-metadata-validation.sh \
tests/test-extensions.sh \
tests/test-bundle.sh{user+system+system-norevokefs} \
tests/test-oci.sh \
diff --git a/tests/test-metadata-validation.sh b/tests/test-metadata-validation.sh
new file mode 100644
index 0000000..7e3efcc
--- /dev/null
+++ b/tests/test-metadata-validation.sh
@@ -0,0 +1,158 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Matthew Leeds <mwleeds@protonmail.com>
+#
+# SPDX-License-Identifier: LGPL-2.0-or-later
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+echo "1..7"
+
+setup_repo
+
+COUNTER=1
+
+create_app () {
+ local OPTIONS="$1"
+ local DIR=`mktemp -d`
+
+ mkdir ${DIR}/files
+ echo $COUNTER > ${DIR}/files/counter
+ let COUNTER=COUNTER+1
+
+ local INVALID=""
+ if [[ $OPTIONS =~ "invalid" ]]; then
+ INVALID=invalidkeyfileline
+ fi
+ cat > ${DIR}/metadata <<EOF
+[Application]
+name=org.test.Malicious
+runtime=org.test.Platform/${ARCH}/master
+$INVALID
+
+[Context]
+EOF
+ if [[ $OPTIONS =~ "mismatch" ]]; then
+ echo -e "filesystems=host;" >> ${DIR}/metadata
+ fi
+ if [[ $OPTIONS =~ "hidden" ]]; then
+ echo -ne "\0" >> ${DIR}/metadata
+ echo -e "\nfilesystems=home;" >> ${DIR}/metadata
+ fi
+ local XA_METADATA=--add-metadata-string=xa.metadata="$(head -n6 ${DIR}/metadata)"$'\n'
+ if [[ $OPTIONS =~ "no-xametadata" ]]; then
+ XA_METADATA="--add-metadata-string=xa.nometadata=1"
+ fi
+ ostree commit --repo=repos/test --branch=app/org.test.Malicious/${ARCH}/master ${FL_GPGARGS} "$XA_METADATA" ${DIR}/
+ if [[ $OPTIONS =~ "no-cache-in-summary" ]]; then
+ ostree --repo=repos/test ${FL_GPGARGS} summary -u
+ # force use of legacy summary format
+ rm -rf repos/test/summary.idx repos/test/summaries
+ else
+ update_repo
+ fi
+ rm -rf ${DIR}
+}
+
+cleanup_repo () {
+ ostree refs --repo=repos/test --delete app/org.test.Malicious/${ARCH}/master
+ update_repo
+}
+
+create_app "hidden"
+
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with hidden permissions"
+fi
+
+assert_file_has_content install-error-log "not matching expected metadata"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with hidden permissions can't be installed (CVE-2021-43860)"
+
+create_app no-xametadata
+
+# The install will fail because the metadata in the summary doesn't match the metadata on the commit
+# The missing xa.metadata in the commit got turned into "" in the xa.cache
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with missing xa.metadata"
+fi
+
+assert_file_has_content install-error-log "not matching expected metadata"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with no xa.metadata can't be installed"
+
+create_app "no-xametadata no-cache-in-summary"
+
+# The install will fail because there's no metadata in the summary or on the commit
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with missing metadata"
+fi
+assert_file_has_content install-error-log "No xa.metadata in local commit"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with no xa.metadata and no metadata in summary can't be installed"
+
+create_app "invalid"
+
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with invalid metadata"
+fi
+assert_file_has_content install-error-log "Metadata for .* is invalid"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with invalid metadata (in summary) can't be installed"
+
+create_app "invalid no-cache-in-summary"
+
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with invalid metadata"
+fi
+assert_file_has_content install-error-log "Metadata for .* is invalid"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with invalid metadata (in commit) can't be installed"
+
+create_app "mismatch no-cache-in-summary"
+
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with non-matching metadata"
+fi
+assert_file_has_content install-error-log "Commit metadata for .* not matching expected metadata"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with mismatched metadata (in commit) can't be installed"
+
+create_app "mismatch"
+
+if ${FLATPAK} ${U} install -y test-repo org.test.Malicious 2>install-error-log; then
+ assert_not_reached "Should not be able to install app with non-matching metadata"
+fi
+assert_file_has_content install-error-log "Commit metadata for .* not matching expected metadata"
+
+assert_not_has_dir $FL_DIR/app/org.test.Malicious/current/active
+
+cleanup_repo
+
+ok "app with mismatched metadata (in summary) can't be installed"
--
2.27.0

View File

@ -0,0 +1,36 @@
From 65cbfac982cb1c83993a9e19aa424daee8e9f042 Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Wed, 12 Jan 2022 11:00:56 +0100
Subject: [PATCH] Ensure that bundles have metadata on install
If we have a bundle without metadata we wouldn't properly present
the permissions in the transaction.
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/65cbfac982cb1c83993a9e19aa424daee8e9f042
---
common/flatpak-dir.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index 94a86f4..ddc5ee9 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -9295,6 +9295,13 @@ flatpak_dir_ensure_bundle_remote (FlatpakDir *self,
if (metadata == NULL)
return NULL;
+ /* If we rely on metadata (to e.g. print permissions), check it exists before creating the remote */
+ if (out_metadata && fp_metadata == NULL)
+ {
+ flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, "No metadata in bundler header");
+ return NULL;
+ }
+
gpg_data = extra_gpg_data ? extra_gpg_data : included_gpg_data;
deploy_data = flatpak_dir_get_deploy_data (self, ref, FLATPAK_DEPLOY_VERSION_ANY, cancellable, NULL);
--
2.27.0

View File

@ -0,0 +1,210 @@
From ba818f504c926baaf6e362be8159cfacf994310e Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Date: Thu, 23 Dec 2021 18:30:17 -0600
Subject: [PATCH] Fix metadata file contents after null terminators being
ignored
In particular, if a null terminator is placed inside the metadata file,
Flatpak will only compare the text *before* it to the value of
xa.metadata, but the full file will be parsed when permissions are set
at runtime. This means that any app can include a null terminator in its
permissions metadata, and Flatpak will only show the user the
permissions *preceding* the terminator during install, but the
permissions *after* the terminator are applied at runtime.
Fixes GHSA-qpjc-vq3c-572j / CVE-2021-43860
Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/ba818f504c926baaf6e362be8159cfacf994310e
---
common/flatpak-dir.c | 36 +++++++++++++++++++++++++++---------
common/flatpak-transaction.c | 8 ++++----
common/flatpak-utils.c | 9 +++++----
3 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index ddc5ee9..e6c8046 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -1762,19 +1762,29 @@ static gboolean
validate_commit_metadata (GVariant *commit_data,
const char *ref,
const char *required_metadata,
+ gsize required_metadata_size,
gboolean require_xa_metadata,
GError **error)
{
g_autoptr(GVariant) commit_metadata = NULL;
+ g_autoptr(GVariant) xa_metadata_v = NULL;
const char *xa_metadata = NULL;
+ gsize xa_metadata_size = 0;
commit_metadata = g_variant_get_child_value (commit_data, 0);
if (commit_metadata != NULL)
- g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
+ {
+ xa_metadata_v = g_variant_lookup_value (commit_metadata,
+ "xa.metadata",
+ G_VARIANT_TYPE_STRING);
+ if (xa_metadata_v)
+ xa_metadata = g_variant_get_string (xa_metadata_v, &xa_metadata_size);
+ }
if ((xa_metadata == NULL && require_xa_metadata) ||
- (xa_metadata != NULL && g_strcmp0 (required_metadata, xa_metadata) != 0))
+ (xa_metadata != NULL && (xa_metadata_size != required_metadata_size ||
+ memcmp (xa_metadata, required_metadata, xa_metadata_size) != 0)))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
_("Commit metadata for %s not matching expected metadata"), ref);
@@ -3478,6 +3488,7 @@ upgrade_deploy_data (GBytes *deploy_data,
g_autoptr(GKeyFile) keyfile = NULL;
g_autoptr(GFile) metadata_file = NULL;
g_autofree char *metadata_contents = NULL;
+ gsize metadata_size = 0;
g_autofree char *id = flatpak_decomposed_dup_id (ref);
/* Add fields from commit metadata to deploy */
@@ -3491,9 +3502,9 @@ upgrade_deploy_data (GBytes *deploy_data,
keyfile = g_key_file_new ();
metadata_file = g_file_resolve_relative_path (deploy_dir, "metadata");
if (!g_file_load_contents (metadata_file, cancellable,
- &metadata_contents, NULL, NULL, error))
+ &metadata_contents, &metadata_size, NULL, error))
return NULL;
- if (!g_key_file_load_from_data (keyfile, metadata_contents, -1, 0, error))
+ if (!g_key_file_load_from_data (keyfile, metadata_contents, metadata_size, 0, error))
return NULL;
add_metadata_to_deploy_data (&metadata_dict, keyfile);
@@ -5799,8 +5810,13 @@ flatpak_dir_pull (FlatpakDir *self,
{
g_autoptr(GVariant) commit_data = NULL;
if (!ostree_repo_load_commit (repo, rev, &commit_data, NULL, error) ||
- !validate_commit_metadata (commit_data, ref, (const char *)g_bytes_get_data (require_metadata, NULL), TRUE, error))
- return FALSE;
+ !validate_commit_metadata (commit_data,
+ ref,
+ (const char *)g_bytes_get_data (require_metadata, NULL),
+ g_bytes_get_size (require_metadata),
+ TRUE,
+ error))
+ goto out;
}
if (!flatpak_dir_pull_extra_data (self, repo,
@@ -8111,6 +8127,7 @@ flatpak_dir_deploy (FlatpakDir *self,
g_auto(GLnxLockFile) lock = { 0, };
g_autoptr(GFile) metadata_file = NULL;
g_autofree char *metadata_contents = NULL;
+ gsize metadata_size = 0;
gboolean is_oci;
if (!flatpak_dir_ensure_repo (self, cancellable, error))
@@ -8320,11 +8337,12 @@ flatpak_dir_deploy (FlatpakDir *self,
keyfile = g_key_file_new ();
metadata_file = g_file_resolve_relative_path (checkoutdir, "metadata");
if (g_file_load_contents (metadata_file, NULL,
- &metadata_contents, NULL, NULL, NULL))
+ &metadata_contents,
+ &metadata_size, NULL, NULL))
{
if (!g_key_file_load_from_data (keyfile,
metadata_contents,
- -1,
+ metadata_size,
0, error))
return FALSE;
@@ -8340,7 +8358,7 @@ flatpak_dir_deploy (FlatpakDir *self,
*/
is_oci = flatpak_dir_get_remote_oci (self, origin);
if (!validate_commit_metadata (commit_data, flatpak_decomposed_get_ref (ref),
- metadata_contents, !is_oci, error))
+ metadata_contents, metadata_size, !is_oci, error))
return FALSE;
dotref = g_file_resolve_relative_path (checkoutdir, "files/.ref");
diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c
index 1927498..721da14 100644
--- a/common/flatpak-transaction.c
+++ b/common/flatpak-transaction.c
@@ -2520,7 +2520,7 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
return FALSE;
if (external_metadata)
- op->external_metadata = g_bytes_new (external_metadata, strlen (external_metadata) + 1);
+ op->external_metadata = g_bytes_new (external_metadata, strlen (external_metadata));
return TRUE;
}
@@ -2937,7 +2937,7 @@ load_deployed_metadata (FlatpakTransaction *self, FlatpakDecomposed *ref, char *
return NULL;
}
- return g_bytes_new_take (g_steal_pointer (&metadata_contents), metadata_contents_length + 1);
+ return g_bytes_new_take (g_steal_pointer (&metadata_contents), metadata_contents_length);
}
static void
@@ -3034,7 +3034,7 @@ resolve_op_from_commit (FlatpakTransaction *self,
if (xa_metadata == NULL)
g_message ("Warning: No xa.metadata in local commit %s ref %s", checksum, flatpak_decomposed_get_ref (op->ref));
else
- metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata) + 1);
+ metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata));
if (g_variant_lookup (commit_metadata, "xa.download-size", "t", &download_size))
op->download_size = GUINT64_FROM_BE (download_size);
@@ -3074,7 +3074,7 @@ try_resolve_op_from_metadata (FlatpakTransaction *self,
&download_size, &installed_size, &metadata, NULL))
return FALSE;
- metadata_bytes = g_bytes_new (metadata, strlen (metadata) + 1);
+ metadata_bytes = g_bytes_new (metadata, strlen (metadata));
if (flatpak_remote_state_lookup_ref (state, flatpak_decomposed_get_ref (op->ref),
NULL, NULL, &info, NULL, NULL))
diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c
index 6901a62..9eedbfa 100644
--- a/common/flatpak-utils.c
+++ b/common/flatpak-utils.c
@@ -6604,6 +6604,7 @@ flatpak_pull_from_bundle (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
+ gsize metadata_size = 0;
g_autofree char *metadata_contents = NULL;
g_autofree char *to_checksum = NULL;
g_autoptr(GFile) root = NULL;
@@ -6620,6 +6621,8 @@ flatpak_pull_from_bundle (OstreeRepo *repo,
if (metadata == NULL)
return FALSE;
+ metadata_size = strlen (metadata_contents);
+
if (!ostree_repo_get_remote_option (repo, remote, "collection-id", NULL,
&remote_collection_id, NULL))
remote_collection_id = NULL;
@@ -6689,12 +6692,10 @@ flatpak_pull_from_bundle (OstreeRepo *repo,
cancellable, error) < 0)
return FALSE;
- /* Null terminate */
- g_output_stream_write (G_OUTPUT_STREAM (data_stream), "\0", 1, NULL, NULL);
-
metadata_valid =
metadata_contents != NULL &&
- strcmp (metadata_contents, g_memory_output_stream_get_data (data_stream)) == 0;
+ metadata_size == g_memory_output_stream_get_data_size (data_stream) &&
+ memcmp (metadata_contents, g_memory_output_stream_get_data (data_stream), metadata_size) == 0;
}
else
{
--
2.27.0

View File

@ -0,0 +1,76 @@
From 93357d357119093804df05acc32ff335839c6451 Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Tue, 11 Jan 2022 10:27:46 +0100
Subject: [PATCH] Require metadata in commit also for OCI remotes
This was disables a long time ago because the fedora remotes didn't
contain metadata, but that has been added since then. Requiring fixes
a security concern where an app claims to require no permissions (by
having no metadata in commit) but then actually requires permissions
in the installed app.
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/93357d357119093804df05acc32ff335839c6451
---
common/flatpak-dir.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index e6c8046..e6a83cf 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -1763,7 +1763,6 @@ validate_commit_metadata (GVariant *commit_data,
const char *ref,
const char *required_metadata,
gsize required_metadata_size,
- gboolean require_xa_metadata,
GError **error)
{
g_autoptr(GVariant) commit_metadata = NULL;
@@ -1782,9 +1781,9 @@ validate_commit_metadata (GVariant *commit_data,
xa_metadata = g_variant_get_string (xa_metadata_v, &xa_metadata_size);
}
- if ((xa_metadata == NULL && require_xa_metadata) ||
- (xa_metadata != NULL && (xa_metadata_size != required_metadata_size ||
- memcmp (xa_metadata, required_metadata, xa_metadata_size) != 0)))
+ if (xa_metadata == NULL ||
+ xa_metadata_size != required_metadata_size ||
+ memcmp (xa_metadata, required_metadata, xa_metadata_size) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
_("Commit metadata for %s not matching expected metadata"), ref);
@@ -5814,7 +5813,6 @@ flatpak_dir_pull (FlatpakDir *self,
ref,
(const char *)g_bytes_get_data (require_metadata, NULL),
g_bytes_get_size (require_metadata),
- TRUE,
error))
goto out;
}
@@ -8128,7 +8126,6 @@ flatpak_dir_deploy (FlatpakDir *self,
g_autoptr(GFile) metadata_file = NULL;
g_autofree char *metadata_contents = NULL;
gsize metadata_size = 0;
- gboolean is_oci;
if (!flatpak_dir_ensure_repo (self, cancellable, error))
return FALSE;
@@ -8353,12 +8350,9 @@ flatpak_dir_deploy (FlatpakDir *self,
/* Check the metadata in the commit to make sure it matches the actual
* deployed metadata, in case we relied on the one in the commit for
* a decision
- * Note: For historical reason we don't enforce commits to contain xa.metadata
- * since this was lacking in fedora builds.
*/
- is_oci = flatpak_dir_get_remote_oci (self, origin);
if (!validate_commit_metadata (commit_data, flatpak_decomposed_get_ref (ref),
- metadata_contents, metadata_size, !is_oci, error))
+ metadata_contents, metadata_size, error))
return FALSE;
dotref = g_file_resolve_relative_path (checkoutdir, "files/.ref");
--
2.27.0

View File

@ -0,0 +1,239 @@
From d9a8f9d8ccc0b7c1135d0ecde006a75d25f66aee Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Mon, 10 Jan 2022 16:43:08 +0100
Subject: [PATCH] Transaction: Fail the resolve if xa.metadata invalid or
missing
If we fail to parse xa.metadata from the summary cache or the commit
xa.metadata we fail the resolve.
If xa.metadata is missing in the commit we fail the resolve (it is
always set in the summary cache, because summary update converts
missing xa.metadata to "", so we either get that, or cache miss which
leads to resolving from the commit.
This means that op->resolved_metadata is always set during install and
updates, which means we will show the app permissions. The transaction
will also always make sure that this data actually matches what gets
deployed.
Before this change an invalid metadata in the summary cache could lead
to a NULL resolved_metadata, which means we wouldn't print the app
permissions, yet we would still deploy some metadata file that could
have permissions. (NOTE: It would fail to deploy unless the
xa.metadata in the commit matched the metadata file, but in this
corner case we would't compare the summary and commit metadata, so
they may differ.)
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/d9a8f9d8ccc0b7c1135d0ecde006a75d25f66aee
---
common/flatpak-transaction.c | 84 +++++++++++++++++++++++-------------
1 file changed, 55 insertions(+), 29 deletions(-)
diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c
index 721da14..b0908c3 100644
--- a/common/flatpak-transaction.c
+++ b/common/flatpak-transaction.c
@@ -2957,12 +2957,13 @@ emit_eol_and_maybe_skip (FlatpakTransaction *self,
g_signal_emit (self, signals[END_OF_LIFED_WITH_REBASE], 0, op->remote, flatpak_decomposed_get_ref (op->ref), op->eol, op->eol_rebase, previous_ids, &op->skip);
}
-static void
+static gboolean
mark_op_resolved (FlatpakTransactionOperation *op,
const char *commit,
GFile *sideload_path,
GBytes *metadata,
- GBytes *old_metadata)
+ GBytes *old_metadata,
+ GError **error)
{
g_debug ("marking op %s:%s resolved to %s", kind_to_str (op->kind), flatpak_decomposed_get_ref (op->ref), commit ? commit : "-");
@@ -2980,13 +2981,12 @@ mark_op_resolved (FlatpakTransactionOperation *op,
if (metadata)
{
g_autoptr(GKeyFile) metakey = g_key_file_new ();
- if (g_key_file_load_from_bytes (metakey, metadata, G_KEY_FILE_NONE, NULL))
- {
- op->resolved_metadata = g_bytes_ref (metadata);
- op->resolved_metakey = g_steal_pointer (&metakey);
- }
- else
- g_message ("Warning: Failed to parse metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+ if (!g_key_file_load_from_bytes (metakey, metadata, G_KEY_FILE_NONE, NULL))
+ return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA,
+ "Metadata for %s is invalid", flatpak_decomposed_get_ref (op->ref));
+
+ op->resolved_metadata = g_bytes_ref (metadata);
+ op->resolved_metakey = g_steal_pointer (&metakey);
}
if (old_metadata)
{
@@ -2997,31 +2997,40 @@ mark_op_resolved (FlatpakTransactionOperation *op,
op->resolved_old_metakey = g_steal_pointer (&metakey);
}
else
- g_message ("Warning: Failed to parse old metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+ {
+ /* This shouldn't happen, but a NULL old metadata is safe (all permisssions are considered new) */
+ g_message ("Warning: Failed to parse old metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+ }
}
+
+ return TRUE;
}
-static void
+static gboolean
resolve_op_end (FlatpakTransaction *self,
FlatpakTransactionOperation *op,
const char *checksum,
GFile *sideload_path,
- GBytes *metadata_bytes)
+ GBytes *metadata_bytes,
+ GError **error)
{
g_autoptr(GBytes) old_metadata_bytes = NULL;
old_metadata_bytes = load_deployed_metadata (self, op->ref, NULL, NULL);
- mark_op_resolved (op, checksum, sideload_path, metadata_bytes, old_metadata_bytes);
+ if (!mark_op_resolved (op, checksum, sideload_path, metadata_bytes, old_metadata_bytes, error))
+ return FALSE;
emit_eol_and_maybe_skip (self, op);
+ return TRUE;
}
-static void
+static gboolean
resolve_op_from_commit (FlatpakTransaction *self,
FlatpakTransactionOperation *op,
const char *checksum,
GFile *sideload_path,
- GVariant *commit_data)
+ GVariant *commit_data,
+ GError **error)
{
g_autoptr(GBytes) metadata_bytes = NULL;
g_autoptr(GVariant) commit_metadata = NULL;
@@ -3032,9 +3041,11 @@ resolve_op_from_commit (FlatpakTransaction *self,
commit_metadata = g_variant_get_child_value (commit_data, 0);
g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
if (xa_metadata == NULL)
- g_message ("Warning: No xa.metadata in local commit %s ref %s", checksum, flatpak_decomposed_get_ref (op->ref));
- else
- metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata));
+ return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA,
+ "No xa.metadata in local commit %s ref %s",
+ checksum, flatpak_decomposed_get_ref (op->ref));
+
+ metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata));
if (g_variant_lookup (commit_metadata, "xa.download-size", "t", &download_size))
op->download_size = GUINT64_FROM_BE (download_size);
@@ -3044,15 +3055,19 @@ resolve_op_from_commit (FlatpakTransaction *self,
g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE, "s", &op->eol);
g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE, "s", &op->eol_rebase);
- resolve_op_end (self, op, checksum, sideload_path, metadata_bytes);
+ return resolve_op_end (self, op, checksum, sideload_path, metadata_bytes, error);
}
+/* NOTE: In case of non-available summary this returns FALSE with a
+ * NULL error, but for other error cases it will be set.
+ */
static gboolean
try_resolve_op_from_metadata (FlatpakTransaction *self,
FlatpakTransactionOperation *op,
const char *checksum,
GFile *sideload_path,
- FlatpakRemoteState *state)
+ FlatpakRemoteState *state,
+ GError **error)
{
g_autoptr(GBytes) metadata_bytes = NULL;
guint64 download_size = 0;
@@ -3092,8 +3107,7 @@ try_resolve_op_from_metadata (FlatpakTransaction *self,
op->token_type = GINT32_FROM_LE (var_metadata_lookup_int32 (sparse_cache, FLATPAK_SPARSE_CACHE_KEY_TOKEN_TYPE, op->token_type));
}
- resolve_op_end (self, op, checksum, sideload_path, metadata_bytes);
- return TRUE;
+ return resolve_op_end (self, op, checksum, sideload_path, metadata_bytes, error);
}
static gboolean
@@ -3136,7 +3150,8 @@ resolve_ops (FlatpakTransaction *self,
* checksum we got was the version already installed.
*/
g_assert (op->resolved_commit != NULL);
- mark_op_resolved (op, op->resolved_commit, NULL, NULL, NULL);
+ if (!mark_op_resolved (op, op->resolved_commit, NULL, NULL, NULL, error))
+ return FALSE;
continue;
}
@@ -3145,14 +3160,16 @@ resolve_ops (FlatpakTransaction *self,
/* We resolve to the deployed metadata, because we need it to uninstall related ops */
metadata_bytes = load_deployed_metadata (self, op->ref, &checksum, NULL);
- mark_op_resolved (op, checksum, NULL, metadata_bytes, NULL);
+ if (!mark_op_resolved (op, checksum, NULL, metadata_bytes, NULL, error))
+ return FALSE;
continue;
}
if (op->kind == FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE)
{
g_assert (op->commit != NULL);
- mark_op_resolved (op, op->commit, NULL, op->external_metadata, NULL);
+ if (!mark_op_resolved (op, op->commit, NULL, op->external_metadata, NULL, error))
+ return FALSE;
continue;
}
@@ -3183,7 +3200,8 @@ resolve_ops (FlatpakTransaction *self,
if (commit_data == NULL)
return FALSE;
- resolve_op_from_commit (self, op, checksum, NULL, commit_data);
+ if (!resolve_op_from_commit (self, op, checksum, NULL, commit_data, error))
+ return FALSE;
}
else
{
@@ -3242,9 +3260,16 @@ resolve_ops (FlatpakTransaction *self,
}
/* First try to resolve via metadata (if remote is available and its metadata matches the commit version) */
- if (!try_resolve_op_from_metadata (self, op, checksum, sideload_path, state))
+ if (!try_resolve_op_from_metadata (self, op, checksum, sideload_path, state, &local_error))
{
- /* Else try to load the commit object.
+ if (local_error)
+ {
+ /* Actual error, not just missing from summary */
+ g_propagate_error (error, g_steal_pointer (&local_error));
+ return FALSE;
+ }
+
+ /* Missing from summary, try to load the commit object.
* Note, we don't have a token here, so this will not work for authenticated apps.
* We handle this by catching the 401 http status and retrying. */
g_autoptr(GVariant) commit_data = NULL;
@@ -3280,7 +3305,8 @@ resolve_ops (FlatpakTransaction *self,
return FALSE;
}
- resolve_op_from_commit (self, op, checksum, sideload_path, commit_data);
+ if (!resolve_op_from_commit (self, op, checksum, sideload_path, commit_data, error))
+ return FALSE;
}
}
}
--
2.27.0

View File

@ -0,0 +1,340 @@
From 5709f1aaed6579f0136976e14e7f3cae399134ca Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Sun, 16 Jan 2022 12:42:30 +0000
Subject: [PATCH] context: Introduce new --nofilesystem=host:reset
This reintroduces the special case that existed in Flatpak 1.12.3, but
under a different name, so that it will be backwards-compatible. With
this change, flatpak-builder will be able to resolve CVE-2022-21682 by
using --filesystem=host:reset.
We want to implement this as a suffix rather than as a new keyword,
because unknown suffixes are ignored with a warning, rather than causing
a fatal error. This means that the new version of flatpak-builder will
be able to run against older versions of flatpak: it will still be
vulnerable to CVE-2022-21682 in that situation, but at least it will run.
Co-authored-by: Alexander Larsson <alexl@redhat.com>
Conflict:NA
Reference:https://github.com/flatpak/flatpak/commit/5709f1aaed6579f0136976e14e7f3cae399134ca
---
common/flatpak-context-private.h | 1 +
common/flatpak-context.c | 166 ++++++++++++++++++++++++++++---
2 files changed, 153 insertions(+), 14 deletions(-)
diff --git a/common/flatpak-context-private.h b/common/flatpak-context-private.h
index 45879ac..b6b9e56 100644
--- a/common/flatpak-context-private.h
+++ b/common/flatpak-context-private.h
@@ -83,6 +83,7 @@ extern const char *flatpak_context_features[];
extern const char *flatpak_context_shares[];
gboolean flatpak_context_parse_filesystem (const char *filesystem_and_mode,
+ gboolean negated,
char **filesystem_out,
FlatpakFilesystemMode *mode_out,
GError **error);
diff --git a/common/flatpak-context.c b/common/flatpak-context.c
index abeda35..a7cd891 100644
--- a/common/flatpak-context.c
+++ b/common/flatpak-context.c
@@ -86,6 +86,7 @@ const char *flatpak_context_special_filesystems[] = {
"host",
"host-etc",
"host-os",
+ "host-reset",
NULL
};
@@ -703,6 +704,12 @@ unparse_filesystem_flags (const char *path,
case FLATPAK_FILESYSTEM_MODE_NONE:
g_string_insert_c (s, 0, '!');
+
+ if (g_str_has_suffix (s->str, "-reset"))
+ {
+ g_string_truncate (s, s->len - 6);
+ g_string_append (s, ":reset");
+ }
break;
default:
@@ -715,11 +722,14 @@ unparse_filesystem_flags (const char *path,
static char *
parse_filesystem_flags (const char *filesystem,
- FlatpakFilesystemMode *mode_out)
+ gboolean negated,
+ FlatpakFilesystemMode *mode_out,
+ GError **error)
{
g_autoptr(GString) s = g_string_new ("");
const char *p, *suffix;
FlatpakFilesystemMode mode;
+ gboolean reset = FALSE;
p = filesystem;
while (*p != 0 && *p != ':')
@@ -734,7 +744,31 @@ parse_filesystem_flags (const char *filesystem,
g_string_append_c (s, *p++);
}
- mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE;
+ if (negated)
+ mode = FLATPAK_FILESYSTEM_MODE_NONE;
+ else
+ mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE;
+
+ if (g_str_equal (s->str, "host-reset"))
+ {
+ reset = TRUE;
+
+ if (!negated)
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ "Filesystem token \"%s\" is only applicable for --nofilesystem",
+ s->str);
+ return NULL;
+ }
+
+ if (*p != '\0')
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ "Filesystem token \"%s\" cannot be used with a suffix",
+ s->str);
+ return NULL;
+ }
+ }
if (*p == ':')
{
@@ -746,10 +780,63 @@ parse_filesystem_flags (const char *filesystem,
mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE;
else if (strcmp (suffix, "create") == 0)
mode = FLATPAK_FILESYSTEM_MODE_CREATE;
+ else if (strcmp (suffix, "reset") == 0)
+ reset = TRUE;
else if (*suffix != 0)
g_warning ("Unexpected filesystem suffix %s, ignoring", suffix);
+
+ if (negated && mode != FLATPAK_FILESYSTEM_MODE_NONE)
+ {
+ g_warning ("Filesystem suffix \"%s\" is not applicable for --nofilesystem",
+ suffix);
+ mode = FLATPAK_FILESYSTEM_MODE_NONE;
+ }
+
+ if (reset)
+ {
+ if (!negated)
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ "Filesystem suffix \"%s\" only applies to --nofilesystem",
+ suffix);
+ return NULL;
+ }
+
+ if (!g_str_equal (s->str, "host"))
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ "Filesystem suffix \"%s\" can only be applied to "
+ "--nofilesystem=host",
+ suffix);
+ return NULL;
+ }
+
+ /* We internally handle host:reset (etc) as host-reset, only exposing it as a flag in the public
+ part to allow it to be ignored (with a warning) for old flatpak versions */
+ g_string_append (s, "-reset");
+ }
+ }
+
+ /* Postcondition check: the code above should make some results
+ * impossible */
+ if (negated)
+ {
+ g_assert (mode == FLATPAK_FILESYSTEM_MODE_NONE);
+ }
+ else
+ {
+ g_assert (mode > FLATPAK_FILESYSTEM_MODE_NONE);
+ /* This flag is only applicable to --nofilesystem */
+ g_assert (!reset);
}
+ /* Postcondition check: filesystem token is host-reset iff reset flag
+ * was found */
+ if (reset)
+ g_assert (g_str_equal (s->str, "host-reset"));
+ else
+ g_assert (!g_str_equal (s->str, "host-reset"));
+
if (mode_out)
*mode_out = mode;
@@ -758,13 +845,18 @@ parse_filesystem_flags (const char *filesystem,
gboolean
flatpak_context_parse_filesystem (const char *filesystem_and_mode,
+ gboolean negated,
char **filesystem_out,
FlatpakFilesystemMode *mode_out,
GError **error)
{
- g_autofree char *filesystem = parse_filesystem_flags (filesystem_and_mode, mode_out);
+ g_autofree char *filesystem = NULL;
char *slash;
+ filesystem = parse_filesystem_flags (filesystem_and_mode, negated, mode_out, error);
+ if (filesystem == NULL)
+ return FALSE;
+
slash = strchr (filesystem, '/');
/* Forbid /../ in paths */
@@ -856,6 +948,14 @@ flatpak_context_take_filesystem (FlatpakContext *context,
char *fs,
FlatpakFilesystemMode mode)
{
+ /* Special case: --nofilesystem=host-reset implies --nofilesystem=host.
+ * --filesystem=host-reset (or host:reset) is not allowed. */
+ if (g_str_equal (fs, "host-reset"))
+ {
+ g_return_if_fail (mode == FLATPAK_FILESYSTEM_MODE_NONE);
+ g_hash_table_insert (context->filesystems, g_strdup ("host"), GINT_TO_POINTER (mode));
+ }
+
g_hash_table_insert (context->filesystems, fs, GINT_TO_POINTER (mode));
}
@@ -887,6 +987,14 @@ flatpak_context_merge (FlatpakContext *context,
while (g_hash_table_iter_next (&iter, &key, &value))
g_hash_table_insert (context->persistent, g_strdup (key), value);
+ /* We first handle host:reset, as it overrides all other keys from the parent */
+ if (g_hash_table_lookup_extended (other->filesystems, "host-reset", NULL, &value))
+ {
+ g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE);
+ g_hash_table_remove_all (context->filesystems);
+ }
+
+ /* Then set the new ones, which includes propagating host:reset. */
g_hash_table_iter_init (&iter, other->filesystems);
while (g_hash_table_iter_next (&iter, &key, &value))
g_hash_table_insert (context->filesystems, g_strdup (key), value);
@@ -1074,7 +1182,7 @@ option_filesystem_cb (const gchar *option_name,
g_autofree char *fs = NULL;
FlatpakFilesystemMode mode;
- if (!flatpak_context_parse_filesystem (value, &fs, &mode, error))
+ if (!flatpak_context_parse_filesystem (value, FALSE, &fs, &mode, error))
return FALSE;
flatpak_context_take_filesystem (context, g_steal_pointer (&fs), mode);
@@ -1091,7 +1199,7 @@ option_nofilesystem_cb (const gchar *option_name,
g_autofree char *fs = NULL;
FlatpakFilesystemMode mode;
- if (!flatpak_context_parse_filesystem (value, &fs, &mode, error))
+ if (!flatpak_context_parse_filesystem (value, TRUE, &fs, &mode, error))
return FALSE;
flatpak_context_take_filesystem (context, g_steal_pointer (&fs),
@@ -1571,15 +1679,13 @@ flatpak_context_load_metadata (FlatpakContext *context,
g_autofree char *filesystem = NULL;
FlatpakFilesystemMode mode;
- if (!flatpak_context_parse_filesystem (fs, &filesystem, &mode, NULL))
+ if (!flatpak_context_parse_filesystem (fs, remove,
+ &filesystem, &mode, NULL))
g_debug ("Unknown filesystem type %s", filesystems[i]);
else
{
- if (remove)
- flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem),
- FLATPAK_FILESYSTEM_MODE_NONE);
- else
- flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem), mode);
+ g_assert (mode == FLATPAK_FILESYSTEM_MODE_NONE || !remove);
+ flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem), mode);
}
}
}
@@ -1825,11 +1931,24 @@ flatpak_context_save_metadata (FlatpakContext *context,
{
g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free);
+ /* Serialize host-reset first, because order can matter in
+ * corner cases. */
+ if (g_hash_table_lookup_extended (context->filesystems, "host-reset",
+ NULL, &value))
+ {
+ g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE);
+ g_ptr_array_add (array, g_strdup ("!host:reset"));
+ }
+
g_hash_table_iter_init (&iter, context->filesystems);
while (g_hash_table_iter_next (&iter, &key, &value))
{
FlatpakFilesystemMode mode = GPOINTER_TO_INT (value);
+ /* We already did this */
+ if (g_str_equal (key, "host-reset"))
+ continue;
+
g_ptr_array_add (array, unparse_filesystem_flags (key, mode));
}
@@ -1968,7 +2087,8 @@ flatpak_context_save_metadata (FlatpakContext *context,
void
flatpak_context_allow_host_fs (FlatpakContext *context)
{
- flatpak_context_take_filesystem (context, g_strdup ("host"), FLATPAK_FILESYSTEM_MODE_READ_WRITE);
+ flatpak_context_take_filesystem (context, g_strdup ("host"),
+ FLATPAK_FILESYSTEM_MODE_READ_WRITE);
}
gboolean
@@ -2155,18 +2275,36 @@ flatpak_context_to_args (FlatpakContext *context,
g_ptr_array_add (args, g_strdup_printf ("--system-%s-name=%s", flatpak_policy_to_string (policy), name));
}
+ /* Serialize host-reset first, because order can matter in
+ * corner cases. */
+ if (g_hash_table_lookup_extended (context->filesystems, "host-reset",
+ NULL, &value))
+ {
+ g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE);
+ g_ptr_array_add (args, g_strdup ("--nofilesystem=host:reset"));
+ }
+
g_hash_table_iter_init (&iter, context->filesystems);
while (g_hash_table_iter_next (&iter, &key, &value))
{
+ g_autofree char *fs = NULL;
FlatpakFilesystemMode mode = GPOINTER_TO_INT (value);
+ /* We already did this */
+ if (g_str_equal (key, "host-reset"))
+ continue;
+
+ fs = unparse_filesystem_flags (key, mode);
+
if (mode != FLATPAK_FILESYSTEM_MODE_NONE)
{
- g_autofree char *fs = unparse_filesystem_flags (key, mode);
g_ptr_array_add (args, g_strdup_printf ("--filesystem=%s", fs));
}
else
- g_ptr_array_add (args, g_strdup_printf ("--nofilesystem=%s", (char *) key));
+ {
+ g_assert (fs[0] == '!');
+ g_ptr_array_add (args, g_strdup_printf ("--nofilesystem=%s", &fs[1]));
+ }
}
}
--
2.27.0

View File

@ -0,0 +1,85 @@
From b912053c6cc556f131465c1fd877d7bd0b433539 Mon Sep 17 00:00:00 2001
From: Phaedrus Leeds <mwleeds@protonmail.com>
Date: Sun, 2 May 2021 21:53:02 -0500
Subject: [PATCH] Fix several memory leaks
(cherry picked from commit 404d7c6941baf63d1b3ccbe9ee9d34f3ff12f35f)
---
app/flatpak-builtins-document-export.c | 6 +++---
common/flatpak-dir.c | 7 ++++---
common/flatpak-utils.c | 1 +
portal/flatpak-portal.c | 2 +-
4 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/app/flatpak-builtins-document-export.c b/app/flatpak-builtins-document-export.c
index 15f1ad1275..e701a826bb 100644
--- a/app/flatpak-builtins-document-export.c
+++ b/app/flatpak-builtins-document-export.c
@@ -90,8 +90,8 @@ flatpak_builtin_document_export (int argc, char **argv,
g_autofree char *dirname = NULL;
g_autofree char *doc_path = NULL;
XdpDbusDocuments *documents;
- int fd, fd_id;
- int i;
+ glnx_autofd int fd = -1;
+ int i, fd_id;
GUnixFDList *fd_list = NULL;
const char *doc_id;
struct stat stbuf;
@@ -173,7 +173,7 @@ flatpak_builtin_document_export (int argc, char **argv,
fd_list = g_unix_fd_list_new ();
fd_id = g_unix_fd_list_append (fd_list, fd, error);
- close (fd);
+ glnx_close_fd (&fd);
if (opt_noexist)
{
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index 94a86f4afb..0724677b91 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -13690,14 +13690,15 @@ parse_ref_file (GKeyFile *keyfile,
collection_id = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP,
FLATPAK_REF_DEPLOY_COLLECTION_ID_KEY, NULL);
- if (collection_id == NULL || *collection_id == '\0')
+ if (collection_id != NULL && *collection_id == '\0')
+ g_clear_pointer (&collection_id, g_free);
+ if (collection_id == NULL)
{
collection_id = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP,
FLATPAK_REF_COLLECTION_ID_KEY, NULL);
}
-
if (collection_id != NULL && *collection_id == '\0')
- collection_id = NULL;
+ g_clear_pointer (&collection_id, g_free);
if (collection_id != NULL && gpg_data == NULL)
return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Collection ID requires GPG key to be provided"));
diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c
index 56cbb06db3..84bc6a398d 100644
--- a/common/flatpak-utils.c
+++ b/common/flatpak-utils.c
@@ -2235,6 +2235,7 @@ flatpak_parse_repofile (const char *remote_name,
decoded = g_base64_decode (gpg_key, &decoded_len);
if (decoded_len < 10) /* Check some minimal size so we don't get crap */
{
+ g_free (decoded);
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Invalid gpg key"));
return NULL;
}
diff --git a/portal/flatpak-portal.c b/portal/flatpak-portal.c
index 7887c57a3b..0539ff2d22 100644
--- a/portal/flatpak-portal.c
+++ b/portal/flatpak-portal.c
@@ -767,7 +767,7 @@ handle_spawn (PortalFlatpak *object,
const gint *fds = NULL;
gint fds_len = 0;
g_autofree FdMapEntry *fd_map = NULL;
- gchar **env;
+ g_auto(GStrv) env = NULL;
gint32 max_fd;
GKeyFile *app_info;
g_autoptr(GPtrArray) flatpak_argv = g_ptr_array_new_with_free_func (g_free);

View File

@ -1,6 +1,6 @@
Name: flatpak
Version: 1.10.2
Release: 3
Release: 9
Summary: Application deployment framework for desktop apps
License: LGPLv2+
URL: http://flatpak.org/
@ -20,6 +20,27 @@ Patch6007: backport-0008-CVE-2021-41133.patch
Patch6008: backport-run-Handle-unknown-syscalls-as-intended.patch
Patch6009: backport-Fix-handling-of-syscalls-only-allowed-by-de.patch
Patch6010: backport-support-new-pyparsing.patch
Patch6011: backport-CVE-2022-21682.patch
Patch6012: backport-0001-CVE-2021-43860.patch
Patch6013: backport-0002-CVE-2021-43860.patch
Patch6014: backport-0003-CVE-2021-43860.patch
Patch6015: backport-0004-CVE-2021-43860.patch
Patch6016: backport-0005-CVE-2021-43860.patch
Patch6017: backport-Fix-several-memory-leaks.patch
# https://github.com/flatpak/flatpak/commit/4206d681c5c52691dec0074e3f8c32dab1953a94
Patch6018: CVE-2023-28100-pre1.patch
# https://github.com/flatpak/flatpak/commit/b83fb81d1a66fe4ea31fd9c36ca425705eaaca99
Patch6019: CVE-2023-28100-pre2.patch
# https://github.com/flatpak/flatpak/commit/e7880e25b9d400feeaacb82f115fae676ce6c65d
Patch6020: CVE-2023-28100-pre3.patch
# https://github.com/flatpak/flatpak/commit/a9bf18040cc075a70657c6090a59d7f6fe78f893
Patch6021: CVE-2023-28100.patch
# https://github.com/flatpak/flatpak/commit/acd627a2fabe9856947399044dbf7aa79247c75b
Patch6022: CVE-2023-28101-1.patch
# https://github.com/flatpak/flatpak/commit/e88eedce76f79a5573df4fc38b344bbeaf7af024
Patch6023: CVE-2023-28101-2.patch
Patch6024: CVE-2024-32462.patch
Patch6025: CVE-2024-42472.patch
BuildRequires: pkgconfig(appstream-glib) pkgconfig(gio-unix-2.0) pkgconfig(gobject-introspection-1.0) >= 1.40.0 pkgconfig(json-glib-1.0) pkgconfig(libarchive) >= 2.8.0
BuildRequires: pkgconfig(libsoup-2.4) pkgconfig(libxml-2.0) >= 2.4 pkgconfig(ostree-1) >= 2020.8 pkgconfig(polkit-gobject-1) pkgconfig(libseccomp) pkgconfig(xau)
@ -125,6 +146,24 @@ flatpak remote-list --system &> /dev/null || :
%{_mandir}/man5/flatpak-remote.5*
%changelog
* Thu Aug 15 2024 wangkai <13474090681@163.com> - 1.10.2-9
- Fix CVE-2024-42472
* Fri Apr 19 2024 wangkai <13474090681@163.com> - 1.10.2-8
- Fix CVE-2024-32462
* Thu Mar 28 2024 yaoxin <yao_xin001@hoperun.com> - 1.10.2-7
- Fix CVE-2023-28100 and CVE-2023-28101
* Tue Dec 26 2023 maokecheng <maokecheng@xfusion.com> - 1.10.2-6
- DESC:Fix several memory leaks
* Sat Jan 29 2022 dongyuzhen <dongyuzhen@h-partners.com> - 1.10.2-5
- Fix CVE-2021-43860
* Tue Jan 25 2022 hanhui <hanhui15@huawei.com> - 1.10.2-4
- Fix CVE-2022-21682
* Tue Jan 25 2022 hanhui <hanhui15@huawei.com> - 1.10.2-3
- Fix compiler error when using pyparsing >= 3.0.2