ports/opt (3.4): [notify] ghostscript: security fix, several -dSAFER sandbox bypass vulnerabilities
commit 11f86218d26b42b30824d7678ec4a7b54cbd50e9 Author: Juergen Daubert <jue@jue.li> Date: Sat Aug 25 20:05:46 2018 +0200 [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 diff --git a/ghostscript/.signature b/ghostscript/.signature index 8c0b3ca66..30d34089a 100644 --- a/ghostscript/.signature +++ b/ghostscript/.signature @@ -1,6 +1,19 @@ untrusted comment: verify with /etc/ports/opt.pub -RWSE3ohX2g5d/fAfjoz0I76mLUiRieNsO8V6jhq5EVQ6xW14I/nmfV+aCRN4GXNPzuibAVddAgeDFQHT67ET7EstLrX9oiWLqgg= -SHA256 (Pkgfile) = bf1af24031803ccccd487cd7dfed24ead00597c00daef0f3c1698ee0b5d46f71 +RWSE3ohX2g5d/froAVb0xfR6peImTLVw25laSQoDWaxYCxl8iIc3+eGFpv01RYYqliddT0nIm31YTdVwZS/RF2l9f/HkZo2LKg4= +SHA256 (Pkgfile) = e4a88a0f36aec4197fc95a307812e31bd329eb53d64dbf81825cfa65fa09b778 SHA256 (.footprint) = 3514d4810f8fe93de5e8d03bc500e39d81dc6ab4118d0728c50d1e50e3bbc606 SHA256 (ghostscript-9.23.tar.xz) = 1fcedc27d4d6081105cdf35606cb3f809523423a6cf9e3c23cead3525d6ae8d9 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 diff --git a/ghostscript/Pkgfile b/ghostscript/Pkgfile index 7188478be..518daca8f 100644 --- a/ghostscript/Pkgfile +++ b/ghostscript/Pkgfile @@ -5,12 +5,39 @@ name=ghostscript version=9.23 -release=1 +release=2 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.t...) + http://downloads.sourceforge.net/sourceforge/gs-fonts/$name-fonts-std-8.11.t... + 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 () { 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 \ --enable-cups \ diff --git a/ghostscript/ghostpdl.git-0b6cd191.patch b/ghostscript/ghostpdl.git-0b6cd191.patch new file mode 100644 index 000000000..5c7323528 --- /dev/null +++ b/ghostscript/ghostpdl.git-0b6cd191.patch @@ -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 + diff --git a/ghostscript/ghostpdl.git-0d390118.patch b/ghostscript/ghostpdl.git-0d390118.patch new file mode 100644 index 000000000..bcaac484a --- /dev/null +++ b/ghostscript/ghostpdl.git-0d390118.patch @@ -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; diff --git a/ghostscript/ghostpdl.git-0edd3d6c.patch b/ghostscript/ghostpdl.git-0edd3d6c.patch new file mode 100644 index 000000000..a03193b34 --- /dev/null +++ b/ghostscript/ghostpdl.git-0edd3d6c.patch @@ -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)); diff --git a/ghostscript/ghostpdl.git-241d9111.patch b/ghostscript/ghostpdl.git-241d9111.patch new file mode 100644 index 000000000..7b6f4a4b2 --- /dev/null +++ b/ghostscript/ghostpdl.git-241d9111.patch @@ -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; diff --git a/ghostscript/ghostpdl.git-5516c614.patch b/ghostscript/ghostpdl.git-5516c614.patch new file mode 100644 index 000000000..5eea5948c --- /dev/null +++ b/ghostscript/ghostpdl.git-5516c614.patch @@ -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, diff --git a/ghostscript/ghostpdl.git-78911a01.patch b/ghostscript/ghostpdl.git-78911a01.patch new file mode 100644 index 000000000..e1434fbea --- /dev/null +++ b/ghostscript/ghostpdl.git-78911a01.patch @@ -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"); diff --git a/ghostscript/ghostpdl.git-8e9ce501.patch b/ghostscript/ghostpdl.git-8e9ce501.patch new file mode 100644 index 000000000..a4790d8a2 --- /dev/null +++ b/ghostscript/ghostpdl.git-8e9ce501.patch @@ -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); diff --git a/ghostscript/ghostpdl.git-a054156d.patch b/ghostscript/ghostpdl.git-a054156d.patch new file mode 100644 index 000000000..50faf184e --- /dev/null +++ b/ghostscript/ghostpdl.git-a054156d.patch @@ -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 diff --git a/ghostscript/ghostpdl.git-b326a716.patch b/ghostscript/ghostpdl.git-b326a716.patch new file mode 100644 index 000000000..c5c167cdb --- /dev/null +++ b/ghostscript/ghostpdl.git-b326a716.patch @@ -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; diff --git a/ghostscript/ghostpdl.git-b575e1ec.patch b/ghostscript/ghostpdl.git-b575e1ec.patch new file mode 100644 index 000000000..d5d15a26b --- /dev/null +++ b/ghostscript/ghostpdl.git-b575e1ec.patch @@ -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; diff --git a/ghostscript/ghostpdl.git-c3476dde.patch b/ghostscript/ghostpdl.git-c3476dde.patch new file mode 100644 index 000000000..cf2a2ebbf --- /dev/null +++ b/ghostscript/ghostpdl.git-c3476dde.patch @@ -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; diff --git a/ghostscript/ghostpdl.git-c432131c.patch b/ghostscript/ghostpdl.git-c432131c.patch new file mode 100644 index 000000000..849b852e0 --- /dev/null +++ b/ghostscript/ghostpdl.git-c432131c.patch @@ -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(); diff --git a/ghostscript/ghostpdl.git-e01e77a3.patch b/ghostscript/ghostpdl.git-e01e77a3.patch new file mode 100644 index 000000000..5859c4960 --- /dev/null +++ b/ghostscript/ghostpdl.git-e01e77a3.patch @@ -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
participants (1)
-
crux@crux.nu