diff options
author | lukefromdc <[email protected]> | 2023-12-25 01:40:42 -0500 |
---|---|---|
committer | Luke from DC <[email protected]> | 2024-01-17 22:39:09 +0000 |
commit | e70b21c815418a1e6ebedf6d8d31b8477c03ba50 (patch) | |
tree | 281419f3f764493f7b53a792c6d0a064379e01fa | |
parent | ce41df6467521ff9fd4f16514ae7d6ebb62eb1ed (diff) | |
download | atril-e70b21c815418a1e6ebedf6d8d31b8477c03ba50.tar.bz2 atril-e70b21c815418a1e6ebedf6d8d31b8477c03ba50.tar.xz |
epub: Prevent path traversal when extracting files
Test each file's resolved path against the temporary directory
before extracting.
-rw-r--r-- | backend/epub/epub-document.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c index b025c630..38ab4c83 100644 --- a/backend/epub/epub-document.c +++ b/backend/epub/epub-document.c @@ -635,7 +635,7 @@ check_mime_type(const gchar* uri,GError** error) for (i = 0; i < g_strv_length (mimetypes); i++) { if (strcmp(mimeFromFile, mimetypes[i]) == 0) return TRUE; - } + } /* fallback for malformed epub files */ if (strcmp (mimeFromFile, "application/zip") == 0) @@ -671,7 +671,7 @@ check_mime_type(const gchar* uri,GError** error) } static gboolean -extract_one_file(EpubDocument* epub_document,GError ** error) +extract_one_file(EpubDocument* epub_document, GFile *tmp_gfile, GError ** error) { GFile * outfile ; gsize writesize = 0; @@ -698,6 +698,20 @@ extract_one_file(EpubDocument* epub_document,GError ** error) gfilepath = g_string_new(epub_document->tmp_archive_dir) ; g_string_append_printf(gfilepath,"/%s",(gchar*)currentfilename); + outfile = g_file_new_for_path (gfilepath->str); + g_autofree gchar *rpath = g_file_get_relative_path (tmp_gfile, outfile); + + if (rpath == NULL) + { + g_set_error_literal (error, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("epub file is invalid or corrupt")); + g_critical ("Invalid filename in Epub container - '%s'", (gchar *) currentfilename); + result = FALSE; + goto out; + } + /*if we encounter a directory, make a directory inside our temporary folder.*/ if (directory != NULL && *directory == '\0') { @@ -725,7 +739,6 @@ extract_one_file(EpubDocument* epub_document,GError ** error) g_string_free(dir_create,TRUE); } - outfile = g_file_new_for_path(gfilepath->str); outstream = g_file_create(outfile,G_FILE_CREATE_PRIVATE,NULL,error); gpointer buffer = g_malloc0(512); while ( (writesize = unzReadCurrentFile(epub_document->epubDocument,buffer,512) ) != 0 ) @@ -738,10 +751,10 @@ extract_one_file(EpubDocument* epub_document,GError ** error) } g_free(buffer); g_output_stream_close((GOutputStream*)outstream,NULL,error); - g_object_unref(outfile) ; - g_object_unref(outstream) ; + g_object_unref(outstream); out: + g_object_unref(outfile); unzCloseCurrentFile (epub_document->epubDocument) ; g_string_free(gfilepath,TRUE); g_free(currentfilename); @@ -753,6 +766,7 @@ extract_epub_from_container (const gchar* uri, EpubDocument *epub_document, GError ** error) { + GFile *tmp_gfile = NULL; GError *err = NULL; epub_document->archivename = g_filename_from_uri(uri,NULL,error); @@ -814,9 +828,10 @@ extract_epub_from_container (const gchar* uri, goto out; } + tmp_gfile = g_file_new_for_path (epub_document->tmp_archive_dir); while ( TRUE ) { - if ( extract_one_file(epub_document,&err) == FALSE ) + if ( extract_one_file(epub_document, tmp_gfile, &err) == FALSE ) { if (err) { g_propagate_error (error, err); @@ -837,6 +852,7 @@ extract_epub_from_container (const gchar* uri, } out: + g_clear_object (&tmp_gfile); unzClose(epub_document->epubDocument); return result; } |