Blame SOURCES/ghostscript-cve-2018-15908.patch

01c841
From: Chris Liddell <chris.liddell@artifex.com>
01c841
Date: Tue, 21 Aug 2018 19:17:05 +0000 (+0100)
01c841
Subject: Bug 699657: properly apply file permissions to .tempfile
01c841
01c841
Bug 699657: properly apply file permissions to .tempfile
01c841
01c841
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=0d3901189f245232f0161addf215d7268c4d05a3
01c841
---
01c841
01c841
diff -up a/psi/zfile.c.cve-2018-15908 b/psi/zfile.c
01c841
--- a/psi/zfile.c.cve-2018-15908	2018-11-14 15:13:31.249625819 +0100
01c841
+++ b/psi/zfile.c	2018-11-14 15:14:16.933831779 +0100
01c841
@@ -121,7 +121,7 @@ make_invalid_file(i_ctx_t *i_ctx_p, ref
01c841
 /* strings of the permitgroup array. */
01c841
 static int
01c841
 check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
01c841
-                        const char *permitgroup)
01c841
+                        gx_io_device *iodev, const char *permitgroup)
01c841
 {
01c841
     long i;
01c841
     ref *permitlist = NULL;
01c841
@@ -131,8 +131,14 @@ check_file_permissions_reduced(i_ctx_t *
01c841
     bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
01c841
     uint plen = gp_file_name_parents(fname, len);
01c841
 
01c841
-    /* Assuming a reduced file name. */
01c841
+    /* we're protecting arbitrary file system accesses, not Postscript device accesses.
01c841
+     * Although, note that %pipe% is explicitly checked for and disallowed elsewhere
01c841
+     */
01c841
+    if (iodev && iodev != iodev_default(imemory)) {
01c841
+        return 0;
01c841
+    }
01c841
 
01c841
+    /* Assuming a reduced file name. */
01c841
     if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
01c841
         return 0;       /* if Permissions not found, just allow access */
01c841
 
01c841
@@ -187,14 +193,14 @@ check_file_permissions_reduced(i_ctx_t *
01c841
 /* strings of the permitgroup array */
01c841
 static int
01c841
 check_file_permissions(i_ctx_t *i_ctx_p, const char *fname, int len,
01c841
-                        const char *permitgroup)
01c841
+                        gx_io_device *iodev, const char *permitgroup)
01c841
 {
01c841
     char fname_reduced[gp_file_name_sizeof];
01c841
     uint rlen = sizeof(fname_reduced);
01c841
 
01c841
     if (gp_file_name_reduce(fname, len, fname_reduced, &rlen) != gp_combine_success)
01c841
         return e_invalidaccess;         /* fail if we couldn't reduce */
01c841
-    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, permitgroup);
01c841
+    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
01c841
 }
01c841
 
01c841
 /* <name_string> <access_string> file <file> */
01c841
@@ -298,7 +304,7 @@ zdeletefile(i_ctx_t *i_ctx_p)
01c841
         return code;
01c841
     if (pname.iodev == iodev_default(imemory)) {
01c841
         if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
01c841
-                "PermitFileControl")) < 0 &&
01c841
+                pname.iodev, "PermitFileControl")) < 0 &&
01c841
                  !file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op))) {
01c841
             return code;
01c841
         }
01c841
@@ -382,7 +388,7 @@ file_continue(i_ctx_t *i_ctx_p)
01c841
         } else if (code > len)      /* overran string */
01c841
             return_error(gs_error_rangecheck);
01c841
         else if (iodev != iodev_default(imemory)
01c841
-              || (check_file_permissions_reduced(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, "PermitFileReading")) == 0) {
01c841
+              || (check_file_permissions_reduced(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, NULL, "PermitFileReading")) == 0) {
01c841
             push(1);
01c841
             ref_assign(op, pscratch);
01c841
             r_set_size(op, code + devlen);
01c841
@@ -432,12 +438,12 @@ zrenamefile(i_ctx_t *i_ctx_p)
01c841
                  * and FileWriting permissions to the destination file/path.
01c841
                  */
01c841
               ((check_file_permissions(i_ctx_p, pname1.fname, pname1.len,
01c841
-                                        "PermitFileControl") < 0 &&
01c841
+                                        pname1.iodev, "PermitFileControl") < 0 &&
01c841
                   !file_is_tempfile(i_ctx_p, op[-1].value.bytes, r_size(op - 1))) ||
01c841
               (check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
01c841
-                                        "PermitFileControl") < 0 ||
01c841
+                                        pname2.iodev, "PermitFileControl") < 0 ||
01c841
               check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
01c841
-                                        "PermitFileWriting") < 0 )))) {
01c841
+                                        pname2.iodev, "PermitFileWriting") < 0 )))) {
01c841
             code = gs_note_error(e_invalidfileaccess);
01c841
         } else {
01c841
             code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
01c841
@@ -484,8 +490,11 @@ zstatus(i_ctx_t *i_ctx_p)
01c841
                 code = gs_terminate_file_name(&pname, imemory, "status");
01c841
                 if (code < 0)
01c841
                     return code;
01c841
-                code = (*pname.iodev->procs.file_status)(pname.iodev,
01c841
+                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
01c841
+                                       pname.iodev, "PermitFileReading")) >= 0) {
01c841
+                    code = (*pname.iodev->procs.file_status)(pname.iodev,
01c841
                                                        pname.fname, &fstat);
01c841
+                }
01c841
                 switch (code) {
01c841
                     case 0:
01c841
                         check_ostack(4);
01c841
@@ -694,8 +703,24 @@ ztempfile(i_ctx_t *i_ctx_p)
01c841
     }
01c841
 
01c841
     if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
01c841
-        if (check_file_permissions(i_ctx_p, pstr, strlen(pstr),
01c841
-                                   "PermitFileWriting") < 0) {
01c841
+        int plen = strlen(pstr);
01c841
+        const char *sep = gp_file_name_separator();
01c841
+#ifdef DEBUG
01c841
+        int seplen = strlen(sep);
01c841
+        if (seplen != 1)
01c841
+            return_error(gs_error_Fatal);
01c841
+#endif
01c841
+        /* strip off the file name prefix, leave just the directory name
01c841
+         * so we can check if we are allowed to write to it
01c841
+         */
01c841
+        for ( ; plen >=0; plen--) {
01c841
+            if (pstr[plen] == sep[0])
01c841
+                break;
01c841
+        }
01c841
+        memcpy(fname, pstr, plen);
01c841
+        fname[plen] = '\0';
01c841
+        if (check_file_permissions(i_ctx_p, fname, strlen(fname),
01c841
+                                   NULL, "PermitFileWriting") < 0) {
01c841
             return_error(e_invalidfileaccess);
01c841
         }
01c841
     } else if (!prefix_is_simple(pstr)) {
01c841
@@ -837,6 +862,7 @@ zopen_file(i_ctx_t *i_ctx_p, const gs_pa
01c841
            const char *file_access, stream **ps, gs_memory_t *mem)
01c841
 {
01c841
     gx_io_device *const iodev = pfn->iodev;
01c841
+    int code = 0;
01c841
 
01c841
     if (pfn->fname == NULL)     /* just a device */
01c841
         return iodev->procs.open_device(iodev, file_access, ps, mem);
01c841
@@ -847,7 +873,7 @@ zopen_file(i_ctx_t *i_ctx_p, const gs_pa
01c841
             open_file = iodev_os_open_file;
01c841
         /* Check OS files to make sure we allow the type of access */
01c841
         if (open_file == iodev_os_open_file) {
01c841
-            int code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len,
01c841
+            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
01c841
                 file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
01c841
 
01c841
             if (code < 0 && !file_is_tempfile(i_ctx_p,
01c841
@@ -894,7 +920,7 @@ check_file_permissions_aux(i_ctx_t *i_ct
01c841
     /* fname must be reduced. */
01c841
     if (i_ctx_p == NULL)
01c841
         return 0;
01c841
-    if (check_file_permissions_reduced(i_ctx_p, fname, flen, "PermitFileReading") < 0)
01c841
+    if (check_file_permissions_reduced(i_ctx_p, fname, flen, NULL, "PermitFileReading") < 0)
01c841
         return_error(e_invalidfileaccess);
01c841
     return 0;
01c841
 }
5ed7ec