summaryrefslogtreecommitdiff
path: root/app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch
diff options
context:
space:
mode:
Diffstat (limited to 'app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch')
-rw-r--r--app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch231
1 files changed, 231 insertions, 0 deletions
diff --git a/app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch b/app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch
new file mode 100644
index 00000000..a5f22d1b
--- /dev/null
+++ b/app-text/ghostscript-gpl/files/VU332928-githash5516c614.patch
@@ -0,0 +1,231 @@
+From: Chris Liddell <chris.liddell@artifex.com>
+Date: Fri, 24 Aug 2018 08:26:04 +0000 (+0100)
+Subject: Improve restore robustness
+X-Git-Tag: ghostpdl-9.24rc1~10
+X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=5516c614
+
+Improve restore robustness
+
+Prompted by looking at Bug 699654:
+
+There are two variants of the restore operator in Ghostscript: one is Level 1
+(restoring VM), the other is Level 2+ (adding page device restoring to the
+Level operator).
+
+This was implemented by the Level 2+ version restoring the device in the
+graphics state, then calling the Level 1 implementation to handle actually
+restoring the VM state.
+
+The problem was that the operand checking, and sanity of the save object was
+only done by the Level 1 variant, thus meaning an invalid save object could
+leave a (Level 2+) restore partially complete - with the page device part
+restored, but not VM, and the page device not configured.
+
+To solve that, this commit splits the operand and sanity checking, and the
+core of the restore operation into separate functions, so the relevant
+operators can validate the operand *before* taking any further action. That
+reduces the chances of an invalid restore leaving the interpreter in an
+unknown state.
+
+If an error occurs during the actual VM restore it is essentially fatal, and the
+interpreter cannot continue, but as an extra surety for security, in the event
+of such an error, we'll explicitly preserve the LockSafetyParams of the device,
+rather than rely on the post-restore device configuration (which won't happen
+in the event of an error).
+---
+
+diff --git a/psi/int.mak b/psi/int.mak
+index 1968820..16db0cf 100644
+--- a/psi/int.mak
++++ b/psi/int.mak
+@@ -1086,8 +1086,8 @@ $(PSD)pagedev.dev : $(ECHOGS_XE) $(pagedev_)\
+
+ $(PSOBJ)zdevice2.$(OBJ) : $(PSSRC)zdevice2.c $(OP) $(math__h) $(memory__h)\
+ $(dstack_h) $(estack_h)\
+- $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(iutil_h) $(store_h)\
+- $(gxdevice_h) $(gsstate_h) $(INT_MAK) $(MAKEDIRS)
++ $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(isave) $(iutil_h) \
++ $(store_h) $(gxdevice_h) $(gsstate_h) $(INT_MAK) $(MAKEDIRS)
+ $(PSCC) $(PSO_)zdevice2.$(OBJ) $(C_) $(PSSRC)zdevice2.c
+
+ $(PSOBJ)zmedia2.$(OBJ) : $(PSSRC)zmedia2.c $(OP) $(math__h) $(memory__h)\
+diff --git a/psi/isave.h b/psi/isave.h
+index 3021639..7eaaced 100644
+--- a/psi/isave.h
++++ b/psi/isave.h
+@@ -128,4 +128,10 @@ int font_restore(const alloc_save_t * save);
+ express purpose of getting the library context. */
+ gs_memory_t *gs_save_any_memory(const alloc_save_t *save);
+
++int
++restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave);
++
++int
++dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave);
++
+ #endif /* isave_INCLUDED */
+diff --git a/psi/zdevice2.c b/psi/zdevice2.c
+index 9fbb4e3..0c7080d 100644
+--- a/psi/zdevice2.c
++++ b/psi/zdevice2.c
+@@ -26,6 +26,7 @@
+ #include "igstate.h"
+ #include "iname.h"
+ #include "iutil.h"
++#include "isave.h"
+ #include "store.h"
+ #include "gxdevice.h"
+ #include "gsstate.h"
+@@ -307,13 +308,24 @@ z2grestoreall(i_ctx_t *i_ctx_p)
+ }
+ return 0;
+ }
+-
++/* This is the Level 2+ variant of restore - which adds restoring
++ of the page device to the Level 1 variant in zvmem.c.
++ Previous this restored the device state before calling zrestore.c
++ which validated operands etc, meaning a restore could error out
++ partially complete.
++ The operand checking, and actual VM restore are now in two functions
++ so they can called separately thus, here, we can do as much
++ checking as possible, before embarking on actual changes
++ */
+ /* <save> restore - */
+ static int
+ z2restore(i_ctx_t *i_ctx_p)
+ {
+- os_ptr op = osp;
+- check_type(*op, t_save);
++ alloc_save_t *asave;
++ bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams;
++ int code = restore_check_save(i_ctx_p, &asave);
++
++ if (code < 0) return code;
+
+ while (gs_gstate_saved(gs_gstate_saved(igs))) {
+ if (restore_page_device(igs, gs_gstate_saved(igs)))
+@@ -322,7 +334,20 @@ z2restore(i_ctx_t *i_ctx_p)
+ }
+ if (restore_page_device(igs, gs_gstate_saved(igs)))
+ return push_callout(i_ctx_p, "%restorepagedevice");
+- return zrestore(i_ctx_p);
++
++ code = dorestore(i_ctx_p, asave);
++
++ if (code < 0) {
++ /* An error here is basically fatal, but....
++ restore_page_device() has to set LockSafetyParams false so it can
++ configure the restored device correctly - in normal operation, that
++ gets reset by that configuration. If we hit an error, though, that
++ may not happen - at least ensure we keep the setting through the
++ error.
++ */
++ gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety;
++ }
++ return code;
+ }
+
+ /* <gstate> setgstate - */
+diff --git a/psi/zvmem.c b/psi/zvmem.c
+index 44cd7a8..87a0a4f 100644
+--- a/psi/zvmem.c
++++ b/psi/zvmem.c
+@@ -99,19 +99,18 @@ zsave(i_ctx_t *i_ctx_p)
+ static int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *);
+ static int restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t *, const alloc_save_t *, bool);
+ static void restore_fix_stack(i_ctx_t *i_ctx_p, ref_stack_t *, const alloc_save_t *, bool);
++
++/* Do as many up front checks of the save object as we reasonably can */
+ int
+-zrestore(i_ctx_t *i_ctx_p)
++restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave)
+ {
+ os_ptr op = osp;
+- alloc_save_t *asave;
+- bool last;
+- vm_save_t *vmsave;
+- int code = restore_check_operand(op, &asave, idmemory);
++ int code = restore_check_operand(op, asave, idmemory);
+
+ if (code < 0)
+ return code;
+ if_debug2m('u', imemory, "[u]vmrestore 0x%lx, id = %lu\n",
+- (ulong) alloc_save_client_data(asave),
++ (ulong) alloc_save_client_data(*asave),
+ (ulong) op->value.saveid);
+ if (I_VALIDATE_BEFORE_RESTORE)
+ ivalidate_clean_spaces(i_ctx_p);
+@@ -120,14 +119,37 @@ zrestore(i_ctx_t *i_ctx_p)
+ {
+ int code;
+
+- if ((code = restore_check_stack(i_ctx_p, &o_stack, asave, false)) < 0 ||
+- (code = restore_check_stack(i_ctx_p, &e_stack, asave, true)) < 0 ||
+- (code = restore_check_stack(i_ctx_p, &d_stack, asave, false)) < 0
++ if ((code = restore_check_stack(i_ctx_p, &o_stack, *asave, false)) < 0 ||
++ (code = restore_check_stack(i_ctx_p, &e_stack, *asave, true)) < 0 ||
++ (code = restore_check_stack(i_ctx_p, &d_stack, *asave, false)) < 0
+ ) {
+ osp++;
+ return code;
+ }
+ }
++ osp++;
++ return 0;
++}
++
++/* the semantics of restore differ slightly between Level 1 and
++ Level 2 and later - the latter includes restoring the device
++ state (whilst Level 1 didn't have "page devices" as such).
++ Hence we have two restore operators - one here (Level 1)
++ and one in zdevice2.c (Level 2+). For that reason, the
++ operand checking and guts of the restore operation are
++ separated so both implementations can use them to best
++ effect.
++ */
++int
++dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave)
++{
++ os_ptr op = osp;
++ bool last;
++ vm_save_t *vmsave;
++ int code;
++
++ osp--;
++
+ /* Reset l_new in all stack entries if the new save level is zero. */
+ /* Also do some special fixing on the e-stack. */
+ restore_fix_stack(i_ctx_p, &o_stack, asave, false);
+@@ -170,9 +192,24 @@ zrestore(i_ctx_t *i_ctx_p)
+ /* cause an 'invalidaccess' in setuserparams. Temporarily set */
+ /* LockFilePermissions false until the gs_lev2.ps can do a */
+ /* setuserparams from the restored userparam dictionary. */
++ /* NOTE: This is safe to do here, since the restore has */
++ /* successfully completed - this should never come before any */
++ /* operation that can trigger an error */
+ i_ctx_p->LockFilePermissions = false;
+ return 0;
+ }
++
++int
++zrestore(i_ctx_t *i_ctx_p)
++{
++ alloc_save_t *asave;
++ int code = restore_check_save(i_ctx_p, &asave);
++ if (code < 0)
++ return code;
++
++ return dorestore(i_ctx_p, asave);
++}
++
+ /* Check the operand of a restore. */
+ static int
+ restore_check_operand(os_ptr op, alloc_save_t ** pasave,
+@@ -193,6 +230,7 @@ restore_check_operand(os_ptr op, alloc_save_t ** pasave,
+ *pasave = asave;
+ return 0;
+ }
++
+ /* Check a stack to make sure all its elements are older than a save. */
+ static int
+ restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t * pstack,