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

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