CVE-2023-44451: Insufficient Information (NVD-CWE-noinfo)
value: Linux Mint Xreader EPUB File Parsing Directory Traversal Remote Code Execution Vulnerability. This vulnerability allows remote attackers to execute arbitrary code on affected installations of Linux Mint Xreader. User interaction is required to exploit this vulnerability in that the target must visit a malicious page or open a malicious file.

The specific flaw exists within the parsing of EPUB files. The issue results from the lack of proper validation of a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to execute code in the context of the current user. Was ZDI-CAN-21897.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-05-03T03:16Z
Repository: https://github.com/linuxmint/xreader
Language: C
Files changed: backend/epub/epub-document.c
Commit date: 2023-12-12 11:26:38 +0000
Commit message: epub: Prevent path traversal when extracting files [CVE-2023-44451]

Test each file's resolved path against the temporary directory
before extracting.

Fixes:
CVE-2023-44451 - Linux Mint Xreader EPUB File Parsing Directory
Traversal Remote Code Execution Vulnerability.

This vulnerability was discovered by:
Febin Mon Saji working with Trend Micro Zero Day Initiative

Diff: diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c
index 4000671..157209b 100644
--- a/backend/epub/epub-document.c
+++ b/backend/epub/epub-document.c
@@ -663,11 +663,11 @@ check_mime_type(const gchar* uri,GError** error)
         return FALSE;
     }
 }
 
 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;
     GString * gfilepath ;
     unz_file_info64 info ;
@@ -694,10 +694,25 @@ extract_one_file(EpubDocument* epub_document,GError ** error)
     
     // handle the html extension (IssueID #266)
     if (g_strrstr(currentfilename, ".html") != NULL)
         g_string_insert_c (gfilepath, gfilepath->len-4, 'x');
 
+    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);
+        g_object_unref (outfile);
+        result = FALSE;
+        goto out;
+    }
+
     /*if we encounter a directory, make a directory inside our temporary folder.*/
     if (directory != NULL && *directory == '\0')
     {
         g_mkdir(gfilepath->str,0777);
         goto out;
@@ -721,11 +736,10 @@ extract_one_file(EpubDocument* epub_document,GError ** error)
 
         g_mkdir_with_parents(dir_create->str,0777);
 		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 )
     {
         if ( g_output_stream_write((GOutputStream*)outstream,buffer,writesize,NULL,error) == -1 )
@@ -749,10 +763,11 @@ out:
 static gboolean
 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);
 
     if ( !epub_document->archivename )
     {
@@ -810,13 +825,15 @@ extract_epub_from_container (const gchar* uri,
                          _("could not extract archive"));
         }
         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);
             }
             else    {
@@ -833,10 +850,11 @@ extract_epub_from_container (const gchar* uri,
             break;
         }
     }
 
 out:
+    g_clear_object (&tmp_gfile);
     unzClose(epub_document->epubDocument);
     return result;
 }
 
 static gchar*

Vulnerable code: extract_one_file(EpubDocument* epub_document,GError ** error)
    outfile = g_file_new_for_path(gfilepath->str);
        if ( extract_one_file(epub_document,&err) == FALSE )
Fixed code: extract_one_file(EpubDocument* epub_document, GFile *tmp_gfile, GError ** error)
    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);
        g_object_unref (outfile);
        result = FALSE;
        goto out;
    }

    GFile *tmp_gfile = NULL;
    tmp_gfile = g_file_new_for_path (epub_document->tmp_archive_dir);

        if ( extract_one_file(epub_document, tmp_gfile, &err) == FALSE )
    g_clear_object (&tmp_gfile);