[notify] ghostscript: security fix, several -dSAFER sandbox bypass vulnerabilities

See
- https://www.kb.cert.org/vuls/id/332928
- http://seclists.org/oss-sec/2018/q3/142
This commit is contained in:
Juergen Daubert 2018-08-25 20:05:46 +02:00
parent 4e5e21dbb0
commit 11f86218d2
15 changed files with 837 additions and 4 deletions

View File

@ -1,6 +1,19 @@
untrusted comment: verify with /etc/ports/opt.pub untrusted comment: verify with /etc/ports/opt.pub
RWSE3ohX2g5d/fAfjoz0I76mLUiRieNsO8V6jhq5EVQ6xW14I/nmfV+aCRN4GXNPzuibAVddAgeDFQHT67ET7EstLrX9oiWLqgg= RWSE3ohX2g5d/froAVb0xfR6peImTLVw25laSQoDWaxYCxl8iIc3+eGFpv01RYYqliddT0nIm31YTdVwZS/RF2l9f/HkZo2LKg4=
SHA256 (Pkgfile) = bf1af24031803ccccd487cd7dfed24ead00597c00daef0f3c1698ee0b5d46f71 SHA256 (Pkgfile) = e4a88a0f36aec4197fc95a307812e31bd329eb53d64dbf81825cfa65fa09b778
SHA256 (.footprint) = 3514d4810f8fe93de5e8d03bc500e39d81dc6ab4118d0728c50d1e50e3bbc606 SHA256 (.footprint) = 3514d4810f8fe93de5e8d03bc500e39d81dc6ab4118d0728c50d1e50e3bbc606
SHA256 (ghostscript-9.23.tar.xz) = 1fcedc27d4d6081105cdf35606cb3f809523423a6cf9e3c23cead3525d6ae8d9 SHA256 (ghostscript-9.23.tar.xz) = 1fcedc27d4d6081105cdf35606cb3f809523423a6cf9e3c23cead3525d6ae8d9
SHA256 (ghostscript-fonts-std-8.11.tar.gz) = 0eb6f356119f2e49b2563210852e17f57f9dcc5755f350a69a46a0d641a0c401 SHA256 (ghostscript-fonts-std-8.11.tar.gz) = 0eb6f356119f2e49b2563210852e17f57f9dcc5755f350a69a46a0d641a0c401
SHA256 (ghostpdl.git-0b6cd191.patch) = 562502dd1eccce30010aa2f00805132dfef86aa3675fb1df6fd00cbca8a4d786
SHA256 (ghostpdl.git-b575e1ec.patch) = 09bf11a0dd2ca575df16e8d08ef64f7d195f8be9fe050026b5ce5d27cfcd8af9
SHA256 (ghostpdl.git-8e9ce501.patch) = dc73b4592a862bbab7d8a4d326503d802ba4266940574ad2d73a444c977953f9
SHA256 (ghostpdl.git-241d9111.patch) = 7f6fc634cf228c12b12c93514c419d7d6f7daad49fcd86baa23a7ff3b7fb55a4
SHA256 (ghostpdl.git-c432131c.patch) = 12122123e1df839d39f844223a24e76a18ea0aab05cfa0012f7b2590792ca8ea
SHA256 (ghostpdl.git-e01e77a3.patch) = 4061b542ad640298caa595c02bcc3b095e6f5682996c4b7330c6a36c04f19a94
SHA256 (ghostpdl.git-0edd3d6c.patch) = 90be1bd4374d2af5b4675275030b7c528a3a03dfb0c4980337c5eec920326d4b
SHA256 (ghostpdl.git-a054156d.patch) = 0f9b55466f45b404a4ccb9fcb18e203762eb06aa5c1b95bc7a2c8480601952c3
SHA256 (ghostpdl.git-0d390118.patch) = 7ea332e7b2059c1f094f94714bc6b4eaf0de2515ae70b469ecfe96e7ccaf7317
SHA256 (ghostpdl.git-c3476dde.patch) = 4ed94469231187ce2a512b4784f6fc7238543cf39b2625e2c09357fefed8aa18
SHA256 (ghostpdl.git-b326a716.patch) = 6529a57c842e9a1573826bc6553956303297b7723c14f2bfcaeb1d899ec65c26
SHA256 (ghostpdl.git-78911a01.patch) = 128065c4120cebcc9f177ce9ca2a525e240fd97a07727767210880080e87f507
SHA256 (ghostpdl.git-5516c614.patch) = 125d5ffd5e891aa42aecb44025126130d014c8e8e98feca0fb6aab17cfe7908c

View File

@ -5,13 +5,40 @@
name=ghostscript name=ghostscript
version=9.23 version=9.23
release=1 release=2
source=(https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs${version/./}/$name-$version.tar.xz source=(https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs${version/./}/$name-$version.tar.xz
http://downloads.sourceforge.net/sourceforge/gs-fonts/$name-fonts-std-8.11.tar.gz) http://downloads.sourceforge.net/sourceforge/gs-fonts/$name-fonts-std-8.11.tar.gz
ghostpdl.git-0b6cd191.patch
ghostpdl.git-b575e1ec.patch
ghostpdl.git-8e9ce501.patch
ghostpdl.git-241d9111.patch
ghostpdl.git-c432131c.patch
ghostpdl.git-e01e77a3.patch
ghostpdl.git-0edd3d6c.patch
ghostpdl.git-a054156d.patch
ghostpdl.git-0d390118.patch
ghostpdl.git-c3476dde.patch
ghostpdl.git-b326a716.patch
ghostpdl.git-78911a01.patch
ghostpdl.git-5516c614.patch)
build () { build () {
cd $name-$version cd $name-$version
patch -p1 -i $SRC/ghostpdl.git-0b6cd191.patch
patch -p1 -i $SRC/ghostpdl.git-b575e1ec.patch
patch -p1 -i $SRC/ghostpdl.git-8e9ce501.patch
patch -p1 -i $SRC/ghostpdl.git-241d9111.patch
patch -p1 -i $SRC/ghostpdl.git-c432131c.patch
patch -p1 -i $SRC/ghostpdl.git-e01e77a3.patch
patch -p1 -i $SRC/ghostpdl.git-0edd3d6c.patch
patch -p1 -i $SRC/ghostpdl.git-a054156d.patch
patch -p1 -i $SRC/ghostpdl.git-0d390118.patch
patch -p1 -i $SRC/ghostpdl.git-c3476dde.patch
patch -p1 -i $SRC/ghostpdl.git-b326a716.patch
patch -p1 -i $SRC/ghostpdl.git-78911a01.patch
patch -p1 -i $SRC/ghostpdl.git-5516c614.patch
./configure --prefix=/usr \ ./configure --prefix=/usr \
--enable-cups \ --enable-cups \
--disable-gtk \ --disable-gtk \

View File

@ -0,0 +1,86 @@
From 0b6cd1918e1ec4ffd087400a754a845180a4522b Mon Sep 17 00:00:00 2001
From: Ken Sharp <ken.sharp@artifex.com>
Date: Thu, 23 Aug 2018 14:12:48 +0100
Subject: [PATCH] Fix Bug 699660 "shading_param incomplete type checking"
Its possible to pass a t_struct parameter to .shfill which is not a
shading function built by .buildshading. This could then lead to memory
corruption or a segmentation fault by treating the object passed in
as if it were a shading.
Its non-trivial to check the t_struct, because this function can take
7 different kinds of structures as a parameter. Checking these is
possible, of course, but would add a performance penalty.
However, we can note that we never call .shfill without first calling
.buildshading, and we never call .buildshading without immediately
calling .shfill. So we can treat these as an atomic operation. The
.buildshading function takes all its parameters as PostScript objects
and validates them, so that should be safe.
This allows us to 'hide' the .shfill operator preventing the possibility
of passing an invalid parameter.
---
Resource/Init/gs_init.ps | 4 ++--
Resource/Init/gs_ll3.ps | 7 ++++++-
Resource/Init/pdf_draw.ps | 3 +--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index 5a5a428..bc17d42 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -2196,8 +2196,8 @@ SAFER { .setsafeglobal } if
/.getiodevice /.getdevparms /.putdevparams /.bbox_transform /.matchmedia /.matchpagesize /.defaultpapersize
/.oserrno /.setoserrno /.oserrorstring /.getCPSImode
/.getscanconverter /.setscanconverter /.type1encrypt /.type1decrypt/.languagelevel /.setlanguagelevel /.eqproc /.fillpage /.buildpattern1 /.saslprep
-/.buildshading1 /.buildshadin2 /.buildshading3 /.buildshading4 /.buildshading5 /.buildshading6 /.buildshading7 /.buildshadingpattern
-/.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring
+/.buildshading1 /.buildshading2 /.buildshading3 /.buildshading4 /.buildshading5 /.buildshading6 /.buildshading7 /.buildshadingpattern
+%/.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring
/.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile
/.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams
/.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath
diff --git a/Resource/Init/gs_ll3.ps b/Resource/Init/gs_ll3.ps
index 5aa56a3..1d37e53 100644
--- a/Resource/Init/gs_ll3.ps
+++ b/Resource/Init/gs_ll3.ps
@@ -440,6 +440,11 @@ systemdict /.reuseparamdict mark
/shfill .systemvar /undefined signalerror
} ifelse
} bind def
+
+/.buildshading_and_shfill {
+ .buildshading .shfill
+} bind def
+
systemdict /.reuseparamdict undef
/.buildpattern2 { % <template> <matrix> .buildpattern2
@@ -464,7 +469,7 @@ systemdict /.reuseparamdict undef
% Currently, .shfill requires that the color space
% in the pattern be the current color space.
% Disable overprintmode for shfill
- { dup gsave 0 .setoverprintmode .buildshading .shfill } stopped
+ { dup gsave 0 .setoverprintmode .buildshading_and_shfill } stopped
grestore {
/$error .systemvar /errorinfo 2 copy known {
pop pop
diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps
index b3d94ac..aef249d 100644
--- a/Resource/Init/pdf_draw.ps
+++ b/Resource/Init/pdf_draw.ps
@@ -1365,9 +1365,8 @@ drawopdict begin
{ dup /.shading .knownget {
exch pop
} {
- .buildshading
+ .buildshading_and_shfill
} ifelse
- .shfill
} stopped {
pop
( **** Error: Ignoring invalid smooth shading object, output may be incorrect.\n)
--
2.9.1

View File

@ -0,0 +1,46 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 21 Aug 2018 19:17:05 +0000 (+0100)
Subject: Bug 699657: properly apply file permissions to .tempfile
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=0d390118
Bug 699657: properly apply file permissions to .tempfile
---
diff --git a/psi/zfile.c b/psi/zfile.c
index a0acd5a..19996b0 100644
--- a/psi/zfile.c
+++ b/psi/zfile.c
@@ -134,7 +134,7 @@ check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
/* we're protecting arbitrary file system accesses, not Postscript device accesses.
* Although, note that %pipe% is explicitly checked for and disallowed elsewhere
*/
- if (iodev != iodev_default(imemory)) {
+ if (iodev && iodev != iodev_default(imemory)) {
return 0;
}
@@ -734,7 +734,23 @@ ztempfile(i_ctx_t *i_ctx_p)
}
if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
- if (check_file_permissions(i_ctx_p, pstr, strlen(pstr),
+ int plen = strlen(pstr);
+ const char *sep = gp_file_name_separator();
+#ifdef DEBUG
+ int seplen = strlen(sep);
+ if (seplen != 1)
+ return_error(gs_error_Fatal);
+#endif
+ /* strip off the file name prefix, leave just the directory name
+ * so we can check if we are allowed to write to it
+ */
+ for ( ; plen >=0; plen--) {
+ if (pstr[plen] == sep[0])
+ break;
+ }
+ memcpy(fname, pstr, plen);
+ fname[plen] = '\0';
+ if (check_file_permissions(i_ctx_p, fname, strlen(fname),
NULL, "PermitFileWriting") < 0) {
code = gs_note_error(gs_error_invalidfileaccess);
goto done;

View File

@ -0,0 +1,21 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 21 Aug 2018 19:36:52 +0000 (+0100)
Subject: Bug 699659: Don't just assume an object is a t_(a)struct
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=0edd3d6c
Bug 699659: Don't just assume an object is a t_(a)struct
---
diff --git a/psi/ztype.c b/psi/ztype.c
index ad248d9..8307956 100644
--- a/psi/ztype.c
+++ b/psi/ztype.c
@@ -76,7 +76,7 @@ ztype(i_ctx_t *i_ctx_p)
/* Must be either a stack underflow or a t_[a]struct. */
check_op(2);
{ /* Get the type name from the structure. */
- if (op[-1].value.pstruct != 0x00) {
+ if ((r_has_type(&op[-1], t_struct) || r_has_type(&op[-1], t_astruct)) && op[-1].value.pstruct != 0x00) {
const char *sname =
gs_struct_type_name_string(gs_object_type(imemory,
op[-1].value.pstruct));

View File

@ -0,0 +1,43 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 23 Aug 2018 14:41:18 +0000 (+0100)
Subject: Bug 699664: Ensure the correct is in place before cleanup
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=241d9111
Bug 699664: Ensure the correct is in place before cleanup
If the PS job replaces the device and leaves that graphics state in place, we
wouldn't cleanup the default device in the normal way, but rely on the garbage
collector.
This works (but isn't ideal), *except* when the job replaces the device with
the null device (using the nulldevice operator) - this means that
.uninstallpagedevice doesn't replace the existing device with the nulldevice
(since it is already installed), the device from the graphics ends up being
freed - and as it is the nulldevice, which we rely on, memory corruption
and a segfault can happen.
We avoid this by checking if the current device is the nulldevice, and if so,
restoring it away, before continuing with the device cleanup.
---
diff --git a/psi/imain.c b/psi/imain.c
index 2fe1546..138bfc8 100644
--- a/psi/imain.c
+++ b/psi/imain.c
@@ -936,6 +936,16 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
}
+ if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL &&
+ gx_device_is_null(i_ctx_p->pgs->device)) {
+ /* if the job replaced the device with the nulldevice, we we need to grestore
+ away that device, so the block below can properly dispense
+ with the default device.
+ */
+ int code = gs_grestoreall(i_ctx_p->pgs);
+ if (code < 0) return_error(gs_error_Fatal);
+ }
+
if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
gx_device *pdev = i_ctx_p->pgs->device;
const char * dname = pdev->dname;

View File

@ -0,0 +1,230 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Fri, 24 Aug 2018 08:26:04 +0000 (+0100)
Subject: Improve restore robustness
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,

View File

@ -0,0 +1,30 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 23 Aug 2018 08:54:59 +0000 (+0100)
Subject: Bug 699654: Check the restore operand type
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=78911a01
Bug 699654: Check the restore operand type
The primary function that implements restore correctly checked its parameter,
but a function that does some preliminary work for the restore (gstate and
device handling) did not check.
So, even though the restore correctly errored out, it left things partially done
and, in particular, the device in partially restored state. Meaning the
LockSafetyParams was not correctly set.
---
diff --git a/psi/zdevice2.c b/psi/zdevice2.c
index de16dd2..9fbb4e3 100644
--- a/psi/zdevice2.c
+++ b/psi/zdevice2.c
@@ -312,6 +312,9 @@ z2grestoreall(i_ctx_t *i_ctx_p)
static int
z2restore(i_ctx_t *i_ctx_p)
{
+ os_ptr op = osp;
+ check_type(*op, t_save);
+
while (gs_gstate_saved(gs_gstate_saved(igs))) {
if (restore_page_device(igs, gs_gstate_saved(igs)))
return push_callout(i_ctx_p, "%restore1pagedevice");

View File

@ -0,0 +1,48 @@
From: Ken Sharp <ken.sharp@artifex.com>
Date: Thu, 23 Aug 2018 14:42:02 +0000 (+0100)
Subject: Bug 699665 "memory corruption in aesdecode"
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=8e9ce501
Bug 699665 "memory corruption in aesdecode"
The specimen file calls aesdecode without specifying the key to be
used, though it does manage to do enough work with the PDF interpreter
routines to get access to aesdecode (which isn't normally available).
This causes us to read uninitialised memory, which can (and often does)
lead to a segmentation fault.
In this commit we set the key to NULL explicitly during intialisation
and then check it before we read it. If its NULL we just return.
It seems bizarre that we don't return error codes, we should probably
look into that at some point, but this prevents the code trying to
read uninitialised memory.
---
diff --git a/base/aes.c b/base/aes.c
index a6bce93..e86f000 100644
--- a/base/aes.c
+++ b/base/aes.c
@@ -662,6 +662,9 @@ void aes_crypt_ecb( aes_context *ctx,
}
#endif
+ if (ctx == NULL || ctx->rk == NULL)
+ return;
+
RK = ctx->rk;
GET_ULONG_LE( X0, input, 0 ); X0 ^= *RK++;
diff --git a/base/saes.c b/base/saes.c
index 6db0e8b..307ed74 100644
--- a/base/saes.c
+++ b/base/saes.c
@@ -120,6 +120,7 @@ s_aes_process(stream_state * ss, stream_cursor_read * pr,
gs_throw(gs_error_VMerror, "could not allocate aes context");
return ERRC;
}
+ memset(state->ctx, 0x00, sizeof(aes_context));
if (state->keylength < 1 || state->keylength > SAES_MAX_KEYLENGTH) {
gs_throw1(gs_error_rangecheck, "invalid aes key length (%d bytes)",
state->keylength);

View File

@ -0,0 +1,51 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 21 Aug 2018 19:17:51 +0000 (+0100)
Subject: Bug 699658: Fix handling of pre-SAFER opened files.
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=a054156d
Bug 699658: Fix handling of pre-SAFER opened files.
Temp files opened for writing before SAFER is engaged are not subject to the
SAFER restrictions - that is handled by recording in a dictionary, and
checking that as part of the permissions checks.
By adding a custom error handler for invalidaccess, that allowed the filename
to be added to the dictionary (despite the attempted open throwing the error)
thus meaning subsequent accesses were erroneously permitted.
---
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index a6e49f0..5a5a428 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -2036,6 +2036,19 @@ readonly def
concatstrings concatstrings .generate_dir_list_templates
} if
]
+ /PermitFileWriting [
+ currentuserparams /PermitFileWriting get aload pop
+ (TMPDIR) getenv not
+ {
+ (TEMP) getenv not
+ {
+ (TMP) getenv not
+ {
+ (/temp) (/tmp)
+ } if
+ } if
+ } if
+ ]
/LockFilePermissions //true
>> setuserparams
}
@@ -2122,7 +2135,9 @@ readonly def
% the file can be deleted later, even if SAFER is set.
/.tempfile {
.tempfile % filename file
- //SAFETY /tempfiles get 2 .argindex //true .forceput
+ //SAFETY /safe get not { % only add the filename if we're not yet safe
+ //SAFETY /tempfiles get 2 .argindex //true .forceput
+ } if
} .bind executeonly odef
% If we are running in SAFER mode, lock things down

View File

@ -0,0 +1,26 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 21 Aug 2018 15:24:05 +0000 (+0100)
Subject: Bug 699655: Properly check the return value....
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=b326a716
Bug 699655: Properly check the return value....
...when getting a value from a dictionary
---
diff --git a/psi/zcolor.c b/psi/zcolor.c
index 4c0f258..e27baf9 100644
--- a/psi/zcolor.c
+++ b/psi/zcolor.c
@@ -283,8 +283,9 @@ zsetcolor(i_ctx_t * i_ctx_p)
if (r_has_type(op, t_dictionary)) {
ref *pImpl, pPatInst;
- code = dict_find_string(op, "Implementation", &pImpl);
- if (code != 0) {
+ if ((code = dict_find_string(op, "Implementation", &pImpl)) < 0)
+ return code;
+ if (code > 0) {
code = array_get(imemory, pImpl, 0, &pPatInst);
if (code < 0)
return code;

View File

@ -0,0 +1,33 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 23 Aug 2018 11:20:56 +0000 (+0100)
Subject: Bug 699668: handle stack overflow during error handling
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=b575e1ec
Bug 699668: handle stack overflow during error handling
When handling a Postscript error, we push the object throwing the error onto
the operand stack for the error handling procedure to access - we were not
checking the available stack before doing so, thus causing a crash.
Basically, if we get a stack overflow when already handling an error, we're out
of options, return to the caller with a fatal error.
---
diff --git a/psi/interp.c b/psi/interp.c
index 8b49556..6150838 100644
--- a/psi/interp.c
+++ b/psi/interp.c
@@ -676,7 +676,12 @@ again:
/* Push the error object on the operand stack if appropriate. */
if (!GS_ERROR_IS_INTERRUPT(code)) {
/* Replace the error object if within an oparray or .errorexec. */
- *++osp = *perror_object;
+ osp++;
+ if (osp >= ostop) {
+ *pexit_code = gs_error_Fatal;
+ return_error(gs_error_Fatal);
+ }
+ *osp = *perror_object;
errorexec_find(i_ctx_p, osp);
}
goto again;

View File

@ -0,0 +1,43 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 21 Aug 2018 15:42:45 +0000 (+0100)
Subject: Bug 699656: Handle LockDistillerParams not being a boolean
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=c3476dde
Bug 699656: Handle LockDistillerParams not being a boolean
This caused a function call commented as "Can't fail" to fail, and resulted
in memory correuption and a segfault.
---
diff --git a/devices/vector/gdevpdfp.c b/devices/vector/gdevpdfp.c
index e942682..7c58af7 100644
--- a/devices/vector/gdevpdfp.c
+++ b/devices/vector/gdevpdfp.c
@@ -364,7 +364,7 @@ gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_par
* LockDistillerParams is read again, and reset if necessary, in
* psdf_put_params.
*/
- ecode = param_read_bool(plist, "LockDistillerParams", &locked);
+ ecode = param_read_bool(plist, (param_name = "LockDistillerParams"), &locked);
if (ecode < 0)
param_signal_error(plist, param_name, ecode);
diff --git a/psi/iparam.c b/psi/iparam.c
index 68c20d4..0279455 100644
--- a/psi/iparam.c
+++ b/psi/iparam.c
@@ -822,10 +822,11 @@ static int
ref_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
{
iparam_list *const iplist = (iparam_list *) plist;
- iparam_loc loc;
+ iparam_loc loc = {0};
- ref_param_read(iplist, pkey, &loc, -1); /* can't fail */
- *loc.presult = code;
+ ref_param_read(iplist, pkey, &loc, -1);
+ if (loc.presult)
+ *loc.presult = code;
switch (ref_param_read_get_policy(plist, pkey)) {
case gs_param_policy_ignore:
return 0;

View File

@ -0,0 +1,109 @@
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 23 Aug 2018 13:13:25 +0000 (+0100)
Subject: Bug 699661: Avoid sharing pointers between pdf14 compositors
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=c432131c
Bug 699661: Avoid sharing pointers between pdf14 compositors
If a copdevice is triggered when the pdf14 compositor is the device, we make
a copy of the device, then throw an error because, by default we're only allowed
to copy the device prototype - then freeing it calls the finalize, which frees
several pointers shared with the parent.
Make a pdf14 specific finish_copydevice() which NULLs the relevant pointers,
before, possibly, throwing the same error as the default method.
This also highlighted a problem with reopening the X11 devices, where a custom
error handler could be replaced with itself, meaning it also called itself,
and infifite recursion resulted.
Keep a note of if the handler replacement has been done, and don't do it a
second time.
---
diff --git a/base/gdevp14.c b/base/gdevp14.c
index d9f8e79..eb9cc23 100644
--- a/base/gdevp14.c
+++ b/base/gdevp14.c
@@ -178,6 +178,7 @@ static dev_proc_fill_mask(pdf14_fill_mask);
static dev_proc_stroke_path(pdf14_stroke_path);
static dev_proc_begin_typed_image(pdf14_begin_typed_image);
static dev_proc_text_begin(pdf14_text_begin);
+static dev_proc_finish_copydevice(pdf14_finish_copydevice);
static dev_proc_create_compositor(pdf14_create_compositor);
static dev_proc_create_compositor(pdf14_forward_create_compositor);
static dev_proc_begin_transparency_group(pdf14_begin_transparency_group);
@@ -245,7 +246,7 @@ static const gx_color_map_procs *
pdf14_create_compositor, /* create_compositor */\
NULL, /* get_hardware_params */\
pdf14_text_begin, /* text_begin */\
- NULL, /* finish_copydevice */\
+ pdf14_finish_copydevice, /* finish_copydevice */\
pdf14_begin_transparency_group,\
pdf14_end_transparency_group,\
pdf14_begin_transparency_mask,\
@@ -3935,6 +3936,19 @@ pdf14_text_begin(gx_device * dev, gs_gstate * pgs,
return code;
}
+static int
+pdf14_finish_copydevice(gx_device *new_dev, const gx_device *from_dev)
+{
+ pdf14_device *pdev = (pdf14_device*)new_dev;
+
+ pdev->ctx = NULL;
+ pdev->trans_group_parent_cmap_procs = NULL;
+ pdev->smaskcolor = NULL;
+
+ /* Only allow copying the prototype. */
+ return (from_dev->memory ? gs_note_error(gs_error_rangecheck) : 0);
+}
+
/*
* Implement copy_mono by filling lots of small rectangles.
*/
@@ -8093,6 +8107,7 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev,
before reopening the device */
if (p14dev->ctx != NULL) {
pdf14_ctx_free(p14dev->ctx);
+ p14dev->ctx = NULL;
}
dev_proc(tdev, open_device) (tdev);
}
diff --git a/devices/gdevxini.c b/devices/gdevxini.c
index 8511eac..23b8c35 100644
--- a/devices/gdevxini.c
+++ b/devices/gdevxini.c
@@ -59,7 +59,8 @@ static struct xv_ {
Boolean alloc_error;
XErrorHandler orighandler;
XErrorHandler oldhandler;
-} x_error_handler;
+ Boolean set;
+} x_error_handler = {0};
static int
x_catch_alloc(Display * dpy, XErrorEvent * err)
@@ -74,7 +75,8 @@ x_catch_alloc(Display * dpy, XErrorEvent * err)
int
x_catch_free_colors(Display * dpy, XErrorEvent * err)
{
- if (err->request_code == X_FreeColors)
+ if (err->request_code == X_FreeColors ||
+ x_error_handler.orighandler == x_catch_free_colors)
return 0;
return x_error_handler.orighandler(dpy, err);
}
@@ -274,8 +276,10 @@ gdev_x_open(gx_device_X * xdev)
return_error(gs_error_ioerror);
}
/* Buggy X servers may cause a Bad Access on XFreeColors. */
- x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);
-
+ if (!x_error_handler.set) {
+ x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);
+ x_error_handler.set = True;
+ }
/* Get X Resources. Use the toolkit for this. */
XtToolkitInitialize();
app_con = XtCreateApplicationContext();

View File

@ -0,0 +1,27 @@
From: Ken Sharp <ken.sharp@artifex.com>
Date: Fri, 24 Aug 2018 11:44:26 +0000 (+0100)
Subject: Hide the .shfill operator
X-Git-Url: http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=e01e77a3
Hide the .shfill operator
Commit 0b6cd1918e1ec4ffd087400a754a845180a4522b was supposed to make
the .shfill operator unobtainable, but I accidentally left a comment
in the line doing so.
Fix it here, without this the operator can still be exploited.
---
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index bc17d42..db3f7fe 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -2197,7 +2197,7 @@ SAFER { .setsafeglobal } if
/.oserrno /.setoserrno /.oserrorstring /.getCPSImode
/.getscanconverter /.setscanconverter /.type1encrypt /.type1decrypt/.languagelevel /.setlanguagelevel /.eqproc /.fillpage /.buildpattern1 /.saslprep
/.buildshading1 /.buildshading2 /.buildshading3 /.buildshading4 /.buildshading5 /.buildshading6 /.buildshading7 /.buildshadingpattern
-%/.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring
+/.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring
/.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile
/.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams
/.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath