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

09061c
From: Chris Liddell <chris.liddell@artifex.com>
09061c
Date: Wed, 14 Nov 2018 09:50:08 +0000 (+0000)
09061c
Subject: Bug 700176: check the *output* device for LockSafetyParams
09061c
09061c
Bug 700176: check the *output* device for LockSafetyParams
09061c
09061c
When calling .setdevice we were checking if LockSafetyParams was set, and if so
09061c
throwing an invalidaccess error.
09061c
09061c
The problem is, if another device, for example the pdf14 compositor is the 'top'
09061c
device, that does not (and cannot) honour LockSafetyParams.
09061c
09061c
To solve this, we'll now use the (relatively new) gxdso_current_output_device
09061c
spec_op to retrieve the *actual* output device, and check the LockSafetyParams
09061c
flag in that.
09061c
09061c
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=661e8d8fb8248c38d67958beda32f3a5876d0c3f
09061c
09061c
From: Chris Liddell <chris.liddell@artifex.com>
09061c
Date: Wed, 14 Nov 2018 21:04:46 +0000 (+0000)
09061c
Subject: Bug 700176: Use the actual output device for both devices in setdevice
09061c
09061c
Bug 700176: Use the actual output device for both devices in setdevice
09061c
09061c
Also fixes bug 700189.
09061c
09061c
The pdf14 compositor device, despite being a forwarding device, does not forward
09061c
all spec_ops to it's target, only a select few are special cased for that.
09061c
gxdso_current_output_device needs to be included in those special cases.
09061c
09061c
The original commit (661e8d8fb8248) changed the code to use the spec_op to
09061c
retrieve the output device, checking that for LockSafetyParams. If
09061c
LockSafetyParams is set, it returns an invalidaccess error if the new device
09061c
differs from the current device.
09061c
09061c
When we do the comparison between the two devices, we need to check the
09061c
output device in both cases.
09061c
09061c
This is complicated by the fact that the new device may not have ever been set
09061c
(and thus fully initialised), and may not have a spec_op method available at
09061c
that point.
09061c
09061c
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=ea1b3ef437f39e45874f821c06bd953196625ac5
09061c
09061c
From: Chris Liddell <chris.liddell@artifex.com>
09061c
Date: Mon, 17 Sep 2018 13:06:12 +0000 (+0100)
09061c
Subject: Implement .currentoutputdevice operator
09061c
09061c
Implement .currentoutputdevice operator
09061c
09061c
The currentdevice operator returns the device currently installed in the
09061c
graphics state. This can be the output/page device, but also could be a
09061c
forwarding device (bbox device), compositor (pdf14) or subclass device
09061c
(erasepage optimisation, First/Last page etc).
09061c
09061c
In certain circumstances (for example during a setpagedevice) we want to be
09061c
sure we're retrieving the *actual* output/page device.
09061c
09061c
The new .currentoutputdevice operator uses the spec_op device method to traverse
09061c
any chain of devices and retrieve the final device in the chain, which
09061c
should always be the output/page device.
09061c
09061c
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=7c3e7eee829cc3d2582e4aa7ae1fd495ca72cef1
09061c
09061c
From: Ken Sharp <ken.sharp@artifex.com>
09061c
Date: Mon, 19 Nov 2018 09:00:54 +0000 (+0000)
09061c
Subject: Coverity ID 327264 - move pointer NULL check
09061c
09061c
Coverity ID 327264 - move pointer NULL check
09061c
09061c
Due to recent changes in this code, the pointer was being dereferenced
09061c
before we checked it to see if it was NULL. Moe the check so that we
09061c
check for NULL before dereferencing.
09061c
09061c
The 'pvalue' of the operand can be NULL, even if the object is a t_device
09061c
type, because invalidate_stack_devices traverses the operand stack
09061c
looking for devices, and sets their pvalue member to NULL in order to
09061c
invalidate them so that they cannot be used.
09061c
09061c
https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a4228a0d8d657fca3bb3becb93a43fae061beae8
09061c
---
09061c
09061c
diff -up ghostscript-9.07/base/gdevdflt.c.cve-2018-19409 ghostscript-9.07/base/gdevdflt.c
09061c
--- ghostscript-9.07/base/gdevdflt.c.cve-2018-19409	2013-02-14 08:58:13.000000000 +0100
09061c
+++ ghostscript-9.07/base/gdevdflt.c	2018-11-29 12:42:59.882160045 +0100
09061c
@@ -954,6 +954,11 @@ gx_default_dev_spec_op(gx_device *pdev,
09061c
                 return 4;
09061c
             }
09061c
             return 0; /* Otherwise no change */
09061c
+        case gxdso_current_output_device:
09061c
+            {
09061c
+                *(gx_device **)data = pdev;
09061c
+                return 0;
09061c
+            }
09061c
     }
09061c
     return gs_error_undefined;
09061c
 }
09061c
diff -up ghostscript-9.07/base/gdevp14.c.cve-2018-19409 ghostscript-9.07/base/gdevp14.c
09061c
--- ghostscript-9.07/base/gdevp14.c.cve-2018-19409	2018-11-29 12:42:59.784161429 +0100
09061c
+++ ghostscript-9.07/base/gdevp14.c	2018-11-29 13:15:49.265339432 +0100
09061c
@@ -5089,6 +5089,11 @@ pdf14_dev_spec_op(gx_device *pdev, int d
09061c
             return 0;
09061c
         }
09061c
     }
09061c
+    if (dev_spec_op == gxdso_current_output_device) {
09061c
+         gx_device * target = ((gx_device_forward *)pdev)->target;
09061c
+         return dev_proc(target, dev_spec_op)(target, dev_spec_op, data, size);
09061c
+    }
09061c
+
09061c
     return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
09061c
 }
09061c
 
09061c
diff -up ghostscript-9.07/base/gxdevsop.h.cve-2018-19409 ghostscript-9.07/base/gxdevsop.h
09061c
--- ghostscript-9.07/base/gxdevsop.h.cve-2018-19409	2013-02-14 08:58:13.000000000 +0100
09061c
+++ ghostscript-9.07/base/gxdevsop.h	2018-11-29 12:42:59.884160017 +0100
09061c
@@ -253,6 +253,10 @@ enum {
09061c
      * Return 0 for 'no special treatment', or 1 for the anitdropout
09061c
      * downscaler. */
09061c
     gxdso_interpolate_antidropout,
09061c
+    /* Retrieve the last device in a device chain
09061c
+       (either forwarding or subclass devices).
09061c
+     */
09061c
+    gxdso_current_output_device,
09061c
     /* Add new gxdso_ keys above this. */
09061c
     gxdso_pattern__LAST
09061c
 };
09061c
diff -up ghostscript-9.07/psi/zdevice.c.cve-2018-19409 ghostscript-9.07/psi/zdevice.c
09061c
--- ghostscript-9.07/psi/zdevice.c.cve-2018-19409	2013-02-14 08:58:13.000000000 +0100
09061c
+++ ghostscript-9.07/psi/zdevice.c	2018-11-29 12:42:59.884160017 +0100
09061c
@@ -34,6 +34,7 @@
09061c
 #include "gxgetbit.h"
09061c
 #include "store.h"
09061c
 #include "gsicc_manage.h"
09061c
+#include "gxdevsop.h"
09061c
 
09061c
 /* <device> <keep_open> .copydevice2 <newdevice> */
09061c
 static int
09061c
@@ -56,6 +57,7 @@ zcopydevice2(i_ctx_t *i_ctx_p)
09061c
 }
09061c
 
09061c
 /* - currentdevice <device> */
09061c
+/* Returns the current device in the graphics state */
09061c
 int
09061c
 zcurrentdevice(i_ctx_t *i_ctx_p)
09061c
 {
09061c
@@ -70,6 +72,34 @@ zcurrentdevice(i_ctx_t *i_ctx_p)
09061c
     return 0;
09061c
 }
09061c
 
09061c
+/* - .currentoutputdevice <device> */
09061c
+/* Returns the *output* device - which will often
09061c
+   be the same as above, but not always: if a compositor
09061c
+   or other forwarding device, or subclassing device is
09061c
+   in force, that will be referenced by the graphics state
09061c
+   rather than the output device.
09061c
+   This is equivalent of currentdevice device, but returns
09061c
+   the *device* object, rather than the dictionary describing
09061c
+   the device and device state.
09061c
+ */
09061c
+static int
09061c
+zcurrentoutputdevice(i_ctx_t *i_ctx_p)
09061c
+{
09061c
+    os_ptr op = osp;
09061c
+    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
09061c
+    gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
09061c
+    int code = dev_proc(dev, dev_spec_op)(dev,
09061c
+                        gxdso_current_output_device, (void *)&odev, 0);
09061c
+    if (code < 0)
09061c
+        return code;
09061c
+
09061c
+    push(1);
09061c
+    make_tav(op, t_device,
09061c
+             (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all,
09061c
+             pdevice, odev);
09061c
+    return 0;
09061c
+}
09061c
+
09061c
 /* <device> .devicename <string> */
09061c
 static int
09061c
 zdevicename(i_ctx_t *i_ctx_p)
09061c
@@ -450,13 +480,34 @@ zputdeviceparams(i_ctx_t *i_ctx_p)
09061c
 int
09061c
 zsetdevice(i_ctx_t *i_ctx_p)
09061c
 {
09061c
-    gx_device *dev = gs_currentdevice(igs);
09061c
+    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
09061c
+    gx_device *ndev = NULL;
09061c
     os_ptr op = osp;
09061c
-    int code = 0;
09061c
+    int code = dev_proc(dev, dev_spec_op)(dev,
09061c
+                        gxdso_current_output_device, (void *)&odev, 0);
09061c
 
09061c
+    if (code < 0)
09061c
+        return code;
09061c
     check_write_type(*op, t_device);
09061c
-    if (dev->LockSafetyParams) {	  /* do additional checking if locked  */
09061c
-        if(op->value.pdevice != dev) 	  /* don't allow a different device    */
09061c
+
09061c
+    if (op->value.pdevice == 0)
09061c
+        return gs_note_error(gs_error_undefined);
09061c
+
09061c
+    /* slightly icky special case: the new device may not have had
09061c
+     * it's procs initialised, at this point - but we need to check
09061c
+     * whether we're being asked to change the device here
09061c
+     */
09061c
+    if (dev_proc((op->value.pdevice), dev_spec_op) == NULL)
09061c
+        ndev = op->value.pdevice;
09061c
+    else
09061c
+        code = dev_proc((op->value.pdevice), dev_spec_op)(op->value.pdevice,
09061c
+                        gxdso_current_output_device, (void *)&ndev, 0);
09061c
+
09061c
+    if (code < 0)
09061c
+        return code;
09061c
+
09061c
+    if (odev->LockSafetyParams) {        /* do additional checking if locked  */
09061c
+        if(ndev != odev)         /* don't allow a different device    */
09061c
             return_error(e_invalidaccess);
09061c
     }
09061c
 #ifndef PSI_INCLUDED
09061c
@@ -480,6 +531,7 @@ const op_def zdevice_op_defs[] =
09061c
 {
09061c
     {"1.copydevice2", zcopydevice2},
09061c
     {"0currentdevice", zcurrentdevice},
09061c
+    {"0.currentoutputdevice", zcurrentoutputdevice},
09061c
     {"1.devicename", zdevicename},
09061c
     {"0.doneshowpage", zdoneshowpage},
09061c
     {"0flushpage", zflushpage},
09061c
diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-19409 ghostscript-9.07/Resource/Init/gs_init.ps
09061c
--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-19409	2018-11-29 12:42:59.873160172 +0100
09061c
+++ ghostscript-9.07/Resource/Init/gs_init.ps	2018-11-29 12:42:59.884160017 +0100
09061c
@@ -2160,7 +2160,7 @@ SAFER { .setsafe } if
09061c
 /.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring
09061c
 /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile
09061c
 /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams
09061c
-/.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath
09061c
+/.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice
09061c
 
09061c
 % Used by a free user in the Library of Congress. Apparently this is used to
09061c
 % draw a partial page, which is then filled in by the results of a barcode
09061c
diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-19409 ghostscript-9.07/Resource/Init/gs_setpd.ps
09061c
--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-19409	2018-11-29 12:42:59.880160073 +0100
09061c
+++ ghostscript-9.07/Resource/Init/gs_setpd.ps	2018-11-29 12:42:59.885160002 +0100
09061c
@@ -772,7 +772,13 @@ SETPDDEBUG { (Selecting.) = pstack flush
09061c
                 % Stack: mark <orig> <request> <merged> <failed>
09061c
 SETPDDEBUG { (Constructing.) = pstack flush } if
09061c
 
09061c
-   currentdevice .devicename 2 index /OutputDevice get eq
09061c
+   % Non-obvious: we need to check the name of the output device, to tell
09061c
+   % whether we're going to have to replace the entire device chain (which
09061c
+   % may be only one device, or may be multiple devices.
09061c
+   % If we're not replacing the entire change, we have to use the device in
09061c
+   % the graphics state, so the configuration of the entire device chain is
09061c
+   % correctly set.
09061c
+   .currentoutputdevice .devicename 2 index /OutputDevice get eq
09061c
     { currentdevice }
09061c
     { 1 index /OutputDevice get finddevice }
09061c
    ifelse