diff --git a/CVE-2023-28100-pre1.patch b/CVE-2023-28100-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..191e9895d21772786abdc2bdbaff8e548da76658 --- /dev/null +++ b/CVE-2023-28100-pre1.patch @@ -0,0 +1,394 @@ +From 4206d681c5c52691dec0074e3f8c32dab1953a94 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +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 +Co-authored-by: Alexander Larsson +(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 . ++ */ ++ ++#include "config.h" ++ ++#include ++ ++#include ++#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 (); ++} diff --git a/CVE-2023-28100-pre2.patch b/CVE-2023-28100-pre2.patch new file mode 100644 index 0000000000000000000000000000000000000000..5bd847a5aa4e4e13f03cbb63c3a62fc9e28fa9c3 --- /dev/null +++ b/CVE-2023-28100-pre2.patch @@ -0,0 +1,231 @@ +From b83fb81d1a66fe4ea31fd9c36ca425705eaaca99 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +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 +, 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 +(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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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; ++} diff --git a/CVE-2023-28100-pre3.patch b/CVE-2023-28100-pre3.patch new file mode 100644 index 0000000000000000000000000000000000000000..3caff79e434b1f52db949d03dcb54c78f03d132f --- /dev/null +++ b/CVE-2023-28100-pre3.patch @@ -0,0 +1,142 @@ +From e7880e25b9d400feeaacb82f115fae676ce6c65d Mon Sep 17 00:00:00 2001 +From: Simon McVittie +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 +(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 diff --git a/CVE-2023-28100.patch b/CVE-2023-28100.patch new file mode 100644 index 0000000000000000000000000000000000000000..36844efb136efdc5740b892da9aafe92979b0e21 --- /dev/null +++ b/CVE-2023-28100.patch @@ -0,0 +1,85 @@ +From a9bf18040cc075a70657c6090a59d7f6fe78f893 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +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 +--- + 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 */ diff --git a/CVE-2023-28101-1.patch b/CVE-2023-28101-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..3478800958eb74b9d275a3201d087cd51ce22ac3 --- /dev/null +++ b/CVE-2023-28101-1.patch @@ -0,0 +1,320 @@ +From acd627a2fabe9856947399044dbf7aa79247c75b Mon Sep 17 00:00:00 2001 +From: Ryan Gonzalez +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 +--- + 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 <> ${DIR}/metadata < 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); diff --git a/CVE-2023-28101-2.patch b/CVE-2023-28101-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..f4c66d4384136d4af99fbc71f1ac38efaff0cc41 --- /dev/null +++ b/CVE-2023-28101-2.patch @@ -0,0 +1,408 @@ +From e88eedce76f79a5573df4fc38b344bbeaf7af024 Mon Sep 17 00:00:00 2001 +From: Ryan Gonzalez +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 +Co-authored-by: Simon McVittie +--- + 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); diff --git a/backport-Fix-several-memory-leaks.patch b/backport-Fix-several-memory-leaks.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c75b9c6781a3b805a864adc6b872c6279da04c5 --- /dev/null +++ b/backport-Fix-several-memory-leaks.patch @@ -0,0 +1,85 @@ +From b912053c6cc556f131465c1fd877d7bd0b433539 Mon Sep 17 00:00:00 2001 +From: Phaedrus Leeds +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); diff --git a/flatpak.spec b/flatpak.spec index f84255fa6f24f74587530c7d7c8d170be78563f0..ac485a80af3b6b9fc100104ca38bde4df938bf33 100644 --- a/flatpak.spec +++ b/flatpak.spec @@ -1,6 +1,6 @@ Name: flatpak Version: 1.10.2 -Release: 5 +Release: 7 Summary: Application deployment framework for desktop apps License: LGPLv2+ URL: http://flatpak.org/ @@ -26,6 +26,19 @@ 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 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) @@ -131,6 +144,12 @@ flatpak remote-list --system &> /dev/null || : %{_mandir}/man5/flatpak-remote.5* %changelog +* Thu Mar 28 2024 yaoxin - 1.10.2-7 +- Fix CVE-2023-28100 and CVE-2023-28101 + +* Tue Dec 26 2023 maokecheng - 1.10.2-6 +- DESC:Fix several memory leaks + * Sat Jan 29 2022 dongyuzhen - 1.10.2-5 - Fix CVE-2021-43860