Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2020-11736: libarchive: do not follow external links when extracting files (21dfcdbf) · Commits · GNOME / File Roller

fr-archive-libarchive.c in GNOME file-roller through 3.36.1 allows Directory Traversal during extraction because it lacks a check of whether a file’s parent is a symlink to a directory outside of the intended extraction location.

CVE

@@ -698,6 +698,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,

@@ -708,6 +851,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;

@@ -724,6 +868,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);

while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {

@@ -751,6 +896,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;

}

@@ -959,6 +1113,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;

@@ -993,6 +1149,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);

}

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907