Additional security fix that missed 9.24.

Taken from upstream:
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=fb713b3818b52d8a6cf62c951eba2e1795ff9624

From fb713b3818b52d8a6cf62c951eba2e1795ff9624 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 6 Sep 2018 09:16:22 +0100
Subject: [PATCH] Bug 699708 (part 1): 'Hide' non-replaceable error handlers
 for SAFER

We already had a 'private' dictionary for non-standard errors: gserrordict.

This now includes all the default error handlers, the dictionary is made
noaccess and all the prodedures are bound and executeonly.

When running with -dSAFER, in the event of a Postscript error, instead of
pulling the handler from errordict, we'll pull it from gserrordict - thus
malicious input cannot trigger problems by the use of custom error handlers.

errordict remains open and writeable, so files such as the Quality Logic tests
that install their own handlers will still 'work', with the exception that the
custom error handlers will not be called.

This is a 'first pass', 'sledgehammer' approach: a nice addition would to allow
an integrator to specify a list of errors that are not to be replaced (for
example, embedded applications would probably want to ensure that VMerror is
always handled as they intend).
---
 Resource/Init/gs_init.ps | 29 ++++++++++++++++++-----------
 psi/interp.c             | 30 +++++++++++++++++++++---------
 2 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index 071c39205..bc8b7951c 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -881,7 +881,7 @@ userdict /.currentresourcefile //null put
        { not exch pop exit } { pop } ifelse
     }
    for exch pop .quit
- } bind def
+ } bind executeonly def
 /.errorhandler		% <command> <errorname> .errorhandler -
   {		% Detect an internal 'stopped'.
     1 .instopped { //null eq { pop pop stop } if } if
@@ -926,7 +926,7 @@ userdict /.currentresourcefile //null put
     $error /globalmode get $error /.nosetlocal get and .setglobal
     $error /.inerror //false put
     stop
-  } bind def
+  } bind executeonly def
 % Define the standard handleerror.  We break out the printing procedure
 % (.printerror) so that it can be extended for binary output
 % if the Level 2 facilities are present.
@@ -976,7 +976,7 @@ userdict /.currentresourcefile //null put
      ifelse	% newerror
      end
      flush
-    } bind def
+    } bind executeonly def
   /.printerror_long			% long error printout,
                                         % $error is on the dict stack
    {	% Push the (anonymous) stack printing procedure.
@@ -1053,14 +1053,14 @@ userdict /.currentresourcefile //null put
         { (Current file position is ) print position = }
        if
 
-   } bind def
+   } bind executeonly def
 % Define a procedure for clearing the error indication.
 /.clearerror
  { $error /newerror //false put
    $error /errorname //null put
    $error /errorinfo //null put
    0 .setoserrno
- } bind def
+ } bind executeonly def
 
 % Define $error.  This must be in local VM.
 .currentglobal //false .setglobal
@@ -1086,11 +1086,15 @@ end
 /errordict ErrorNames length 3 add dict
 .forcedef		% errordict is local, systemdict is global
 .setglobal		% back to global VM
-% For greater Adobe compatibility, we put all non-standard errors in a
-%   separate dictionary, gserrordict.  It does not need to be in local VM,
-%   because PostScript programs do not access it.
+%  gserrordict contains all the default error handling methods, but unlike
+%  errordict it is noaccess after creation (also it is in global VM).
+%  When running 'SAFER', we'll ignore the contents of errordict, which
+%  may have been tampered with by the running job, and always use gserrordict
+%  gserrordict also contains any non-standard errors, for better compatibility
+%  with Adobe.
+%
 %   NOTE: the name gserrordict is known to the interpreter.
-/gserrordict 5 dict def
+/gserrordict ErrorNames length 3 add dict def
 % Register an error in errordict.  We make this a procedure because we only
 % register the Level 1 errors here: the rest are registered by "feature"
 % files.  However, ErrorNames contains all of the error names regardless of
@@ -1119,8 +1123,11 @@ errordict begin
  } bind def
 end		% errordict
 
-% Put non-standard errors in gserrordict.
-gserrordict /unknownerror errordict /unknownerror get put
+% 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
 errordict /unknownerror .undef
 % Define a stable private copy of handleerror that we will always use under
 % JOBSERVER mode.
diff --git a/psi/interp.c b/psi/interp.c
index c27b70dca..d41a9d3f5 100644
--- a/psi/interp.c
+++ b/psi/interp.c
@@ -661,16 +661,28 @@ again:
         return code;
     if (gs_errorname(i_ctx_p, code, &error_name) < 0)
         return code;            /* out-of-range error code! */
-    /*
-     * For greater Adobe compatibility, only the standard PostScript errors
-     * are defined in errordict; the rest are in gserrordict.
+
+    /*  If LockFilePermissions is true, we only refer to gserrordict, which
+     *  is not accessible to Postcript jobs
      */
-    if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
-        (dict_find(perrordict, &error_name, &epref) <= 0 &&
-         (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
-          dict_find(perrordict, &error_name, &epref) <= 0))
-        )
-        return code;            /* error name not in errordict??? */
+    if (i_ctx_p->LockFilePermissions) {
+        if (((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
+              dict_find(perrordict, &error_name, &epref) <= 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", &perrordict) <= 0 ||
+            (dict_find(perrordict, &error_name, &epref) <= 0 &&
+             (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
+              dict_find(perrordict, &error_name, &epref) <= 0))
+            )
+            return code;            /* error name not in errordict??? */
+    }
     doref = *epref;
     epref = &doref;
     /* Push the error object on the operand stack if appropriate. */
-- 
2.18.0

