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

8812f8
From: Chris Liddell <chris.liddell@artifex.com>
8812f8
Date: Tue, 21 Aug 2018 19:17:05 +0000 (+0100)
8812f8
Subject: Bug 699657: properly apply file permissions to .tempfile
8812f8
8812f8
Bug 699657: properly apply file permissions to .tempfile
8812f8
8812f8
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=0d3901189f245232f0161addf215d7268c4d05a3
8812f8
8812f8
From: Chris Liddell <chris.liddell@artifex.com>
8812f8
Date: Tue, 21 Aug 2018 19:17:51 +0000 (+0100)
8812f8
Subject: Bug 699658: Fix handling of pre-SAFER opened files.
8812f8
8812f8
Bug 699658: Fix handling of pre-SAFER opened files.
8812f8
8812f8
Temp files opened for writing before SAFER is engaged are not subject to the
8812f8
SAFER restrictions - that is handled by recording in a dictionary, and
8812f8
checking that as part of the permissions checks.
8812f8
8812f8
By adding a custom error handler for invalidaccess, that allowed the filename
8812f8
to be added to the dictionary (despite the attempted open throwing the error)
8812f8
thus meaning subsequent accesses were erroneously permitted.
8812f8
8812f8
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a054156d425b4dbdaaa9fda4b5f1182b27598c2b
8812f8
---
8812f8
8812f8
diff -up a/psi/zfile.c.cve-2018-15908 b/psi/zfile.c
8812f8
--- a/psi/zfile.c.cve-2018-15908	2018-11-14 15:13:31.249625819 +0100
8812f8
+++ b/psi/zfile.c	2018-11-14 15:14:16.933831779 +0100
8812f8
@@ -121,7 +121,7 @@ make_invalid_file(i_ctx_t *i_ctx_p, ref
8812f8
 /* strings of the permitgroup array. */
8812f8
 static int
8812f8
 check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
8812f8
-                        const char *permitgroup)
8812f8
+                        gx_io_device *iodev, const char *permitgroup)
8812f8
 {
8812f8
     long i;
8812f8
     ref *permitlist = NULL;
8812f8
@@ -131,8 +131,14 @@ check_file_permissions_reduced(i_ctx_t *
8812f8
     bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
8812f8
     uint plen = gp_file_name_parents(fname, len);
8812f8
 
8812f8
-    /* Assuming a reduced file name. */
8812f8
+    /* we're protecting arbitrary file system accesses, not Postscript device accesses.
8812f8
+     * Although, note that %pipe% is explicitly checked for and disallowed elsewhere
8812f8
+     */
8812f8
+    if (iodev && iodev != iodev_default(imemory)) {
8812f8
+        return 0;
8812f8
+    }
8812f8
 
8812f8
+    /* Assuming a reduced file name. */
8812f8
     if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
8812f8
         return 0;       /* if Permissions not found, just allow access */
8812f8
 
8812f8
@@ -187,14 +193,14 @@ check_file_permissions_reduced(i_ctx_t *
8812f8
 /* strings of the permitgroup array */
8812f8
 static int
8812f8
 check_file_permissions(i_ctx_t *i_ctx_p, const char *fname, int len,
8812f8
-                        const char *permitgroup)
8812f8
+                        gx_io_device *iodev, const char *permitgroup)
8812f8
 {
8812f8
     char fname_reduced[gp_file_name_sizeof];
8812f8
     uint rlen = sizeof(fname_reduced);
8812f8
 
8812f8
     if (gp_file_name_reduce(fname, len, fname_reduced, &rlen) != gp_combine_success)
8812f8
         return e_invalidaccess;         /* fail if we couldn't reduce */
8812f8
-    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, permitgroup);
8812f8
+    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
8812f8
 }
8812f8
 
8812f8
 /* <name_string> <access_string> file <file> */
8812f8
@@ -298,7 +304,7 @@ zdeletefile(i_ctx_t *i_ctx_p)
8812f8
         return code;
8812f8
     if (pname.iodev == iodev_default(imemory)) {
8812f8
         if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
8812f8
-                "PermitFileControl")) < 0 &&
8812f8
+                pname.iodev, "PermitFileControl")) < 0 &&
8812f8
                  !file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op))) {
8812f8
             return code;
8812f8
         }
8812f8
@@ -382,7 +388,7 @@ file_continue(i_ctx_t *i_ctx_p)
8812f8
         } else if (code > len)      /* overran string */
8812f8
             return_error(gs_error_rangecheck);
8812f8
         else if (iodev != iodev_default(imemory)
8812f8
-              || (check_file_permissions_reduced(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, "PermitFileReading")) == 0) {
8812f8
+              || (check_file_permissions_reduced(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, NULL, "PermitFileReading")) == 0) {
8812f8
             push(1);
8812f8
             ref_assign(op, pscratch);
8812f8
             r_set_size(op, code + devlen);
8812f8
@@ -432,12 +438,12 @@ zrenamefile(i_ctx_t *i_ctx_p)
8812f8
                  * and FileWriting permissions to the destination file/path.
8812f8
                  */
8812f8
               ((check_file_permissions(i_ctx_p, pname1.fname, pname1.len,
8812f8
-                                        "PermitFileControl") < 0 &&
8812f8
+                                        pname1.iodev, "PermitFileControl") < 0 &&
8812f8
                   !file_is_tempfile(i_ctx_p, op[-1].value.bytes, r_size(op - 1))) ||
8812f8
               (check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
8812f8
-                                        "PermitFileControl") < 0 ||
8812f8
+                                        pname2.iodev, "PermitFileControl") < 0 ||
8812f8
               check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
8812f8
-                                        "PermitFileWriting") < 0 )))) {
8812f8
+                                        pname2.iodev, "PermitFileWriting") < 0 )))) {
8812f8
             code = gs_note_error(e_invalidfileaccess);
8812f8
         } else {
8812f8
             code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
8812f8
@@ -484,8 +490,11 @@ zstatus(i_ctx_t *i_ctx_p)
8812f8
                 code = gs_terminate_file_name(&pname, imemory, "status");
8812f8
                 if (code < 0)
8812f8
                     return code;
8812f8
-                code = (*pname.iodev->procs.file_status)(pname.iodev,
8812f8
+                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
8812f8
+                                       pname.iodev, "PermitFileReading")) >= 0) {
8812f8
+                    code = (*pname.iodev->procs.file_status)(pname.iodev,
8812f8
                                                        pname.fname, &fstat);
8812f8
+                }
8812f8
                 switch (code) {
8812f8
                     case 0:
8812f8
                         check_ostack(4);
8812f8
@@ -694,8 +703,24 @@ ztempfile(i_ctx_t *i_ctx_p)
8812f8
     }
8812f8
 
8812f8
     if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
8812f8
-        if (check_file_permissions(i_ctx_p, pstr, strlen(pstr),
8812f8
-                                   "PermitFileWriting") < 0) {
8812f8
+        int plen = strlen(pstr);
8812f8
+        const char *sep = gp_file_name_separator();
8812f8
+#ifdef DEBUG
8812f8
+        int seplen = strlen(sep);
8812f8
+        if (seplen != 1)
8812f8
+            return_error(gs_error_Fatal);
8812f8
+#endif
8812f8
+        /* strip off the file name prefix, leave just the directory name
8812f8
+         * so we can check if we are allowed to write to it
8812f8
+         */
8812f8
+        for ( ; plen >=0; plen--) {
8812f8
+            if (pstr[plen] == sep[0])
8812f8
+                break;
8812f8
+        }
8812f8
+        memcpy(fname, pstr, plen);
8812f8
+        fname[plen] = '\0';
8812f8
+        if (check_file_permissions(i_ctx_p, fname, strlen(fname),
8812f8
+                                   NULL, "PermitFileWriting") < 0) {
8812f8
             return_error(e_invalidfileaccess);
8812f8
         }
8812f8
     } else if (!prefix_is_simple(pstr)) {
8812f8
@@ -837,6 +862,7 @@ zopen_file(i_ctx_t *i_ctx_p, const gs_pa
8812f8
            const char *file_access, stream **ps, gs_memory_t *mem)
8812f8
 {
8812f8
     gx_io_device *const iodev = pfn->iodev;
8812f8
+    int code = 0;
8812f8
 
8812f8
     if (pfn->fname == NULL)     /* just a device */
8812f8
         return iodev->procs.open_device(iodev, file_access, ps, mem);
8812f8
@@ -847,7 +873,7 @@ zopen_file(i_ctx_t *i_ctx_p, const gs_pa
8812f8
             open_file = iodev_os_open_file;
8812f8
         /* Check OS files to make sure we allow the type of access */
8812f8
         if (open_file == iodev_os_open_file) {
8812f8
-            int code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len,
8812f8
+            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
8812f8
                 file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
8812f8
 
8812f8
             if (code < 0 && !file_is_tempfile(i_ctx_p,
8812f8
@@ -894,7 +920,7 @@ check_file_permissions_aux(i_ctx_t *i_ct
8812f8
     /* fname must be reduced. */
8812f8
     if (i_ctx_p == NULL)
8812f8
         return 0;
8812f8
-    if (check_file_permissions_reduced(i_ctx_p, fname, flen, "PermitFileReading") < 0)
8812f8
+    if (check_file_permissions_reduced(i_ctx_p, fname, flen, NULL, "PermitFileReading") < 0)
8812f8
         return_error(e_invalidfileaccess);
8812f8
     return 0;
8812f8
 }
8812f8
diff -up a/Resource/Init/gs_init.ps.cve-2018-15908 b/Resource/Init/gs_init.ps
8812f8
--- a/Resource/Init/gs_init.ps.cve-2018-15908	2018-11-14 16:34:23.268867657 +0100
8812f8
+++ b/Resource/Init/gs_init.ps	2018-11-14 16:36:38.765552576 +0100
8812f8
@@ -2015,6 +2015,19 @@ readonly def
8812f8
             concatstrings concatstrings .generate_dir_list_templates
8812f8
         } if
8812f8
       ]
8812f8
+      /PermitFileWriting [
8812f8
+          currentuserparams /PermitFileWriting get aload pop
8812f8
+          (TMPDIR) getenv not
8812f8
+          {
8812f8
+            (TEMP) getenv not
8812f8
+            {
8812f8
+              (TMP) getenv not
8812f8
+              {
8812f8
+                (/temp) (/tmp)
8812f8
+              } if
8812f8
+            } if
8812f8
+          } if
8812f8
+      ]
8812f8
       /LockFilePermissions //true
8812f8
     >> setuserparams
8812f8
   }
8812f8
@@ -2062,7 +2075,9 @@ readonly def
8812f8
 % the file can be deleted later, even if SAFER is set.
8812f8
 /.tempfile {
8812f8
   .tempfile	% filename file
8812f8
-  //SAFETY /tempfiles get 2 .argindex //true .forceput
8812f8
+    //SAFETY /safe get not { % only add the filename if we're not yet safe
8812f8
+    //SAFETY /tempfiles get 2 .argindex //true .forceput
8812f8
+  } if
8812f8
 } .bind executeonly odef
8812f8
 
8812f8
 % If we are running in SAFER mode, lock things down