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

1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Tue, 4 Sep 2018 22:18:46 +0000 (+0100)
1164f7
Subject: Bug 699714: retain .LockSafetyParams through failed .installpagedevice
1164f7
1164f7
Bug 699714: retain .LockSafetyParams through failed .installpagedevice
1164f7
1164f7
In the event that the .trysetparams fails during .installpagedevice, catch the
1164f7
error, and ensure that at least the .LockSafetyParams is set.
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=5812b1b78fc4d36fdc293b7859de69241140d590
1164f7
1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Wed, 5 Sep 2018 16:14:59 +0000 (+0100)
1164f7
Subject: Bug 699718: Ensure stack space is available before gsrestore call out
1164f7
1164f7
Bug 699718: Ensure stack space is available before gsrestore call out
1164f7
1164f7
During a grestore, if the device is going to change, we call out to Postscript
1164f7
to restore the device configuration, before returning to restore the graphics
1164f7
state internally.
1164f7
1164f7
We have to ensure sufficient op stack space is available to complete the
1164f7
operation, otherwise the device can end up an undefined state.
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=3e5d316b72e3965b7968bb1d96baa137cd063ac6
1164f7
1164f7
From: Chris Liddell <chris.liddell@artifex.com>
1164f7
Date: Fri, 7 Sep 2018 07:07:12 +0000 (+0100)
1164f7
Subject: Bug 699718(2): Improve/augment stack size checking
1164f7
1164f7
Bug 699718(2): Improve/augment stack size checking
1164f7
1164f7
Improve the rebustness of the previous solution (previously it could trigger an
1164f7
error when there *was* stack capacity available).
1164f7
1164f7
Remove redundant check: we don't need to check if the *current* stack size is
1164f7
sufficient, before checking the maximum permitted stack size.
1164f7
1164f7
Also check the exec stack, as execstackoverflow can also cause the
1164f7
Postscript call out to fail.
1164f7
1164f7
Lastly, in event of failure, put the LockSafetyParams flag back in the existing
1164f7
device (this is only necessary because we don't enfore JOBSERVER mode).
1164f7
1164f7
Note: the Postscript callout (%grestorepagedevice) never pushes any dictionaries
1164f7
on the dict stack - if that changes, we should check that stack, too.
1164f7
1164f7
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=643b24dbd002fb9c131313253c307cf3951b3d47
1164f7
---
1164f7
1164f7
diff -up ghostscript-9.07/base/gserrors.h.cve-2018-16802 ghostscript-9.07/base/gserrors.h
1164f7
--- ghostscript-9.07/base/gserrors.h.cve-2018-16802	2018-11-27 19:07:38.076517822 +0100
1164f7
+++ ghostscript-9.07/base/gserrors.h	2018-11-27 19:09:19.116234748 +0100
1164f7
@@ -25,6 +25,7 @@
1164f7
 /* We use ints rather than an enum to avoid a lot of casting. */
1164f7
 
1164f7
 #define gs_error_unknownerror (-1)	/* unknown error */
1164f7
+#define gs_error_execstackoverflow (-5)
1164f7
 #define gs_error_interrupt (-6)
1164f7
 #define gs_error_invalidaccess (-7)
1164f7
 #define gs_error_invalidfileaccess (-9)
1164f7
@@ -33,6 +34,7 @@
1164f7
 #define gs_error_limitcheck (-13)
1164f7
 #define gs_error_nocurrentpoint (-14)
1164f7
 #define gs_error_rangecheck (-15)
1164f7
+#define gs_error_stackoverflow (-16)
1164f7
 #define gs_error_stackunderflow (-17)
1164f7
 #define gs_error_typecheck (-20)
1164f7
 #define gs_error_undefined (-21)
1164f7
diff -up ghostscript-9.07/psi/zdevice2.c.cve-2018-16802 ghostscript-9.07/psi/zdevice2.c
1164f7
--- ghostscript-9.07/psi/zdevice2.c.cve-2018-16802	2018-11-27 19:04:51.665627148 +0100
1164f7
+++ ghostscript-9.07/psi/zdevice2.c	2018-11-27 19:04:51.696626755 +0100
1164f7
@@ -250,8 +250,8 @@ z2currentgstate(i_ctx_t *i_ctx_p)
1164f7
 /* ------ Wrappers for operators that reset the graphics state. ------ */
1164f7
 
1164f7
 /* Check whether we need to call out to restore the page device. */
1164f7
-static bool
1164f7
-restore_page_device(const gs_state * pgs_old, const gs_state * pgs_new)
1164f7
+static int
1164f7
+restore_page_device(i_ctx_t *i_ctx_p, const gs_state * pgs_old, const gs_state * pgs_new)
1164f7
 {
1164f7
     gx_device *dev_old = gs_currentdevice(pgs_old);
1164f7
     gx_device *dev_new;
1164f7
@@ -259,9 +259,10 @@ restore_page_device(const gs_state * pgs
1164f7
     gx_device *dev_t2;
1164f7
     bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
1164f7
         &gs_int_gstate(pgs_new)->pagedevice);
1164f7
+    bool LockSafetyParams = dev_old->LockSafetyParams;
1164f7
 
1164f7
     if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
1164f7
-        return false;
1164f7
+        return 0;
1164f7
     /* If we are going to putdeviceparams in a callout, we need to */
1164f7
     /* unlock temporarily.  The device will be re-locked as needed */
1164f7
     /* by putdeviceparams from the pgs_old->pagedevice dict state. */
1164f7
@@ -270,23 +271,51 @@ restore_page_device(const gs_state * pgs
1164f7
     dev_new = gs_currentdevice(pgs_new);
1164f7
     if (dev_old != dev_new) {
1164f7
         if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
1164f7
-            return false;
1164f7
-        if (dev_t1 != dev_t2)
1164f7
-            return true;
1164f7
+            samepagedevice = true;
1164f7
+        else if (dev_t1 != dev_t2)
1164f7
+            samepagedevice = false;
1164f7
+    }
1164f7
+
1164f7
+    if (LockSafetyParams && !samepagedevice) {
1164f7
+        const int required_ops = 512;
1164f7
+        const int required_es = 32;
1164f7
+
1164f7
+        /* The %grestorepagedevice must complete: the biggest danger
1164f7
+           is operand stack overflow. As we use get/putdeviceparams
1164f7
+           that means pushing all the device params onto the stack,
1164f7
+           pdfwrite having by far the largest number of parameters
1164f7
+           at (currently) 212 key/value pairs - thus needing (currently)
1164f7
+           424 entries on the op stack. Allowing for working stack
1164f7
+           space, and safety margin.....
1164f7
+         */
1164f7
+        if (required_ops + ref_stack_count(&o_stack) >= ref_stack_max_count(&o_stack)) {
1164f7
+           gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
1164f7
+           return_error(gs_error_stackoverflow);
1164f7
+        }
1164f7
+        /* We also want enough exec stack space - 32 is an overestimate of
1164f7
+           what we need to complete the Postscript call out.
1164f7
+         */
1164f7
+        if (required_es + ref_stack_count(&e_stack) >= ref_stack_max_count(&e_stack)) {
1164f7
+           gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
1164f7
+           return_error(gs_error_execstackoverflow);
1164f7
+        }
1164f7
     }
1164f7
     /*
1164f7
      * The current implementation of setpagedevice just sets new
1164f7
      * parameters in the same device object, so we have to check
1164f7
      * whether the page device dictionaries are the same.
1164f7
      */
1164f7
-    return !samepagedevice;
1164f7
+    return samepagedevice ? 0 : 1;
1164f7
 }
1164f7
 
1164f7
 /* - grestore - */
1164f7
 static int
1164f7
 z2grestore(i_ctx_t *i_ctx_p)
1164f7
 {
1164f7
-    if (!restore_page_device(igs, gs_state_saved(igs)))
1164f7
+    int code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs));
1164f7
+    if (code < 0) return code;
1164f7
+
1164f7
+    if (code == 0)
1164f7
         return gs_grestore(igs);
1164f7
     return push_callout(i_ctx_p, "%grestorepagedevice");
1164f7
 }
1164f7
@@ -296,7 +325,9 @@ static int
1164f7
 z2grestoreall(i_ctx_t *i_ctx_p)
1164f7
 {
1164f7
     for (;;) {
1164f7
-        if (!restore_page_device(igs, gs_state_saved(igs))) {
1164f7
+        int code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs));
1164f7
+        if (code < 0) return code;
1164f7
+        if (code == 0) {
1164f7
             bool done = !gs_state_saved(gs_state_saved(igs));
1164f7
 
1164f7
             gs_grestore(igs);
1164f7
@@ -327,11 +358,15 @@ z2restore(i_ctx_t *i_ctx_p)
1164f7
     if (code < 0) return code;
1164f7
 
1164f7
     while (gs_state_saved(gs_state_saved(igs))) {
1164f7
-        if (restore_page_device(igs, gs_state_saved(igs)))
1164f7
+        code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs));
1164f7
+        if (code < 0) return code;
1164f7
+        if (code > 0)
1164f7
             return push_callout(i_ctx_p, "%restore1pagedevice");
1164f7
         gs_grestore(igs);
1164f7
     }
1164f7
-    if (restore_page_device(igs, gs_state_saved(igs)))
1164f7
+    code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs));
1164f7
+    if (code < 0) return code;
1164f7
+    if (code > 0)
1164f7
         return push_callout(i_ctx_p, "%restorepagedevice");
1164f7
 
1164f7
     code = dorestore(i_ctx_p, asave);
1164f7
@@ -354,9 +389,12 @@ static int
1164f7
 z2setgstate(i_ctx_t *i_ctx_p)
1164f7
 {
1164f7
     os_ptr op = osp;
1164f7
+    int code;
1164f7
 
1164f7
     check_stype(*op, st_igstate_obj);
1164f7
-    if (!restore_page_device(igs, igstate_ptr(op)))
1164f7
+    code = restore_page_device(i_ctx_p, igs, igstate_ptr(op));
1164f7
+    if (code < 0) return code;
1164f7
+    if (code == 0)
1164f7
         return zsetgstate(i_ctx_p);
1164f7
     return push_callout(i_ctx_p, "%setgstatepagedevice");
1164f7
 }
1164f7
diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-16802 ghostscript-9.07/Resource/Init/gs_setpd.ps
1164f7
--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-16802	2013-02-14 08:58:16.000000000 +0100
1164f7
+++ ghostscript-9.07/Resource/Init/gs_setpd.ps	2018-11-27 19:04:51.696626755 +0100
1164f7
@@ -95,27 +95,41 @@ level2dict begin
1164f7
  {	% Since setpagedevice doesn't create new device objects,
1164f7
         % we must (carefully) reinstall the old parameters in
1164f7
         % the same device.
1164f7
-   .currentpagedevice pop //null currentdevice //null .trysetparams
1164f7
+   .currentpagedevice pop //null currentdevice //null
1164f7
+   { .trysetparams } .internalstopped
1164f7
+   {
1164f7
+     //null
1164f7
+   } if
1164f7
    dup type /booleantype eq
1164f7
     { pop pop }
1164f7
-    {		% This should never happen!
1164f7
+    {
1164f7
       SETPDDEBUG { (Error in .trysetparams!) = pstack flush } if
1164f7
-      cleartomark pop pop pop
1164f7
+      {cleartomark pop pop pop} .internalstopped pop
1164f7
+      % if resetting the entire device state failed, at least put back the
1164f7
+      % security related key
1164f7
+      currentdevice //null //false mark /.LockSafetyParams
1164f7
+      currentpagedevice /.LockSafetyParams .knownget not
1164f7
+      {systemdict /SAFER .knownget not {//false} } if
1164f7
+      .putdeviceparamsonly
1164f7
       /.installpagedevice cvx /rangecheck signalerror
1164f7
     }
1164f7
    ifelse pop pop
1164f7
         % A careful reading of the Red Book reveals that an erasepage
1164f7
         % should occur, but *not* an initgraphics.
1164f7
    erasepage .beginpage
1164f7
- } bind def
1164f7
+ } bind executeonly def
1164f7
 
1164f7
 /.uninstallpagedevice
1164f7
- { 2 .endpage { .currentnumcopies //false .outputpage } if
1164f7
+ {
1164f7
+   {2 .endpage { .currentnumcopies //false .outputpage } if} .internalstopped pop
1164f7
    nulldevice
1164f7
  } bind def
1164f7
 
1164f7
 (%grestorepagedevice) cvn
1164f7
- { .uninstallpagedevice grestore .installpagedevice
1164f7
+ {
1164f7
+ .uninstallpagedevice
1164f7
+ grestore
1164f7
+ .installpagedevice
1164f7
  } bind def
1164f7
 
1164f7
 (%grestoreallpagedevice) cvn