<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">not yet Submitted By: Ken Moffat &lt;ken at linuxfromscratch dot org&gt;
Date: 2018-10-09
Initial Package Version: 9.25
Upstream Status: Applied
Origin: Upstream
Description: Fixes another -dSAFER sandbox escape, probably in all
all versions still in use.  This is exploitable from e.g. gimp,
evince, and probably from some other applications which can use
postscript files.

http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=a54c9e61e7d0
 (manually fixed up)
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=a6807394bd94
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=1778db6bc10a

diff -Naur a/psi/interp.c b/psi/interp.c
--- a/psi/interp.c	2018-09-13 11:02:01.000000000 +0100
+++ b/psi/interp.c	2018-10-09 20:45:18.442954528 +0100
@@ -662,31 +662,24 @@
     if (gs_errorname(i_ctx_p, code, &amp;error_name) &lt; 0)
         return code;            /* out-of-range error code! */
 
-    /*  If LockFilePermissions is true, we only refer to gserrordict, which
-     *  is not accessible to Postcript jobs
+    /*  We refer to gserrordict first, which is not accessible to Postcript jobs
+     *  If we're running with SAFERERRORS all the handlers are copied to gserrordict
+     *  so we'll always find the default one. If not SAFERERRORS, only gs specific
+     *  errors are in gserrordict.
      */
-    if (i_ctx_p-&gt;LockFilePermissions) {
-        if (((dict_find_string(systemdict, "gserrordict", &amp;perrordict) &lt;= 0 ||
-              dict_find(perrordict, &amp;error_name, &amp;epref) &lt;= 0))
-            )
-            return code;            /* error name not in errordict??? */
-    }
-    else {
-        /*
-         * For greater Adobe compatibility, only the standard PostScript errors
-         * are defined in errordict; the rest are in gserrordict.
-         */
-        if (dict_find_string(systemdict, "errordict", &amp;perrordict) &lt;= 0 ||
-            (dict_find(perrordict, &amp;error_name, &amp;epref) &lt;= 0 &amp;&amp;
-             (dict_find_string(systemdict, "gserrordict", &amp;perrordict) &lt;= 0 ||
-              dict_find(perrordict, &amp;error_name, &amp;epref) &lt;= 0))
-            )
-            return code;            /* error name not in errordict??? */
-    }
+    if (dict_find_string(systemdict, "gserrordict", &amp;perrordict) &lt;= 0 ||
+        (dict_find(perrordict, &amp;error_name, &amp;epref) &lt;= 0 &amp;&amp;
+         (dict_find_string(systemdict, "errordict", &amp;perrordict) &lt;= 0 ||
+          dict_find(perrordict, &amp;error_name, &amp;epref) &lt;= 0))
+        )
+        return code;            /* error name not in errordict??? */
+
     doref = *epref;
     epref = &amp;doref;
     /* Push the error object on the operand stack if appropriate. */
     if (!GS_ERROR_IS_INTERRUPT(code)) {
+        byte buf[260], *bufptr;
+        uint rlen;
         /* Replace the error object if within an oparray or .errorexec. */
         osp++;
         if (osp &gt;= ostop) {
@@ -695,6 +688,37 @@
         }
         *osp = *perror_object;
         errorexec_find(i_ctx_p, osp);
+
+        if (!r_has_type(osp, t_string) &amp;&amp; !r_has_type(osp, t_name)) {
+            code = obj_cvs(imemory, osp, buf + 2, 256, &amp;rlen, (const byte **)&amp;bufptr);
+            if (code &lt; 0) {
+                const char *unknownstr = "--unknown--";
+                rlen = strlen(unknownstr);
+                memcpy(buf, unknownstr, rlen);
+                bufptr = buf;
+            }
+            else {
+                ref *tobj;
+                bufptr[rlen] = '\0';
+                /* Only pass a name object if the operator doesn't exist in systemdict
+                 * i.e. it's an internal operator we have hidden
+                 */
+                code = dict_find_string(systemdict, (const char *)bufptr, &amp;tobj);
+                if (code &lt; 0) {
+                    buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
+                    rlen += 4;
+                    bufptr = buf;
+                }
+                else {
+                    bufptr = NULL;
+                }
+            }
+            if (bufptr) {
+                code = name_ref(imemory, buf, rlen, osp, 1);
+                if (code &lt; 0)
+                    make_null(osp);
+            }
+        }
     }
     goto again;
 }
diff -Naur a/Resource/Init/gs_diskn.ps b/Resource/Init/gs_diskn.ps
--- a/Resource/Init/gs_diskn.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_diskn.ps	2018-10-09 20:35:56.075373644 +0100
@@ -53,7 +53,7 @@
     exch .setglobal
   }
   if
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 % Modify .putdevparams to force regeneration of .searchabledevs list
 /.putdevparams {
diff -Naur a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps
--- a/Resource/Init/gs_dps1.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_dps1.ps	2018-10-09 20:45:18.442954528 +0100
@@ -21,7 +21,7 @@
 % ------ Virtual memory ------ %
 
 /currentshared /.currentglobal load def
-/scheck /.gcheck load def
+/scheck {.gcheck} bind odef
 %****** FOLLOWING IS WRONG ******
 /shareddict currentdict /globaldict .knownget not { 20 dict } if def
 
diff -Naur a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps
--- a/Resource/Init/gs_dps.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_dps.ps	2018-10-09 20:35:56.075373644 +0100
@@ -70,7 +70,7 @@
                 % Save a copy of the initial gstate.
   //systemdict /savedinitialgstate gstate readonly .forceput
   .setglobal
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 % Initialize local dictionaries and gstate when creating a new context.
 % Note that until this completes, we are in the anomalous situation of
diff -Naur a/Resource/Init/gs_fntem.ps b/Resource/Init/gs_fntem.ps
--- a/Resource/Init/gs_fntem.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_fntem.ps	2018-10-09 20:35:56.075373644 +0100
@@ -408,7 +408,7 @@
     exit
   } loop
   exch setglobal
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 currentdict end /ProcSet defineresource pop
 
diff -Naur a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
--- a/Resource/Init/gs_fonts.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_fonts.ps	2018-10-09 20:38:27.925450703 +0100
@@ -373,7 +373,7 @@
 % and the access path.
 /.setnativefontmapbuilt { % set whether we've been run
   systemdict exch /.nativefontmapbuilt exch .forceput
-} .bind executeonly def
+} .bind executeonly odef
 systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt
 /.buildnativefontmap {   % - .buildnativefontmap &lt;bool&gt;
   systemdict /.nativefontmapbuilt .knownget not
@@ -1098,7 +1098,7 @@
 
                 % Check to make sure the font was actually loaded.
         dup 3 index .fontknownget
-         { dup /PathLoad 4 index //.putgstringcopy exec
+         { dup /PathLoad 4 index .putgstringcopy
            4 1 roll pop pop pop //true exit
          } if
 
@@ -1110,7 +1110,7 @@
          {            % Stack: origfontname fontdirectory path filefontname
            2 index 1 index .fontknownget
             {   % Yes.  Stack: origfontname fontdirectory path filefontname fontdict
-              dup 4 -1 roll /PathLoad exch //.putgstringcopy exec
+              dup 4 -1 roll /PathLoad exch .putgstringcopy
                       % Stack: origfontname fontdirectory filefontname fontdict
               3 -1 roll pop
                       % Stack: origfontname filefontname fontdict
diff -Naur a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
--- a/Resource/Init/gs_init.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_init.ps	2018-10-09 20:41:04.779497336 +0100
@@ -188,6 +188,16 @@
   currentdict /PARANOIDSAFER known or	% PARANOIDSAFER is equivalent
 }
 ifelse def
+
+/SAFERERRORS
+currentdict /NOSAFERERRORS known
+{
+  //false
+}
+{
+  currentdict /SAFERERRORS known
+} ifelse def
+
 currentdict /SHORTERRORS known   /SHORTERRORS exch def
 currentdict /TTYPAUSE known   /TTYPAUSE exch def
 currentdict /WRITESYSTEMDICT known   /WRITESYSTEMDICT exch def
@@ -1123,12 +1133,23 @@
  } bind def
 end		% errordict
 
-% Put all the default handlers in gserrordict
-gserrordict
-errordict {2 index 3 1 roll put} forall
-noaccess pop
-% remove the non-standard errors from errordict
+gserrordict /unknownerror errordict /unknownerror get put
 errordict /unknownerror .undef
+
+/.SAFERERRORLIST ErrorNames def
+/.setsafererrors
+{
+% Put all the requested handlers in gserrordict
+  gserrordict
+  //.SAFERERRORLIST
+  {dup errordict exch get 2 index 3 1 roll put} forall
+  noaccess pop
+  systemdict /.setsafeerrors .forceundef
+  systemdict /.SAFERERRORLIST .forceundef
+} bind executeonly odef
+
+SAFERERRORS {.setsafererrors} if
+
 % Define a stable private copy of handleerror that we will always use under
 % JOBSERVER mode.
 /.GShandleerror errordict /handleerror get def
@@ -1760,18 +1781,15 @@
 
 % Bind all the operators defined as procedures.
 /.bindoperators		% binds operators in currentdict
- { % Temporarily disable the typecheck error.
-   errordict /typecheck 2 copy get
-   errordict /typecheck { pop } put	% pop the command
+ {
    currentdict
     { dup type /operatortype eq
-       { % This might be a real operator, so bind might cause a typecheck,
-         % but we've made the error a no-op temporarily.
-         .bind
+       {
+         % This might be a real operator, so bind might cause a typecheck
+         {.bind} .internalstopped pop
        }
       if pop pop
     } forall
-   put
  } def
 DELAYBIND not { .bindoperators } if
 
diff -Naur a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps
--- a/Resource/Init/gs_lev2.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_lev2.ps	2018-10-09 20:35:56.076373638 +0100
@@ -163,10 +163,11 @@
         % Set them again to the new values.  From here on, we are safe,
         % since a context switch will consult userparams.
   .setuserparams
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 /setuserparams {		% &lt;dict&gt; setuserparams -
-    .setuserparams2
+    {.setuserparams2} stopped
+    {/setuserparams load $error /errorname get signalerror} if
 } .bind odef
 % Initialize user parameters managed here.
 /JobName () .definepsuserparam
@@ -415,7 +416,9 @@
 
 % VMReclaim and VMThreshold are user parameters.
 /setvmthreshold {		% &lt;int&gt; setvmthreshold -
-  mark /VMThreshold 2 .argindex .dicttomark .setuserparams2 pop
+  mark /VMThreshold 2 .argindex .dicttomark {.setuserparams2} stopped
+  {pop /setvmthreshold load $error /errorname get signalerror}
+  {pop} ifelse
 } odef
 /vmreclaim {			% &lt;int&gt; vmreclaim -
   dup 0 gt {
@@ -427,7 +430,9 @@
     ifelse
   } {
     % VMReclaim userparam controls enable/disable GC
-    mark /VMReclaim 2 index .dicttomark .setuserparams2 pop
+    mark /VMReclaim 2 index .dicttomark {.setuserparams2} stopped
+    {pop /vmreclaim load $error /errorname get signalerror}
+    {pop} ifelse
   } ifelse
 } odef
 -1 setvmthreshold
diff -Naur a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps
--- a/Resource/Init/gs_pdfwr.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_pdfwr.ps	2018-10-09 20:35:56.076373638 +0100
@@ -660,7 +660,7 @@
   {
     pop
   } ifelse
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 % Use the DSC processing hook to pass DSC comments to the driver.
 % We use a pseudo-parameter named DSC whose value is an array:
diff -Naur a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps
--- a/Resource/Init/gs_setpd.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_setpd.ps	2018-10-09 20:35:56.076373638 +0100
@@ -608,6 +608,20 @@
 % in the &lt;failed&gt; dictionary with the policy value,
 % and we replace the key in the &lt;merged&gt; dictionary with its prior value
 % (or remove it if it had no prior value).
+
+% Making this an operator means we can properly hide
+% the contents - specifically .forceput
+/1Policy
+{
+  % Roll back the failed request to its previous status.
+  SETPDDEBUG { (Rolling back.) = pstack flush } if
+  3 index 2 index 3 -1 roll .forceput
+  4 index 1 index .knownget
+   { 4 index 3 1 roll .forceput }
+   { 3 index exch .undef }
+  ifelse
+} bind executeonly odef
+
 /.policyprocs mark
 % These procedures are called with the following on the stack:
 %   &lt;orig&gt; &lt;merged&gt; &lt;failed&gt; &lt;Policies&gt; &lt;key&gt; &lt;policy&gt;
@@ -631,14 +645,7 @@
         /setpagedevice .systemvar /configurationerror signalerror
       } ifelse
   } bind
-  1 {		% Roll back the failed request to its previous status.
-SETPDDEBUG { (Rolling back.) = pstack flush } if
-        3 index 2 index 3 -1 roll .forceput
-        4 index 1 index .knownget
-         { 4 index 3 1 roll .forceput }
-         { 3 index exch .undef }
-        ifelse
-  } .bind executeonly % must be bound and hidden for .forceput
+  1 /1Policy load
   7 {		% For PageSize only, just impose the request.
         1 index /PageSize eq
          { pop pop 1 index /PageSize 7 put }
@@ -646,6 +653,8 @@
         ifelse
   } bind
 .dicttomark readonly def
+currentdict /1Policy undef
+
 /.applypolicies		% &lt;orig&gt; &lt;merged&gt; &lt;failed&gt; .applypolicies
                         %   &lt;orig&gt; &lt;merged'&gt; &lt;failed'&gt;
  { 1 index /Policies get 1 index
diff -Naur a/Resource/Init/gs_typ32.ps b/Resource/Init/gs_typ32.ps
--- a/Resource/Init/gs_typ32.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_typ32.ps	2018-10-09 20:35:56.076373638 +0100
@@ -79,15 +79,19 @@
 .dicttomark /ProcSet defineresource pop
 
 /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse
-.cidfonttypes begin
-
-4	% CIDFontType 4 = FontType 32
-{ dup /FontType 32 .forceput
+/CIDFontType4
+{
+  dup /FontType 32 .forceput
   dup /CharStrings 20 dict .forceput
   1 index exch .buildfont32 exch pop
-} .bind executeonly def % must be bound and hidden for .forceput
+} .bind executeonly odef
+.cidfonttypes begin
+
+
+4 /CIDFontType4 load def % CIDFontType 4 = FontType 32
 
 end		% .cidfonttypes
+currentdict /CIDFontType4 .forceundef
 
 % Define the BuildGlyph procedure.
 % Since Type 32 fonts are indexed by CID, there is no BuildChar procedure.
diff -Naur a/Resource/Init/gs_type1.ps b/Resource/Init/gs_type1.ps
--- a/Resource/Init/gs_type1.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/gs_type1.ps	2018-10-09 20:35:56.076373638 +0100
@@ -283,7 +283,7 @@
   } if
   2 copy /WeightVector exch .forceput
   .setweightvector
-} .bind executeonly def
+} .bind executeonly odef
 end
 
 % Register the font types for definefont.
diff -Naur a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps
--- a/Resource/Init/pdf_base.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/pdf_base.ps	2018-10-09 20:35:56.076373638 +0100
@@ -218,7 +218,7 @@
       } ifelse
     } ifelse
   } ifelse
-} bind executeonly def
+} bind executeonly odef
 /PDFScanRules_true &lt;&lt; /PDFScanRules //true &gt;&gt; def
 /PDFScanRules_null &lt;&lt; /PDFScanRules //null &gt;&gt; def
 /.pdfrun {			% &lt;file&gt; &lt;opdict&gt; .pdfrun -
diff -Naur a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps
--- a/Resource/Init/pdf_draw.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/pdf_draw.ps	2018-10-09 20:35:56.076373638 +0100
@@ -1158,7 +1158,7 @@
   Q
   PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if
   PDFfile exch setfileposition
-} bind executeonly def
+} bind executeonly odef
 
 /.pdfpaintproc {
     %% Get the /m from pdfopdict (must be present)
@@ -1189,7 +1189,7 @@
     {
       switch_to_text_marking_ops
     } if
-}bind executeonly def
+}bind executeonly odef
 
 /resolvepattern {	% &lt;patternstreamdict&gt; resolvepattern &lt;patterndict&gt;
                 % Don't do the resolvestream now: just capture the data
@@ -2353,7 +2353,7 @@
   }{
     pdfdict /AppearanceNumber 0 .forceput
   } ifelse
-}bind executeonly def
+}bind executeonly odef
 
 /MakeAppearanceName {
   pdfdict /AppearanceNumber get
@@ -2382,7 +2382,7 @@
   DoForm
   pdfdict /.PreservePDFForm 3 -1 roll .forceput
   grestore
-} bind executeonly def
+} bind executeonly odef
 
 /DoForm {
   %% save the current value, if its true we will set it to false later, in order
@@ -2541,7 +2541,7 @@
     end
   } if
   pdfdict /.PreservePDFForm 3 -1 roll .forceput
-} bind executeonly def
+} bind executeonly odef
 
 /_dops_save 1 array def
 
diff -Naur a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps
--- a/Resource/Init/pdf_font.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/pdf_font.ps	2018-10-09 20:35:56.076373638 +0100
@@ -718,7 +718,7 @@
   {pop pop pop}
   ifelse
 
-} bind executeonly def
+} bind executeonly odef
 
 currentdict /.DoToUnicode? .forceundef
 
@@ -1241,7 +1241,7 @@
     } bdef
     dup currentdict Encoding .processToUnicode
     currentdict end .completefont exch pop
-} bind executeonly def
+} bind executeonly odef
 /.adjustcharwidth {	% &lt;wx&gt; &lt;wy&gt; .adjustcharwidth &lt;wx'&gt; &lt;wy'&gt;
   % Enforce the metrics, in glyph space, to the values found in the PDF Font object
   % - force wy == 0 (assumed, and not stored in the PDF font)
@@ -2026,7 +2026,7 @@
     } if
     /findresource cvx /undefined signalerror
   } loop
-} bind executeonly def
+} bind executeonly odef
 
 /buildCIDType0 {	% &lt;CIDFontType0-font-resource&gt; buildCIDType0 &lt;font&gt;
   dup /BaseFont get findCIDFont exch pop
@@ -2211,7 +2211,7 @@
   /Type0 //buildType0
   /Type1 //buildType1
   /MMType1 //buildType1
-  /Type3 //buildType3
+  /Type3 /buildType3 load
   /TrueType //buildTrueType
   /CIDFontType0 //buildCIDType0
   /CIDFontType2 //buildCIDType2
diff -Naur a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps
--- a/Resource/Init/pdf_main.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/pdf_main.ps	2018-10-09 20:35:56.077373631 +0100
@@ -660,7 +660,7 @@
     } forall
     pop
   } ifelse
-} bind executeonly def
+} bind executeonly odef
 
 currentdict /pdf_collection_files .undef
 
@@ -2715,7 +2715,7 @@
   .setglobal
   /RepairedAnError exch def
   /Repaired exch def
-} bind executeonly def
+} bind executeonly odef
 
 % Display the contents of a page (including annotations).
 /showpagecontents {	% &lt;pagedict&gt; showpagecontents -
diff -Naur a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps
--- a/Resource/Init/pdf_ops.ps	2018-09-13 11:02:01.000000000 +0100
+++ b/Resource/Init/pdf_ops.ps	2018-10-09 20:35:56.077373631 +0100
@@ -193,7 +193,7 @@
       pdfformaterror
     } ifelse
   } if
-} bind executeonly def
+} bind executeonly odef
 
 % Save PDF gstate
 /qstate {       % - qstate &lt;qstate&gt;
@@ -451,7 +451,7 @@
   %% a gsave, so we haven't copied it to /self, if we don't do that here
   %% then transparent annotations cause an invalid access error.
   currentdict //nodict eq {/self dup load end 5 dict begin def} if
-} bind executeonly def
+} bind executeonly odef
 /AIS { .setalphaisshape } bind executeonly def
 /BM {
   /.setblendmode where {
@@ -1077,7 +1077,7 @@
     pdfopdict /v {inside_text_v} bind .forceput
     pdfopdict /y {inside_text_y} bind .forceput
     pdfopdict /re {inside_text_re} bind .forceput
-} bind executeonly def
+} bind executeonly odef
 
 /switch_to_normal_marking_ops {
     pdfopdict /m {normal_m} bind .forceput
@@ -1086,7 +1086,7 @@
     pdfopdict /v {normal_v} bind .forceput
     pdfopdict /y {normal_y} bind .forceput
     pdfopdict /re {normal_re} bind .forceput
-} bind executeonly def
+} bind executeonly odef
 
 /BT {
   currentdict /TextSaveMatrix known {
</pre></body></html>