From b261d129e63005d2b043a6f668a1a4a3424f7307 Mon Sep 17 00:00:00 2001 From: wang_yue111 <648774160@qq.com> Date: Thu, 29 Jul 2021 17:28:42 +0800 Subject: [PATCH] Fix CVE-2020-11736 (cherry picked from commit 626eec41afd5596c0f450d66c66c0467b0aa8c04) --- backport-CVE-2020-11736.patch | 218 ++++++++++++++++++++++++++++++++++ file-roller.spec | 6 +- 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2020-11736.patch diff --git a/backport-CVE-2020-11736.patch b/backport-CVE-2020-11736.patch new file mode 100644 index 0000000..639f690 --- /dev/null +++ b/backport-CVE-2020-11736.patch @@ -0,0 +1,218 @@ +From 8d48f633a48232c0ae8785a7388ae7e99faf3c5b Mon Sep 17 00:00:00 2001 +From: Paolo Bacchilega +Date: Sun, 12 Apr 2020 11:38:35 +0200 +Subject: [PATCH] libarchive: do not follow external links when extracting + files + +Do not extract a file if its parent is a symbolic link to a +directory external to the destination. +--- + src/fr-archive-libarchive.c | 157 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 157 insertions(+) + +diff --git a/src/fr-archive-libarchive.c b/src/fr-archive-libarchive.c +index 1d45164..e86ed3d 100644 +--- a/src/fr-archive-libarchive.c ++++ b/src/fr-archive-libarchive.c +@@ -603,6 +603,149 @@ _g_output_stream_add_padding (ExtractData *extract_data, + } + + ++static gboolean ++_symlink_is_external_to_destination (GFile *file, ++ const char *symlink, ++ GFile *destination, ++ GHashTable *external_links); ++ ++ ++static gboolean ++_g_file_is_external_link (GFile *file, ++ GFile *destination, ++ GHashTable *external_links) ++{ ++ GFileInfo *info; ++ gboolean external; ++ ++ if (g_hash_table_lookup (external_links, file) != NULL) ++ return TRUE; ++ ++ info = g_file_query_info (file, ++ G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, ++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, ++ NULL, ++ NULL); ++ ++ if (info == NULL) ++ return FALSE; ++ ++ external = FALSE; ++ ++ if (g_file_info_get_is_symlink (info)) { ++ if (_symlink_is_external_to_destination (file, ++ g_file_info_get_symlink_target (info), ++ destination, ++ external_links)) ++ { ++ g_hash_table_insert (external_links, g_object_ref (file), GINT_TO_POINTER (1)); ++ external = TRUE; ++ } ++ } ++ ++ g_object_unref (info); ++ ++ return external; ++} ++ ++ ++static gboolean ++_symlink_is_external_to_destination (GFile *file, ++ const char *symlink, ++ GFile *destination, ++ GHashTable *external_links) ++{ ++ gboolean external = FALSE; ++ GFile *parent; ++ char **components; ++ int i; ++ ++ if ((file == NULL) || (symlink == NULL)) ++ return FALSE; ++ ++ if (symlink[0] == '/') ++ return TRUE; ++ ++ parent = g_file_get_parent (file); ++ components = g_strsplit (symlink, "/", -1); ++ for (i = 0; components[i] != NULL; i++) { ++ char *name = components[i]; ++ GFile *tmp; ++ ++ if ((name[0] == 0) || ((name[0] == '.') && (name[1] == 0))) ++ continue; ++ ++ if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { ++ if (g_file_equal (parent, destination)) { ++ external = TRUE; ++ break; ++ } ++ else { ++ tmp = g_file_get_parent (parent); ++ g_object_unref (parent); ++ parent = tmp; ++ } ++ } ++ else { ++ tmp = g_file_get_child (parent, components[i]); ++ g_object_unref (parent); ++ parent = tmp; ++ } ++ ++ if (_g_file_is_external_link (parent, destination, external_links)) { ++ external = TRUE; ++ break; ++ } ++ } ++ ++ g_strfreev (components); ++ g_object_unref (parent); ++ ++ return external; ++} ++ ++ ++static gboolean ++_g_path_is_external_to_destination (const char *relative_path, ++ GFile *destination, ++ GHashTable *external_links) ++{ ++ gboolean external = FALSE; ++ GFile *parent; ++ char **components; ++ int i; ++ ++ if (relative_path == NULL) ++ return FALSE; ++ ++ if (destination == NULL) ++ return TRUE; ++ ++ parent = g_object_ref (destination); ++ components = g_strsplit (relative_path, "/", -1); ++ for (i = 0; (components[i] != NULL) && (components[i + 1] != NULL); i++) { ++ GFile *tmp; ++ ++ if (components[i][0] == 0) ++ continue; ++ ++ tmp = g_file_get_child (parent, components[i]); ++ g_object_unref (parent); ++ parent = tmp; ++ ++ if (_g_file_is_external_link (parent, destination, external_links)) { ++ external = TRUE; ++ break; ++ } ++ } ++ ++ g_strfreev (components); ++ g_object_unref (parent); ++ ++ return external; ++} ++ ++ + static void + extract_archive_thread (GSimpleAsyncResult *result, + GObject *object, +@@ -613,6 +756,7 @@ extract_archive_thread (GSimpleAsyncResult *result, + GHashTable *checked_folders; + GHashTable *created_files; + GHashTable *folders_created_during_extraction; ++ GHashTable *external_links; + struct archive *a; + struct archive_entry *entry; + int r; +@@ -623,6 +767,7 @@ extract_archive_thread (GSimpleAsyncResult *result, + checked_folders = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL); + created_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref); + folders_created_during_extraction = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL); ++ external_links = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL); + fr_archive_progress_set_total_files (load_data->archive, extract_data->n_files_to_extract); + + a = archive_read_new (); +@@ -654,6 +799,15 @@ extract_archive_thread (GSimpleAsyncResult *result, + fullpath = (*pathname == '/') ? g_strdup (pathname) : g_strconcat ("/", pathname, NULL); + relative_path = _g_path_get_relative_basename_safe (fullpath, extract_data->base_dir, extract_data->junk_paths); + if (relative_path == NULL) { ++ fr_archive_progress_inc_completed_files (load_data->archive, 1); ++ fr_archive_progress_inc_completed_bytes (load_data->archive, archive_entry_size_is_set (entry) ? archive_entry_size (entry) : 0); ++ archive_read_data_skip (a); ++ continue; ++ } ++ ++ if (_g_path_is_external_to_destination (relative_path, extract_data->destination, external_links)) { ++ fr_archive_progress_inc_completed_files (load_data->archive, 1); ++ fr_archive_progress_inc_completed_bytes (load_data->archive, archive_entry_size_is_set (entry) ? archive_entry_size (entry) : 0); + archive_read_data_skip (a); + continue; + } +@@ -862,6 +1016,8 @@ extract_archive_thread (GSimpleAsyncResult *result, + load_data->error = g_error_copy (local_error); + g_clear_error (&local_error); + } ++ else if (_symlink_is_external_to_destination (file, archive_entry_symlink (entry), extract_data->destination, external_links)) ++ g_hash_table_insert (external_links, g_object_ref (file), GINT_TO_POINTER (1)); + archive_read_data_skip (a); + break; + +@@ -896,6 +1052,7 @@ extract_archive_thread (GSimpleAsyncResult *result, + g_hash_table_unref (folders_created_during_extraction); + g_hash_table_unref (created_files); + g_hash_table_unref (checked_folders); ++ g_hash_table_unref (external_links); + archive_read_free (a); + extract_data_free (extract_data); + } +-- +2.23.0 + diff --git a/file-roller.spec b/file-roller.spec index 72f858c..f6ab2a0 100644 --- a/file-roller.spec +++ b/file-roller.spec @@ -1,11 +1,12 @@ Name: file-roller Version: 3.30.1 -Release: 2 +Release: 3 Summary: An archive manager utility for the GNOME Environment License: GPLv2+ URL: https://wiki.gnome.org/Apps/FileRoller Source0: https://download.gnome.org/sources/%{name}/3.30/%{name}-%{version}.tar.xz +Patch0: backport-CVE-2020-11736.patch BuildRequires: cpio gettext gcc itstool file-devel pkgconfig(gthread-2.0) BuildRequires: meson >= 0.43 pkgconfig(glib-2.0) >= 2.36 pkgconfig(gtk+-3.0) >= 3.13.2 pkgconfig(libnautilus-extension) >= 2.22.2 @@ -58,5 +59,8 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.gnome.FileRoller. %{_libdir}/nautilus/extensions-3.0/libnautilus-fileroller.so %changelog +* Thu Jul 29 2021 wangyue - 3.30.1-3 +- Fix CVE-2020-11736 + * Thu Oct 17 2019 Yiru Wang - 1.20.7-17 - Pakcage init