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

1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Thu, 6 Sep 2018 08:16:22 +0000 (+0100)
1164f7
Subject: Bug 699708 (part 1): 'Hide' non-replaceable error handlers for SAFER
1164f7
1164f7
Bug 699708 (part 1): 'Hide' non-replaceable error handlers for SAFER
1164f7
1164f7
We already had a 'private' dictionary for non-standard errors: gserrordict.
1164f7
1164f7
This now includes all the default error handlers, the dictionary is made
1164f7
noaccess and all the prodedures are bound and executeonly.
1164f7
1164f7
When running with -dSAFER, in the event of a Postscript error, instead of
1164f7
pulling the handler from errordict, we'll pull it from gserrordict - thus
1164f7
malicious input cannot trigger problems by the use of custom error handlers.
1164f7
1164f7
errordict remains open and writeable, so files such as the Quality Logic tests
1164f7
that install their own handlers will still 'work', with the exception that the
1164f7
custom error handlers will not be called.
1164f7
1164f7
This is a 'first pass', 'sledgehammer' approach: a nice addition would to allow
1164f7
an integrator to specify a list of errors that are not to be replaced (for
1164f7
example, embedded applications would probably want to ensure that VMerror is
1164f7
always handled as they intend).
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=fb713b3818b52d8a6cf62c951eba2e1795ff9624
1164f7
1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Thu, 4 Oct 2018 09:42:13 +0000 (+0100)
1164f7
Subject: Bug 699832: add control over hiding error handlers.
1164f7
1164f7
Bug 699832: add control over hiding error handlers.
1164f7
1164f7
With a previous commit changing error handling in SAFER so the handler gets
1164f7
passed a name object (rather than executable object), it is less critical to
1164f7
hide the error handlers.
1164f7
1164f7
This introduces a -dSAFERERRORS option to force only use of the default error
1164f7
handlers.
1164f7
1164f7
It also adds a .setsafererrors Postscript call, meaning a caller, without
1164f7
-dSAFERERRORS, can create their own default error handlers (in errordict, as
1164f7
normal), and then call .setsafererrors meaning their own handlers are always
1164f7
called.
1164f7
1164f7
With -dSAFERERRORS or after a call to .setsafererrors, .setsafererrors is
1164f7
removed.
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=1778db6bc10a8d60dfe986b22d2300326733ddd6
1164f7
1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Tue, 2 Oct 2018 15:02:58 +0000 (+0100)
1164f7
Subject: For hidden operators, pass a name object to error handler.
1164f7
1164f7
For hidden operators, pass a name object to error handler.
1164f7
1164f7
In normal operation, Postscript error handlers are passed the object which
1164f7
triggered the error: this is invariably an operator object.
1164f7
1164f7
The issue arises when an error is triggered by an operator which is for internal
1164f7
use only, and that operator is then passed to the error handler, meaning it
1164f7
becomes visible to the error handler code.
1164f7
1164f7
By converting to a name object, the error message is still valid, but we no
1164f7
longer expose internal use only operators.
1164f7
1164f7
The change in gs_dps1.ps is related to the above: previously an error in
1164f7
scheck would throw an error against .gcheck, but as .gcheck is now a hidden
1164f7
operator, it resulted in a name object being passed to the error handler. As
1164f7
scheck is a 'real' operator, it's better to use the real operator, rather than
1164f7
the name of an internal, hidden one.
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a6807394bd94b708be24758287b606154daaaed9
1164f7
---
1164f7
1164f7
diff -up ghostscript-9.07/psi/interp.c.cve-2018-17183 ghostscript-9.07/psi/interp.c
1164f7
--- ghostscript-9.07/psi/interp.c.cve-2018-17183	2018-11-30 14:21:33.531815665 +0100
1164f7
+++ ghostscript-9.07/psi/interp.c	2018-11-30 14:43:42.520691143 +0100
1164f7
@@ -650,20 +650,25 @@ again:
1164f7
         return code;
1164f7
     if (gs_errorname(i_ctx_p, code, &error_name) < 0)
1164f7
         return code;            /* out-of-range error code! */
1164f7
-    /*
1164f7
-     * For greater Adobe compatibility, only the standard PostScript errors
1164f7
-     * are defined in errordict; the rest are in gserrordict.
1164f7
+
1164f7
+    /*  We refer to gserrordict first, which is not accessible to Postcript jobs
1164f7
+     *  If we're running with SAFERERRORS all the handlers are copied to gserrordict
1164f7
+     *  so we'll always find the default one. If not SAFERERRORS, only gs specific
1164f7
+     *  errors are in gserrordict.
1164f7
      */
1164f7
-    if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
1164f7
+    if (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
1164f7
         (dict_find(perrordict, &error_name, &epref) <= 0 &&
1164f7
-         (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
1164f7
+         (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
1164f7
           dict_find(perrordict, &error_name, &epref) <= 0))
1164f7
         )
1164f7
         return code;            /* error name not in errordict??? */
1164f7
+
1164f7
     doref = *epref;
1164f7
     epref = &doref;
1164f7
     /* Push the error object on the operand stack if appropriate. */
1164f7
     if (!ERROR_IS_INTERRUPT(code)) {
1164f7
+        byte buf[260], *bufptr;
1164f7
+        uint rlen;
1164f7
         /* Replace the error object if within an oparray or .errorexec. */
1164f7
         osp++;
1164f7
         if (osp >= ostop) {
1164f7
@@ -672,6 +677,37 @@ again:
1164f7
         }
1164f7
         *osp = *perror_object;
1164f7
         errorexec_find(i_ctx_p, osp);
1164f7
+
1164f7
+        if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) {
1164f7
+            code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr);
1164f7
+            if (code < 0) {
1164f7
+                const char *unknownstr = "--unknown--";
1164f7
+                rlen = strlen(unknownstr);
1164f7
+                memcpy(buf, unknownstr, rlen);
1164f7
+                bufptr = buf;
1164f7
+            }
1164f7
+            else {
1164f7
+                ref *tobj;
1164f7
+                bufptr[rlen] = '\0';
1164f7
+                /* Only pass a name object if the operator doesn't exist in systemdict
1164f7
+                 * i.e. it's an internal operator we have hidden
1164f7
+                 */
1164f7
+                code = dict_find_string(systemdict, (const char *)bufptr, &tobj);
1164f7
+                if (code < 0) {
1164f7
+                    buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
1164f7
+                    rlen += 4;
1164f7
+                    bufptr = buf;
1164f7
+                }
1164f7
+                else {
1164f7
+                    bufptr = NULL;
1164f7
+                }
1164f7
+            }
1164f7
+            if (bufptr) {
1164f7
+                code = name_ref(imemory, buf, rlen, osp, 1);
1164f7
+                if (code < 0)
1164f7
+                    make_null(osp);
1164f7
+            }
1164f7
+        }
1164f7
     }
1164f7
     goto again;
1164f7
 }
1164f7
diff -up ghostscript-9.07/Resource/Init/gs_dps1.ps.cve-2018-17183 ghostscript-9.07/Resource/Init/gs_dps1.ps
1164f7
--- ghostscript-9.07/Resource/Init/gs_dps1.ps.cve-2018-17183	2018-11-30 14:40:30.044460932 +0100
1164f7
+++ ghostscript-9.07/Resource/Init/gs_dps1.ps	2018-11-30 14:41:03.291982495 +0100
1164f7
@@ -21,7 +21,7 @@ level2dict begin
1164f7
 % ------ Virtual memory ------ %
1164f7
 
1164f7
 /currentshared /.currentglobal load def
1164f7
-/scheck /.gcheck load def
1164f7
+/scheck {.gcheck} bind odef
1164f7
 %****** FOLLOWING IS WRONG ******
1164f7
 /shareddict currentdict /globaldict .knownget not { 20 dict } if def
1164f7
 
1164f7
diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-17183 ghostscript-9.07/Resource/Init/gs_init.ps
1164f7
--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-17183	2018-11-30 14:16:19.956328097 +0100
1164f7
+++ ghostscript-9.07/Resource/Init/gs_init.ps	2018-11-30 14:30:28.051123777 +0100
1164f7
@@ -183,6 +183,16 @@ currentdict /DELAYSAFER known { /DELAYSA
1164f7
   currentdict /PARANOIDSAFER known or	% PARANOIDSAFER is equivalent
1164f7
 }
1164f7
 ifelse def
1164f7
+
1164f7
+/SAFERERRORS
1164f7
+currentdict /NOSAFERERRORS known
1164f7
+{
1164f7
+  //false
1164f7
+}
1164f7
+{
1164f7
+  currentdict /SAFERERRORS known
1164f7
+} ifelse def
1164f7
+
1164f7
 currentdict /SHORTERRORS known   /SHORTERRORS exch def
1164f7
 currentdict /STRICT known   /STRICT exch def
1164f7
 currentdict /TTYPAUSE known   /TTYPAUSE exch def
1164f7
@@ -880,7 +890,7 @@ userdict /.currentresourcefile //null pu
1164f7
        { not exch pop exit } { pop } ifelse
1164f7
     }
1164f7
    for exch pop .quit
1164f7
- } bind def
1164f7
+ } bind executeonly def
1164f7
 /.errorhandler		% <command> <errorname> .errorhandler -
1164f7
   {		% Detect an internal 'stopped'.
1164f7
     1 .instopped { //null eq { pop pop stop } if } if
1164f7
@@ -925,7 +935,7 @@ userdict /.currentresourcefile //null pu
1164f7
     $error /globalmode get $error /.nosetlocal get and .setglobal
1164f7
     $error /.inerror //false put
1164f7
     stop
1164f7
-  } bind def
1164f7
+  } bind executeonly def
1164f7
 % Define the standard handleerror.  We break out the printing procedure
1164f7
 % (.printerror) so that it can be extended for binary output
1164f7
 % if the Level 2 facilities are present.
1164f7
@@ -975,7 +985,7 @@ userdict /.currentresourcefile //null pu
1164f7
      ifelse	% newerror
1164f7
      end
1164f7
      flush
1164f7
-    } bind def
1164f7
+    } bind executeonly def
1164f7
   /.printerror_long			% long error printout,
1164f7
                                         % $error is on the dict stack
1164f7
    {	% Push the (anonymous) stack printing procedure.
1164f7
@@ -1052,14 +1062,14 @@ userdict /.currentresourcefile //null pu
1164f7
         { (Current file position is ) print position = }
1164f7
        if
1164f7
 
1164f7
-   } bind def
1164f7
+   } bind executeonly def
1164f7
 % Define a procedure for clearing the error indication.
1164f7
 /.clearerror
1164f7
  { $error /newerror //false put
1164f7
    $error /errorname //null put
1164f7
    $error /errorinfo //null put
1164f7
    0 .setoserrno
1164f7
- } bind def
1164f7
+ } bind executeonly def
1164f7
 
1164f7
 % Define $error.  This must be in local VM.
1164f7
 .currentglobal //false .setglobal
1164f7
@@ -1085,11 +1095,15 @@ end
1164f7
 /errordict ErrorNames length 3 add dict
1164f7
 .forcedef		% errordict is local, systemdict is global
1164f7
 .setglobal		% back to global VM
1164f7
-% For greater Adobe compatibility, we put all non-standard errors in a
1164f7
-%   separate dictionary, gserrordict.  It does not need to be in local VM,
1164f7
-%   because PostScript programs do not access it.
1164f7
+%  gserrordict contains all the default error handling methods, but unlike
1164f7
+%  errordict it is noaccess after creation (also it is in global VM).
1164f7
+%  When running 'SAFER', we'll ignore the contents of errordict, which
1164f7
+%  may have been tampered with by the running job, and always use gserrordict
1164f7
+%  gserrordict also contains any non-standard errors, for better compatibility
1164f7
+%  with Adobe.
1164f7
+%
1164f7
 %   NOTE: the name gserrordict is known to the interpreter.
1164f7
-/gserrordict 5 dict def
1164f7
+/gserrordict ErrorNames length 3 add dict def
1164f7
 % Register an error in errordict.  We make this a procedure because we only
1164f7
 % register the Level 1 errors here: the rest are registered by "feature"
1164f7
 % files.  However, ErrorNames contains all of the error names regardless of
1164f7
@@ -1118,9 +1132,23 @@ errordict begin
1164f7
  } bind def
1164f7
 end		% errordict
1164f7
 
1164f7
-% Put non-standard errors in gserrordict.
1164f7
 gserrordict /unknownerror errordict /unknownerror get put
1164f7
 errordict /unknownerror .undef
1164f7
+
1164f7
+/.SAFERERRORLIST ErrorNames def
1164f7
+/.setsafererrors
1164f7
+{
1164f7
+% Put all the requested handlers in gserrordict
1164f7
+  gserrordict
1164f7
+  //.SAFERERRORLIST
1164f7
+  {dup errordict exch get 2 index 3 1 roll put} forall
1164f7
+  noaccess pop
1164f7
+  systemdict /.setsafeerrors .forceundef
1164f7
+  systemdict /.SAFERERRORLIST .forceundef
1164f7
+} bind executeonly odef
1164f7
+
1164f7
+SAFERERRORS {.setsafererrors} if
1164f7
+
1164f7
 % Define a stable private copy of handleerror that we will always use under
1164f7
 % JOBSERVER mode.
1164f7
 /.GShandleerror errordict /handleerror get def
1164f7
@@ -1743,18 +1771,15 @@ currentdict /.runlibfile .undef
1164f7
 
1164f7
 % Bind all the operators defined as procedures.
1164f7
 /.bindoperators		% binds operators in currentdict
1164f7
- { % Temporarily disable the typecheck error.
1164f7
-   errordict /typecheck 2 copy get
1164f7
-   errordict /typecheck { pop } put	% pop the command
1164f7
+ {
1164f7
    currentdict
1164f7
     { dup type /operatortype eq
1164f7
-       { % This might be a real operator, so bind might cause a typecheck,
1164f7
-         % but we've made the error a no-op temporarily.
1164f7
-         .bind		% do a real bind even if NOBIND is set
1164f7
+       {
1164f7
+         % This might be a real operator, so bind might cause a typecheck
1164f7
+         {.bind} .internalstopped pop
1164f7
        }
1164f7
       if pop pop
1164f7
     } forall
1164f7
-   put
1164f7
  } def
1164f7
 NOBIND DELAYBIND or not { .bindoperators } if
1164f7