From 34a8c5aa987d4db5234172a62218b168371606b1 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 2 Oct 2018 16:02:58 +0100
Subject: [PATCH 4/5] For hidden operators, pass a name object to error
 handler.

In normal operation, Postscript error handlers are passed the object which
triggered the error: this is invariably an operator object.

The issue arises when an error is triggered by an operator which is for internal
use only, and that operator is then passed to the error handler, meaning it
becomes visible to the error handler code.

By converting to a name object, the error message is still valid, but we no
longer expose internal use only operators.

The change in gs_dps1.ps is related to the above: previously an error in
scheck would throw an error against .gcheck, but as .gcheck is now a hidden
operator, it resulted in a name object being passed to the error handler. As
scheck is a 'real' operator, it's better to use the real operator, rather than
the name of an internal, hidden one.

CVE: CVE-2018-17961
Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
 Resource/Init/gs_dps1.ps |  2 +-
 psi/interp.c             | 33 ++++++++++++++++++++++++---------
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps
index 1182f53..ec5db61 100644
--- a/Resource/Init/gs_dps1.ps
+++ b/Resource/Init/gs_dps1.ps
@@ -21,7 +21,7 @@ level2dict begin
 % ------ 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 --git a/psi/interp.c b/psi/interp.c
index cd894f9..b70769d 100644
--- a/psi/interp.c
+++ b/psi/interp.c
@@ -678,6 +678,8 @@ again:
     epref = &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 >= ostop) {
@@ -686,23 +688,36 @@ again:
         }
         *osp = *perror_object;
         errorexec_find(i_ctx_p, osp);
-        /* If using SAFER, hand a name object to the error handler, rather than the executable
-         * object/operator itself.
-         */
-        if (i_ctx_p->LockFilePermissions) {
+
+        if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) {
             code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr);
             if (code < 0) {
                 const char *unknownstr = "--unknown--";
                 rlen = strlen(unknownstr);
                 memcpy(buf, unknownstr, rlen);
+                bufptr = buf;
             }
             else {
-                buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
-                rlen += 4;
+                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, &tobj);
+                if (code < 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 < 0)
+                    make_null(osp);
             }
-            code = name_ref(imemory, buf, rlen, osp, 1);
-            if (code < 0)
-                make_null(osp);
         }
     }
     goto again;
-- 
2.7.4

