diff --git a/SOURCES/ghostscript-cve-2018-15909.patch b/SOURCES/ghostscript-cve-2018-15909.patch index a4aff4b..372e663 100644 --- a/SOURCES/ghostscript-cve-2018-15909.patch +++ b/SOURCES/ghostscript-cve-2018-15909.patch @@ -39,9 +39,9 @@ Fix it here, without this the operator can still be exploited. https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=e01e77a36cbb2e0277bc3a63852244bec41be0f6 --- -diff -up a/Resource/Init/gs_init.ps.cve-2018-15909 b/Resource/Init/gs_init.ps ---- a/Resource/Init/gs_init.ps.cve-2018-15909 2018-11-15 12:01:44.102863484 +0100 -+++ b/Resource/Init/gs_init.ps 2018-11-15 12:03:16.564421701 +0100 +diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-15909 ghostscript-9.07/Resource/Init/gs_init.ps +--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-15909 2018-12-10 11:23:36.732179705 +0100 ++++ ghostscript-9.07/Resource/Init/gs_init.ps 2018-12-10 11:23:36.738179607 +0100 @@ -2136,8 +2136,8 @@ SAFER { .setsafe } if /.getiodevice /.getdevparms /.putdevparams /.bbox_transform /.matchmedia /.matchpagesize /.defaultpapersize /.oserrno /.setoserrno /.oserrorstring /.getCPSImode @@ -53,9 +53,9 @@ diff -up a/Resource/Init/gs_init.ps.cve-2018-15909 b/Resource/Init/gs_init.ps /.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 -up a/Resource/Init/gs_ll3.ps.cve-2018-15909 b/Resource/Init/gs_ll3.ps ---- a/Resource/Init/gs_ll3.ps.cve-2018-15909 2018-11-15 12:03:38.878073758 +0100 -+++ b/Resource/Init/gs_ll3.ps 2018-11-15 12:04:56.895857191 +0100 +diff -up ghostscript-9.07/Resource/Init/gs_ll3.ps.cve-2018-15909 ghostscript-9.07/Resource/Init/gs_ll3.ps +--- ghostscript-9.07/Resource/Init/gs_ll3.ps.cve-2018-15909 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_ll3.ps 2018-12-10 11:23:36.739179591 +0100 @@ -406,6 +406,11 @@ systemdict /.reuseparamdict mark /shfill .systemvar /undefined signalerror } ifelse @@ -77,15 +77,17 @@ diff -up a/Resource/Init/gs_ll3.ps.cve-2018-15909 b/Resource/Init/gs_ll3.ps grestore { /$error .systemvar /errorinfo 2 copy known { pop pop -diff -up a/Resource/Init/pdf_draw.ps.cve-2018-15909 b/Resource/Init/pdf_draw.ps ---- a/Resource/Init/pdf_draw.ps.cve-2018-15909 2018-11-15 12:05:34.592269375 +0100 -+++ b/Resource/Init/pdf_draw.ps 2018-11-15 12:06:54.143028905 +0100 -@@ -1131,7 +1131,7 @@ drawopdict begin +diff -up ghostscript-9.07/Resource/Init/pdf_draw.ps.cve-2018-15909 ghostscript-9.07/Resource/Init/pdf_draw.ps +--- ghostscript-9.07/Resource/Init/pdf_draw.ps.cve-2018-15909 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_draw.ps 2018-12-10 11:32:31.155445637 +0100 +@@ -1131,9 +1131,8 @@ drawopdict begin exch pop } { - .buildshading + .buildshading_and_shfill } ifelse - .shfill +- .shfill } stopped { + pop + ( **** Warning: Dropping incorrect smooth shading object.\n) diff --git a/SOURCES/ghostscript-cve-2018-15911.patch b/SOURCES/ghostscript-cve-2018-15911.patch new file mode 100644 index 0000000..70702e5 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-15911.patch @@ -0,0 +1,47 @@ +From: Ken Sharp +Date: Thu, 23 Aug 2018 14:42:02 +0000 (+0100) +Subject: Bug 699665 "memory corruption in aesdecode" + +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. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=8e9ce5016db968b40e4ec255a3005f2786cce45f +--- + +diff -up ghostscript-9.07/base/aes.c.cve-2018-15911 ghostscript-9.07/base/aes.c +--- ghostscript-9.07/base/aes.c.cve-2018-15911 2018-11-23 11:23:38.826259192 +0100 ++++ ghostscript-9.07/base/aes.c 2018-11-23 11:25:19.684507346 +0100 +@@ -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 -up ghostscript-9.07/base/saes.c.cve-2018-15911 ghostscript-9.07/base/saes.c +--- ghostscript-9.07/base/saes.c.cve-2018-15911 2018-11-23 11:25:48.914999536 +0100 ++++ ghostscript-9.07/base/saes.c 2018-11-23 11:26:29.903287483 +0100 +@@ -120,6 +120,7 @@ s_aes_process(stream_state * ss, stream_ + 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/SOURCES/ghostscript-cve-2018-16541.patch b/SOURCES/ghostscript-cve-2018-16541.patch new file mode 100644 index 0000000..f63b5c0 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-16541.patch @@ -0,0 +1,43 @@ +From: Chris Liddell +Date: Thu, 23 Aug 2018 14:41:18 +0000 (+0100) +Subject: Bug 699664: Ensure the correct is in place before cleanup + +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. + +http://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=241d91112771a6104de10b3948c3f350d6690c1d +--- + +diff -up ghostscript-9.07/psi/imain.c.cve-2018-16541 ghostscript-9.07/psi/imain.c +--- ghostscript-9.07/psi/imain.c.cve-2018-16541 2018-11-29 15:54:54.640496328 +0100 ++++ ghostscript-9.07/psi/imain.c 2018-11-29 15:56:00.652563801 +0100 +@@ -846,6 +846,16 @@ gs_main_finit(gs_main_instance * minst, + i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */ + } + #ifndef PSI_INCLUDED ++ 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/SOURCES/ghostscript-cve-2018-16802.patch b/SOURCES/ghostscript-cve-2018-16802.patch new file mode 100644 index 0000000..3d0f066 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-16802.patch @@ -0,0 +1,246 @@ +From: Chris Liddell +Date: Tue, 4 Sep 2018 22:18:46 +0000 (+0100) +Subject: Bug 699714: retain .LockSafetyParams through failed .installpagedevice + +Bug 699714: retain .LockSafetyParams through failed .installpagedevice + +In the event that the .trysetparams fails during .installpagedevice, catch the +error, and ensure that at least the .LockSafetyParams is set. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=5812b1b78fc4d36fdc293b7859de69241140d590 + +From: Chris Liddell +Date: Wed, 5 Sep 2018 16:14:59 +0000 (+0100) +Subject: Bug 699718: Ensure stack space is available before gsrestore call out + +Bug 699718: Ensure stack space is available before gsrestore call out + +During a grestore, if the device is going to change, we call out to Postscript +to restore the device configuration, before returning to restore the graphics +state internally. + +We have to ensure sufficient op stack space is available to complete the +operation, otherwise the device can end up an undefined state. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=3e5d316b72e3965b7968bb1d96baa137cd063ac6 + +From: Chris Liddell +Date: Fri, 7 Sep 2018 07:07:12 +0000 (+0100) +Subject: Bug 699718(2): Improve/augment stack size checking + +Bug 699718(2): Improve/augment stack size checking + +Improve the rebustness of the previous solution (previously it could trigger an +error when there *was* stack capacity available). + +Remove redundant check: we don't need to check if the *current* stack size is +sufficient, before checking the maximum permitted stack size. + +Also check the exec stack, as execstackoverflow can also cause the +Postscript call out to fail. + +Lastly, in event of failure, put the LockSafetyParams flag back in the existing +device (this is only necessary because we don't enfore JOBSERVER mode). + +Note: the Postscript callout (%grestorepagedevice) never pushes any dictionaries +on the dict stack - if that changes, we should check that stack, too. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=643b24dbd002fb9c131313253c307cf3951b3d47 +--- + +diff -up ghostscript-9.07/base/gserrors.h.cve-2018-16802 ghostscript-9.07/base/gserrors.h +--- ghostscript-9.07/base/gserrors.h.cve-2018-16802 2018-11-27 19:07:38.076517822 +0100 ++++ ghostscript-9.07/base/gserrors.h 2018-11-27 19:09:19.116234748 +0100 +@@ -25,6 +25,7 @@ + /* We use ints rather than an enum to avoid a lot of casting. */ + + #define gs_error_unknownerror (-1) /* unknown error */ ++#define gs_error_execstackoverflow (-5) + #define gs_error_interrupt (-6) + #define gs_error_invalidaccess (-7) + #define gs_error_invalidfileaccess (-9) +@@ -33,6 +34,7 @@ + #define gs_error_limitcheck (-13) + #define gs_error_nocurrentpoint (-14) + #define gs_error_rangecheck (-15) ++#define gs_error_stackoverflow (-16) + #define gs_error_stackunderflow (-17) + #define gs_error_typecheck (-20) + #define gs_error_undefined (-21) +diff -up ghostscript-9.07/psi/zdevice2.c.cve-2018-16802 ghostscript-9.07/psi/zdevice2.c +--- ghostscript-9.07/psi/zdevice2.c.cve-2018-16802 2018-11-27 19:04:51.665627148 +0100 ++++ ghostscript-9.07/psi/zdevice2.c 2018-11-27 19:04:51.696626755 +0100 +@@ -250,8 +250,8 @@ z2currentgstate(i_ctx_t *i_ctx_p) + /* ------ Wrappers for operators that reset the graphics state. ------ */ + + /* Check whether we need to call out to restore the page device. */ +-static bool +-restore_page_device(const gs_state * pgs_old, const gs_state * pgs_new) ++static int ++restore_page_device(i_ctx_t *i_ctx_p, const gs_state * pgs_old, const gs_state * pgs_new) + { + gx_device *dev_old = gs_currentdevice(pgs_old); + gx_device *dev_new; +@@ -259,9 +259,10 @@ restore_page_device(const gs_state * pgs + gx_device *dev_t2; + bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice, + &gs_int_gstate(pgs_new)->pagedevice); ++ bool LockSafetyParams = dev_old->LockSafetyParams; + + if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0) +- return false; ++ return 0; + /* If we are going to putdeviceparams in a callout, we need to */ + /* unlock temporarily. The device will be re-locked as needed */ + /* by putdeviceparams from the pgs_old->pagedevice dict state. */ +@@ -270,23 +271,51 @@ restore_page_device(const gs_state * pgs + dev_new = gs_currentdevice(pgs_new); + if (dev_old != dev_new) { + if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0) +- return false; +- if (dev_t1 != dev_t2) +- return true; ++ samepagedevice = true; ++ else if (dev_t1 != dev_t2) ++ samepagedevice = false; ++ } ++ ++ if (LockSafetyParams && !samepagedevice) { ++ const int required_ops = 512; ++ const int required_es = 32; ++ ++ /* The %grestorepagedevice must complete: the biggest danger ++ is operand stack overflow. As we use get/putdeviceparams ++ that means pushing all the device params onto the stack, ++ pdfwrite having by far the largest number of parameters ++ at (currently) 212 key/value pairs - thus needing (currently) ++ 424 entries on the op stack. Allowing for working stack ++ space, and safety margin..... ++ */ ++ if (required_ops + ref_stack_count(&o_stack) >= ref_stack_max_count(&o_stack)) { ++ gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams; ++ return_error(gs_error_stackoverflow); ++ } ++ /* We also want enough exec stack space - 32 is an overestimate of ++ what we need to complete the Postscript call out. ++ */ ++ if (required_es + ref_stack_count(&e_stack) >= ref_stack_max_count(&e_stack)) { ++ gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams; ++ return_error(gs_error_execstackoverflow); ++ } + } + /* + * The current implementation of setpagedevice just sets new + * parameters in the same device object, so we have to check + * whether the page device dictionaries are the same. + */ +- return !samepagedevice; ++ return samepagedevice ? 0 : 1; + } + + /* - grestore - */ + static int + z2grestore(i_ctx_t *i_ctx_p) + { +- if (!restore_page_device(igs, gs_state_saved(igs))) ++ int code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs)); ++ if (code < 0) return code; ++ ++ if (code == 0) + return gs_grestore(igs); + return push_callout(i_ctx_p, "%grestorepagedevice"); + } +@@ -296,7 +325,9 @@ static int + z2grestoreall(i_ctx_t *i_ctx_p) + { + for (;;) { +- if (!restore_page_device(igs, gs_state_saved(igs))) { ++ int code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs)); ++ if (code < 0) return code; ++ if (code == 0) { + bool done = !gs_state_saved(gs_state_saved(igs)); + + gs_grestore(igs); +@@ -327,11 +358,15 @@ z2restore(i_ctx_t *i_ctx_p) + if (code < 0) return code; + + while (gs_state_saved(gs_state_saved(igs))) { +- if (restore_page_device(igs, gs_state_saved(igs))) ++ code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs)); ++ if (code < 0) return code; ++ if (code > 0) + return push_callout(i_ctx_p, "%restore1pagedevice"); + gs_grestore(igs); + } +- if (restore_page_device(igs, gs_state_saved(igs))) ++ code = restore_page_device(i_ctx_p, igs, gs_state_saved(igs)); ++ if (code < 0) return code; ++ if (code > 0) + return push_callout(i_ctx_p, "%restorepagedevice"); + + code = dorestore(i_ctx_p, asave); +@@ -354,9 +389,12 @@ static int + z2setgstate(i_ctx_t *i_ctx_p) + { + os_ptr op = osp; ++ int code; + + check_stype(*op, st_igstate_obj); +- if (!restore_page_device(igs, igstate_ptr(op))) ++ code = restore_page_device(i_ctx_p, igs, igstate_ptr(op)); ++ if (code < 0) return code; ++ if (code == 0) + return zsetgstate(i_ctx_p); + return push_callout(i_ctx_p, "%setgstatepagedevice"); + } +diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-16802 ghostscript-9.07/Resource/Init/gs_setpd.ps +--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-16802 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_setpd.ps 2018-11-27 19:04:51.696626755 +0100 +@@ -95,27 +95,41 @@ level2dict begin + { % Since setpagedevice doesn't create new device objects, + % we must (carefully) reinstall the old parameters in + % the same device. +- .currentpagedevice pop //null currentdevice //null .trysetparams ++ .currentpagedevice pop //null currentdevice //null ++ { .trysetparams } .internalstopped ++ { ++ //null ++ } if + dup type /booleantype eq + { pop pop } +- { % This should never happen! ++ { + SETPDDEBUG { (Error in .trysetparams!) = pstack flush } if +- cleartomark pop pop pop ++ {cleartomark pop pop pop} .internalstopped pop ++ % if resetting the entire device state failed, at least put back the ++ % security related key ++ currentdevice //null //false mark /.LockSafetyParams ++ currentpagedevice /.LockSafetyParams .knownget not ++ {systemdict /SAFER .knownget not {//false} } if ++ .putdeviceparamsonly + /.installpagedevice cvx /rangecheck signalerror + } + ifelse pop pop + % A careful reading of the Red Book reveals that an erasepage + % should occur, but *not* an initgraphics. + erasepage .beginpage +- } bind def ++ } bind executeonly def + + /.uninstallpagedevice +- { 2 .endpage { .currentnumcopies //false .outputpage } if ++ { ++ {2 .endpage { .currentnumcopies //false .outputpage } if} .internalstopped pop + nulldevice + } bind def + + (%grestorepagedevice) cvn +- { .uninstallpagedevice grestore .installpagedevice ++ { ++ .uninstallpagedevice ++ grestore ++ .installpagedevice + } bind def + + (%grestoreallpagedevice) cvn diff --git a/SOURCES/ghostscript-cve-2018-17183.patch b/SOURCES/ghostscript-cve-2018-17183.patch new file mode 100644 index 0000000..54f4bd6 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-17183.patch @@ -0,0 +1,290 @@ +From: Chris Liddell +Date: Thu, 6 Sep 2018 08:16:22 +0000 (+0100) +Subject: Bug 699708 (part 1): 'Hide' non-replaceable error handlers for SAFER + +Bug 699708 (part 1): 'Hide' non-replaceable error handlers for SAFER + +We already had a 'private' dictionary for non-standard errors: gserrordict. + +This now includes all the default error handlers, the dictionary is made +noaccess and all the prodedures are bound and executeonly. + +When running with -dSAFER, in the event of a Postscript error, instead of +pulling the handler from errordict, we'll pull it from gserrordict - thus +malicious input cannot trigger problems by the use of custom error handlers. + +errordict remains open and writeable, so files such as the Quality Logic tests +that install their own handlers will still 'work', with the exception that the +custom error handlers will not be called. + +This is a 'first pass', 'sledgehammer' approach: a nice addition would to allow +an integrator to specify a list of errors that are not to be replaced (for +example, embedded applications would probably want to ensure that VMerror is +always handled as they intend). + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=fb713b3818b52d8a6cf62c951eba2e1795ff9624 + +From: Chris Liddell +Date: Thu, 4 Oct 2018 09:42:13 +0000 (+0100) +Subject: Bug 699832: add control over hiding error handlers. + +Bug 699832: add control over hiding error handlers. + +With a previous commit changing error handling in SAFER so the handler gets +passed a name object (rather than executable object), it is less critical to +hide the error handlers. + +This introduces a -dSAFERERRORS option to force only use of the default error +handlers. + +It also adds a .setsafererrors Postscript call, meaning a caller, without +-dSAFERERRORS, can create their own default error handlers (in errordict, as +normal), and then call .setsafererrors meaning their own handlers are always +called. + +With -dSAFERERRORS or after a call to .setsafererrors, .setsafererrors is +removed. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=1778db6bc10a8d60dfe986b22d2300326733ddd6 + +From: Chris Liddell +Date: Tue, 2 Oct 2018 15:02:58 +0000 (+0100) +Subject: For hidden operators, pass a name object to error handler. + +For hidden operators, pass a name object to error handler. + +In normal operation, Postscript error handlers are passed the object which +triggered the error: this is invariably an operator object. + +The issue arises when an error is triggered by an operator which is for internal +use only, and that operator is then passed to the error handler, meaning it +becomes visible to the error handler code. + +By converting to a name object, the error message is still valid, but we no +longer expose internal use only operators. + +The change in gs_dps1.ps is related to the above: previously an error in +scheck would throw an error against .gcheck, but as .gcheck is now a hidden +operator, it resulted in a name object being passed to the error handler. As +scheck is a 'real' operator, it's better to use the real operator, rather than +the name of an internal, hidden one. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a6807394bd94b708be24758287b606154daaaed9 +--- + +diff -up ghostscript-9.07/psi/interp.c.cve-2018-17183 ghostscript-9.07/psi/interp.c +--- ghostscript-9.07/psi/interp.c.cve-2018-17183 2018-11-30 14:21:33.531815665 +0100 ++++ ghostscript-9.07/psi/interp.c 2018-11-30 14:43:42.520691143 +0100 +@@ -650,20 +650,25 @@ again: + return code; + if (gs_errorname(i_ctx_p, code, &error_name) < 0) + return code; /* out-of-range error code! */ +- /* +- * For greater Adobe compatibility, only the standard PostScript errors +- * are defined in errordict; the rest are in gserrordict. ++ ++ /* We refer to gserrordict first, which is not accessible to Postcript jobs ++ * If we're running with SAFERERRORS all the handlers are copied to gserrordict ++ * so we'll always find the default one. If not SAFERERRORS, only gs specific ++ * errors are in gserrordict. + */ +- if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || ++ if (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || + (dict_find(perrordict, &error_name, &epref) <= 0 && +- (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || ++ (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || + dict_find(perrordict, &error_name, &epref) <= 0)) + ) + return code; /* error name not in errordict??? */ ++ + doref = *epref; + epref = &doref; + /* Push the error object on the operand stack if appropriate. */ + if (!ERROR_IS_INTERRUPT(code)) { ++ byte buf[260], *bufptr; ++ uint rlen; + /* Replace the error object if within an oparray or .errorexec. */ + osp++; + if (osp >= ostop) { +@@ -672,6 +677,37 @@ again: + } + *osp = *perror_object; + errorexec_find(i_ctx_p, osp); ++ ++ if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) { ++ code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr); ++ if (code < 0) { ++ const char *unknownstr = "--unknown--"; ++ rlen = strlen(unknownstr); ++ memcpy(buf, unknownstr, rlen); ++ bufptr = buf; ++ } ++ else { ++ ref *tobj; ++ bufptr[rlen] = '\0'; ++ /* Only pass a name object if the operator doesn't exist in systemdict ++ * i.e. it's an internal operator we have hidden ++ */ ++ code = dict_find_string(systemdict, (const char *)bufptr, &tobj); ++ if (code < 0) { ++ buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; ++ rlen += 4; ++ bufptr = buf; ++ } ++ else { ++ bufptr = NULL; ++ } ++ } ++ if (bufptr) { ++ code = name_ref(imemory, buf, rlen, osp, 1); ++ if (code < 0) ++ make_null(osp); ++ } ++ } + } + goto again; + } +diff -up ghostscript-9.07/Resource/Init/gs_dps1.ps.cve-2018-17183 ghostscript-9.07/Resource/Init/gs_dps1.ps +--- ghostscript-9.07/Resource/Init/gs_dps1.ps.cve-2018-17183 2018-11-30 14:40:30.044460932 +0100 ++++ ghostscript-9.07/Resource/Init/gs_dps1.ps 2018-11-30 14:41:03.291982495 +0100 +@@ -21,7 +21,7 @@ level2dict begin + % ------ Virtual memory ------ % + + /currentshared /.currentglobal load def +-/scheck /.gcheck load def ++/scheck {.gcheck} bind odef + %****** FOLLOWING IS WRONG ****** + /shareddict currentdict /globaldict .knownget not { 20 dict } if def + +diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-17183 ghostscript-9.07/Resource/Init/gs_init.ps +--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-17183 2018-11-30 14:16:19.956328097 +0100 ++++ ghostscript-9.07/Resource/Init/gs_init.ps 2018-11-30 14:30:28.051123777 +0100 +@@ -183,6 +183,16 @@ currentdict /DELAYSAFER known { /DELAYSA + currentdict /PARANOIDSAFER known or % PARANOIDSAFER is equivalent + } + ifelse def ++ ++/SAFERERRORS ++currentdict /NOSAFERERRORS known ++{ ++ //false ++} ++{ ++ currentdict /SAFERERRORS known ++} ifelse def ++ + currentdict /SHORTERRORS known /SHORTERRORS exch def + currentdict /STRICT known /STRICT exch def + currentdict /TTYPAUSE known /TTYPAUSE exch def +@@ -880,7 +890,7 @@ userdict /.currentresourcefile //null pu + { not exch pop exit } { pop } ifelse + } + for exch pop .quit +- } bind def ++ } bind executeonly def + /.errorhandler % .errorhandler - + { % Detect an internal 'stopped'. + 1 .instopped { //null eq { pop pop stop } if } if +@@ -925,7 +935,7 @@ userdict /.currentresourcefile //null pu + $error /globalmode get $error /.nosetlocal get and .setglobal + $error /.inerror //false put + stop +- } bind def ++ } bind executeonly def + % Define the standard handleerror. We break out the printing procedure + % (.printerror) so that it can be extended for binary output + % if the Level 2 facilities are present. +@@ -975,7 +985,7 @@ userdict /.currentresourcefile //null pu + ifelse % newerror + end + flush +- } bind def ++ } bind executeonly def + /.printerror_long % long error printout, + % $error is on the dict stack + { % Push the (anonymous) stack printing procedure. +@@ -1052,14 +1062,14 @@ userdict /.currentresourcefile //null pu + { (Current file position is ) print position = } + if + +- } bind def ++ } bind executeonly def + % Define a procedure for clearing the error indication. + /.clearerror + { $error /newerror //false put + $error /errorname //null put + $error /errorinfo //null put + 0 .setoserrno +- } bind def ++ } bind executeonly def + + % Define $error. This must be in local VM. + .currentglobal //false .setglobal +@@ -1085,11 +1095,15 @@ end + /errordict ErrorNames length 3 add dict + .forcedef % errordict is local, systemdict is global + .setglobal % back to global VM +-% For greater Adobe compatibility, we put all non-standard errors in a +-% separate dictionary, gserrordict. It does not need to be in local VM, +-% because PostScript programs do not access it. ++% gserrordict contains all the default error handling methods, but unlike ++% errordict it is noaccess after creation (also it is in global VM). ++% When running 'SAFER', we'll ignore the contents of errordict, which ++% may have been tampered with by the running job, and always use gserrordict ++% gserrordict also contains any non-standard errors, for better compatibility ++% with Adobe. ++% + % NOTE: the name gserrordict is known to the interpreter. +-/gserrordict 5 dict def ++/gserrordict ErrorNames length 3 add dict def + % Register an error in errordict. We make this a procedure because we only + % register the Level 1 errors here: the rest are registered by "feature" + % files. However, ErrorNames contains all of the error names regardless of +@@ -1118,9 +1132,23 @@ errordict begin + } bind def + end % errordict + +-% Put non-standard errors in gserrordict. + gserrordict /unknownerror errordict /unknownerror get put + errordict /unknownerror .undef ++ ++/.SAFERERRORLIST ErrorNames def ++/.setsafererrors ++{ ++% Put all the requested handlers in gserrordict ++ gserrordict ++ //.SAFERERRORLIST ++ {dup errordict exch get 2 index 3 1 roll put} forall ++ noaccess pop ++ systemdict /.setsafeerrors .forceundef ++ systemdict /.SAFERERRORLIST .forceundef ++} bind executeonly odef ++ ++SAFERERRORS {.setsafererrors} if ++ + % Define a stable private copy of handleerror that we will always use under + % JOBSERVER mode. + /.GShandleerror errordict /handleerror get def +@@ -1743,18 +1771,15 @@ currentdict /.runlibfile .undef + + % Bind all the operators defined as procedures. + /.bindoperators % binds operators in currentdict +- { % Temporarily disable the typecheck error. +- errordict /typecheck 2 copy get +- errordict /typecheck { pop } put % pop the command ++ { + currentdict + { dup type /operatortype eq +- { % This might be a real operator, so bind might cause a typecheck, +- % but we've made the error a no-op temporarily. +- .bind % do a real bind even if NOBIND is set ++ { ++ % This might be a real operator, so bind might cause a typecheck ++ {.bind} .internalstopped pop + } + if pop pop + } forall +- put + } def + NOBIND DELAYBIND or not { .bindoperators } if + diff --git a/SOURCES/ghostscript-cve-2018-17961.patch b/SOURCES/ghostscript-cve-2018-17961.patch new file mode 100644 index 0000000..f708067 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-17961.patch @@ -0,0 +1,387 @@ +From: Chris Liddell +Date: Sat, 29 Sep 2018 14:34:55 +0000 (+0100) +Subject: Bug 699816: Improve hiding of security critical custom operators + +Bug 699816: Improve hiding of security critical custom operators + +Make procedures that use .forceput/.forcedef/.forceundef into operators. + +The result of this is that errors get reported against the "top" operator, +rather than the "called" operator within the procedure. + +For example: +/myproc +{ + myop +} bind def + +If 'myop' throws an error, the error handler will be passed the 'myop' +operator. Promoting 'myproc' to a operator means the error handler will be +passed 'myproc'. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a54c9e61e7d02bbc620bcba9b1c208462a876afb + +From: Chris Liddell +Date: Wed, 10 Oct 2018 22:25:51 +0000 (+0100) +Subject: Bug 699938: .loadfontloop must be an operator + +Bug 699938: .loadfontloop must be an operator + +In the fix for Bug 699816, I omitted to make .loadfontloop into an operator, to +better hide .forceundef and .putgstringcopy. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a5a9bf8c6a63aa4ac6874234fe8cd63e72077291 + +From: Chris Liddell +Date: Wed, 28 Nov 2018 17:12:08 +0000 (+0000) +Subject: Bug 700290: Fix problems with DELAYBIND and font substitution + +Bug 700290: Fix problems with DELAYBIND and font substitution + +Judicious use of immediate evaluation for .setnativefontmapbuilt and +.putgstringcopy to avoid problems with DELAYBIND + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=2756f0efae1d3966989b15a6526c5d80848b5015 +--- + +diff -up ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_diskn.ps +--- ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_diskn.ps 2018-12-10 14:51:03.208407266 +0100 +@@ -53,7 +53,7 @@ systemdict begin + exch .setglobal + } + if +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Modify .putdevparams to force regeneration of .searchabledevs list + /.putdevparams { +diff -up ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_dps.ps +--- ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_dps.ps 2018-12-10 14:51:03.208407266 +0100 +@@ -71,7 +71,7 @@ + //true .setglobal + //systemdict /savedinitialgstate gstate readonly put + .setglobal +-} .bind def ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Initialize local dictionaries and gstate when creating a new context. + % Note that until this completes, we are in the anomalous situation of +diff -up ghostscript-9.07/Resource/Init/gs_fntem.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_fntem.ps +--- ghostscript-9.07/Resource/Init/gs_fntem.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_fntem.ps 2018-12-10 14:51:03.209407249 +0100 +@@ -432,7 +432,7 @@ currentdict end def + exit + } loop + exch setglobal +-} bind def ++} .bind executeonly odef % must be bound and hidden for .forceput + + currentdict end /ProcSet defineresource pop + +diff -up ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_fonts.ps +--- ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-17961 2018-12-10 14:51:03.002410648 +0100 ++++ ghostscript-9.07/Resource/Init/gs_fonts.ps 2018-12-10 14:51:03.209407249 +0100 +@@ -375,7 +375,7 @@ FONTPATH length 0 eq { (%END FONTPATH) . + % and the access path. + /.setnativefontmapbuilt { % set whether we've been run + systemdict exch /.nativefontmapbuilt exch .forceput +-} .bind executeonly def ++} .bind executeonly odef + systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt + /.buildnativefontmap { % - .buildnativefontmap + QUIET not { +@@ -404,7 +404,7 @@ systemdict /NONATIVEFONTMAP known .setna + } forall + } if + % record that we've been run +- //true .setnativefontmapbuilt ++ //true //.setnativefontmapbuilt + } bind def + + % Create the dictionary that registers the .buildfont procedure +@@ -1082,7 +1082,7 @@ $error /SubstituteFont { } put + + % Check to make sure the font was actually loaded. + dup 3 index .fontknownget +- { dup /PathLoad 4 index //.putgstringcopy exec ++ { dup /PathLoad 4 index //.putgstringcopy + 4 1 roll pop pop pop //true exit + } if + +@@ -1094,7 +1094,7 @@ $error /SubstituteFont { } put + { % Stack: origfontname fontdirectory path filefontname + 2 index 1 index .fontknownget + { % Yes. Stack: origfontname fontdirectory path filefontname fontdict +- dup 4 -1 roll /PathLoad exch //.putgstringcopy exec ++ dup 4 -1 roll /PathLoad exch //.putgstringcopy + % Stack: origfontname fontdirectory filefontname fontdict + 3 -1 roll pop exch + % Stack: origfontname fontdict filefontname +@@ -1122,9 +1122,8 @@ $error /SubstituteFont { } put + + } loop % end of loop + +- } bind executeonly def % must be bound and hidden for .putgstringcopy +- +-currentdict /.putgstringcopy .undef ++ } bind executeonly odef % must be bound and hidden for .putgstringcopy ++currentdict /.putgstringcopy .forceundef + + % Define a procedure to load all known fonts. + % This isn't likely to be very useful. +diff -up ghostscript-9.07/Resource/Init/gs_lev2.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_lev2.ps +--- ghostscript-9.07/Resource/Init/gs_lev2.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_lev2.ps 2018-12-10 14:51:03.210407233 +0100 +@@ -163,9 +163,10 @@ end + % Set them again to the new values. From here on, we are safe, + % since a context switch will consult userparams. + .setuserparams +-} .bind def ++} .bind executeonly odef % must be bound and hidden for .forceput + /setuserparams { % setuserparams - +- .setuserparams2 ++ {.setuserparams2} stopped ++ {/setuserparams load $error /errorname get signalerror} if + } .bind odef + % Initialize user parameters managed here. + /JobName () .definepsuserparam +@@ -414,7 +415,9 @@ psuserparams /ProcessDSCComment {.checkp + + % VMReclaim and VMThreshold are user parameters. + /setvmthreshold { % setvmthreshold - +- mark /VMThreshold 2 .argindex .dicttomark .setuserparams2 pop ++ mark /VMThreshold 2 .argindex .dicttomark {.setuserparams2} stopped ++ {pop /setvmthreshold load $error /errorname get signalerror} ++ {pop} ifelse + } odef + /vmreclaim { % vmreclaim - + dup 0 gt { +@@ -426,7 +429,9 @@ psuserparams /ProcessDSCComment {.checkp + ifelse + } { + % VMReclaim userparam controls enable/disable GC +- mark /VMReclaim 2 index .dicttomark .setuserparams2 pop ++ mark /VMReclaim 2 index .dicttomark {.setuserparams2} stopped ++ {pop /vmreclaim load $error /errorname get signalerror} ++ {pop} ifelse + } ifelse + } odef + -1 setvmthreshold +diff -up ghostscript-9.07/Resource/Init/gs_pdfwr.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_pdfwr.ps +--- ghostscript-9.07/Resource/Init/gs_pdfwr.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_pdfwr.ps 2018-12-10 14:51:03.210407233 +0100 +@@ -547,8 +547,7 @@ currentdict /.pdfmarkparams .undef + } { + pop + } ifelse +-} +-bind def ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Use the DSC processing hook to pass DSC comments to the driver. + % We use a pseudo-parameter named DSC whose value is an array: +diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_setpd.ps +--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-17961 2018-12-10 14:51:03.194407496 +0100 ++++ ghostscript-9.07/Resource/Init/gs_setpd.ps 2018-12-10 14:51:03.210407233 +0100 +@@ -544,6 +544,20 @@ NOMEDIAATTRS { + % in the dictionary with the policy value, + % and we replace the key in the dictionary with its prior value + % (or remove it if it had no prior value). ++ ++% Making this an operator means we can properly hide ++% the contents - specifically .forceput ++/1Policy ++{ ++ % Roll back the failed request to its previous status. ++ SETPDDEBUG { (Rolling back.) = pstack flush } if ++ 3 index 2 index 3 -1 roll .forceput ++ 4 index 1 index .knownget ++ { 4 index 3 1 roll .forceput } ++ { 3 index exch .undef } ++ ifelse ++} bind executeonly odef ++ + /.policyprocs mark + % These procedures are called with the following on the stack: + % +@@ -567,14 +581,7 @@ NOMEDIAATTRS { + /setpagedevice .systemvar /configurationerror signalerror + } ifelse + } bind +- 1 { % Roll back the failed request to its previous status. +-SETPDDEBUG { (Rolling back.) = pstack flush } if +- 3 index 2 index 3 -1 roll .forceput +- 4 index 1 index .knownget +- { 4 index 3 1 roll .forceput } +- { 3 index exch .undef } +- ifelse +- } .bind ++ 1 /1Policy load + 7 { % For PageSize only, just impose the request. + 1 index /PageSize eq + { pop pop 1 index /PageSize 7 put } +@@ -582,6 +589,8 @@ SETPDDEBUG { (Rolling back.) = pstack fl + ifelse + } bind + .dicttomark readonly def ++currentdict /1Policy undef ++ + /.applypolicies % .applypolicies + % + { 1 index /Policies get 1 index +diff -up ghostscript-9.07/Resource/Init/gs_typ32.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_typ32.ps +--- ghostscript-9.07/Resource/Init/gs_typ32.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_typ32.ps 2018-12-10 14:51:03.211407216 +0100 +@@ -79,15 +79,19 @@ systemdict /.removeglyphs .undef + .dicttomark /ProcSet defineresource pop + + /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse +-.cidfonttypes begin +- +-4 % CIDFontType 4 = FontType 32 +-{ dup /FontType 32 .forceput ++/CIDFontType4 ++{ ++ dup /FontType 32 .forceput + dup /CharStrings 20 dict .forceput + 1 index exch .buildfont32 exch pop +-} bind def ++} .bind executeonly odef ++.cidfonttypes begin ++ ++ ++4 /CIDFontType4 load def % CIDFontType 4 = FontType 32 + + end % .cidfonttypes ++currentdict /CIDFontType4 .forceundef + + % Define the BuildGlyph procedure. + % Since Type 32 fonts are indexed by CID, there is no BuildChar procedure. +diff -up ghostscript-9.07/Resource/Init/gs_type1.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/gs_type1.ps +--- ghostscript-9.07/Resource/Init/gs_type1.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_type1.ps 2018-12-10 14:51:03.211407216 +0100 +@@ -215,7 +215,7 @@ currentdict /closesourcedict .undef + } if + 2 copy /WeightVector exch .forceput + .setweightvector +-} .bind executeonly def ++} .bind executeonly odef + end + + % Register the font types for definefont. +diff -up ghostscript-9.07/Resource/Init/pdf_base.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/pdf_base.ps +--- ghostscript-9.07/Resource/Init/pdf_base.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_base.ps 2018-12-10 14:51:03.211407216 +0100 +@@ -177,7 +177,7 @@ currentdict /num-chars-dict .undef + } ifelse + } ifelse + } ifelse +-} bind def ++} bind executeonly odef + /PDFScanRules_true << /PDFScanRules //true >> def + /PDFScanRules_null << /PDFScanRules //null >> def + /.pdfrun { % .pdfrun - +diff -up ghostscript-9.07/Resource/Init/pdf_draw.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/pdf_draw.ps +--- ghostscript-9.07/Resource/Init/pdf_draw.ps.cve-2018-17961 2018-12-10 14:51:03.177407775 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_draw.ps 2018-12-10 14:51:03.212407200 +0100 +@@ -948,7 +948,7 @@ currentdict end readonly def + Q + PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if + PDFfile exch setfileposition +-} bdef ++}bind executeonly odef + + /resolvepattern { % resolvepattern + % Don't do the resolvestream now: just capture the data +@@ -1809,7 +1809,7 @@ currentdict /last-ditch-bpc-csp undef + } if + pop + /pdfemptycount exch store +-} bdef ++} bind executeonly odef + + /_dops_save 1 array def + +diff -up ghostscript-9.07/Resource/Init/pdf_font.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/pdf_font.ps +--- ghostscript-9.07/Resource/Init/pdf_font.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_font.ps 2018-12-10 14:51:03.213407183 +0100 +@@ -641,7 +641,7 @@ currentdict end readonly def + } if + } if + pop pop pop +-} bind def ++} bind executeonly odef + + % ---------------- Descriptors ---------------- % + +@@ -1097,7 +1097,7 @@ currentdict /eexec_pdf_param_dict .undef + } bdef + dup currentdict Encoding .processToUnicode + currentdict end .completefont exch pop +-} bdef ++} bind executeonly odef + /.adjustcharwidth { % .adjustcharwidth + % Enforce the metrics, in glyph space, to the values found in the PDF Font object + % - force wy == 0 (assumed, and not stored in the PDF font) +@@ -1794,7 +1794,7 @@ currentdict /CMap_read_dict undef + } if + /findresource cvx /undefined signalerror + } loop +-} bdef ++} bind executeonly odef + + /buildCIDType0 { % buildCIDType0 + dup /BaseFont get findCIDFont exch pop +@@ -1964,7 +1964,7 @@ currentdict /CMap_read_dict undef + /Type0 //buildType0 + /Type1 //buildType1 + /MMType1 //buildType1 +- /Type3 //buildType3 ++ /Type3 /buildType3 load + /TrueType //buildTrueType + /CIDFontType0 //buildCIDType0 + /CIDFontType2 //buildCIDType2 +diff -up ghostscript-9.07/Resource/Init/pdf_main.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/pdf_main.ps +--- ghostscript-9.07/Resource/Init/pdf_main.ps.cve-2018-17961 2018-12-10 14:51:03.168407922 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_main.ps 2018-12-10 14:51:03.213407183 +0100 +@@ -382,7 +382,7 @@ currentdict /runpdfstring .undef + } forall + pop + } ifelse +-} bind def ++} bind executeonly odef + + currentdict /pdf_collection_files .undef + +@@ -1878,7 +1878,7 @@ currentdict /PDF2PS_matrix_key undef + Repaired % pass Repaired state around the restore + PDFSave restore + /Repaired exch def +-} bind def ++} bind executeonly odef + + % Display the contents of a page (including annotations). + /showpagecontents { % showpagecontents - +diff -up ghostscript-9.07/Resource/Init/pdf_ops.ps.cve-2018-17961 ghostscript-9.07/Resource/Init/pdf_ops.ps +--- ghostscript-9.07/Resource/Init/pdf_ops.ps.cve-2018-17961 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/pdf_ops.ps 2018-12-10 14:51:03.214407167 +0100 +@@ -128,7 +128,7 @@ nodict readonly pop + { (\n **** File has unbalanced q/Q operators \(too many Q's\) ****\n) + pdfformaterror + } if +-} bdef ++} bind executeonly odef + + % Save PDF gstate + /qstate { % - qstate +@@ -282,7 +282,7 @@ nodict readonly pop + } bdef + /ca { /FillConstantAlpha gput } bdef + /CA { /StrokeConstantAlpha gput } bdef +-/SMask { /SoftMask gput } bdef ++/SMask { /SoftMask gput } bind executeonly odef + /AIS { /AlphaIsShape gput } bdef + /BM { + /.setblendmode where { diff --git a/SOURCES/ghostscript-cve-2018-18073.patch b/SOURCES/ghostscript-cve-2018-18073.patch new file mode 100644 index 0000000..8761177 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-18073.patch @@ -0,0 +1,229 @@ +From: Chris Liddell +Date: Wed, 10 Oct 2018 14:38:10 +0000 (+0100) +Subject: Bug 699927: don't include operator arrays in execstack output + +Bug 699927: don't include operator arrays in execstack output + +When we transfer the contents of the execution stack into the array, take the +extra step of replacing any operator arrays on the stack with the operator +that reference them. + +This prevents the contents of Postscript defined, internal only operators (those +created with .makeoperator) being exposed via execstack (and thus, via error +handling). + +This necessitates a change in the resource remapping 'resource', which contains +a procedure which relies on the contents of the operators arrays being present. +As we already had internal-only variants of countexecstack and execstack +(.countexecstack and .execstack) - using those, and leaving thier operation +including the operator arrays means the procedure continues to work correctly. + +Both .countexecstack and .execstack are undefined after initialization. + +Also, when we store the execstack (or part thereof) for an execstackoverflow +error, make the same oparray/operator substitution as above for execstack. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=34cc326eb2c5695833361887fe0b32e8d987741c + +From: Chris Liddell +Date: Tue, 25 Sep 2018 14:38:14 +0000 (+0100) +Subject: Bug 699793: Hide the .needinput operator + +Bug 699793: Hide the .needinput operator + +This removes the .needinput operator from systemdict, ensuring it can only +be used in the initialization code, and not called erroneously from random +Postscript. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=f8ccc7dfb990336b1ca55f65f2e1a8ecdcb76adf +--- + +diff -up ghostscript-9.07/psi/interp.c.cve-2018-18073 ghostscript-9.07/psi/interp.c +--- ghostscript-9.07/psi/interp.c.cve-2018-18073 2018-12-05 15:15:27.071274267 +0100 ++++ ghostscript-9.07/psi/interp.c 2018-12-05 15:15:27.077274220 +0100 +@@ -142,7 +142,6 @@ static int oparray_pop(i_ctx_t *); + static int oparray_cleanup(i_ctx_t *); + static int zerrorexec(i_ctx_t *); + static int zfinderrorobject(i_ctx_t *); +-static int errorexec_find(i_ctx_t *, ref *); + static int errorexec_pop(i_ctx_t *); + static int errorexec_cleanup(i_ctx_t *); + static int zsetstackprotect(i_ctx_t *); +@@ -751,7 +750,7 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_s + { + uint size = ref_stack_count(pstack) - skip; + uint save_space = ialloc_space(idmemory); +- int code; ++ int code, i; + + if (size > 65535) + size = 65535; +@@ -760,6 +759,15 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_s + if (code >= 0) + code = ref_stack_store(pstack, arr, size, 0, 1, true, idmemory, + "copy_stack"); ++ /* If we are copying the exec stack, try to replace any oparrays with ++ * with the operator than references them ++ */ ++ if (pstack == &e_stack) { ++ for (i = 0; i < size; i++) { ++ if (errorexec_find(i_ctx_p, &arr->value.refs[i]) < 0) ++ make_null(&arr->value.refs[i]); ++ } ++ } + ialloc_set_space(idmemory, save_space); + return code; + } +@@ -1908,7 +1916,7 @@ zfinderrorobject(i_ctx_t *i_ctx_p) + * .errorexec with errobj != null, store it in *perror_object and return 1, + * otherwise return 0; + */ +-static int ++int + errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object) + { + long i; +diff -up ghostscript-9.07/psi/interp.h.cve-2018-18073 ghostscript-9.07/psi/interp.h +--- ghostscript-9.07/psi/interp.h.cve-2018-18073 2013-02-14 08:58:13.000000000 +0100 ++++ ghostscript-9.07/psi/interp.h 2018-12-05 15:15:27.077274220 +0100 +@@ -92,5 +92,7 @@ void gs_interp_reset(i_ctx_t *i_ctx_p); + /* Define the top-level interface to the interpreter. */ + int gs_interpret(i_ctx_t **pi_ctx_p, ref * pref, int user_errors, + int *pexit_code, ref * perror_object); ++int ++errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object); + + #endif /* interp_INCLUDED */ +diff -up ghostscript-9.07/psi/int.mak.cve-2018-18073 ghostscript-9.07/psi/int.mak +--- ghostscript-9.07/psi/int.mak.cve-2018-18073 2018-12-05 15:15:27.017274689 +0100 ++++ ghostscript-9.07/psi/int.mak 2018-12-05 15:15:27.077274220 +0100 +@@ -317,7 +317,8 @@ $(PSOBJ)zarray.$(OBJ) : $(PSSRC)zarray.c + $(PSCC) $(PSO_)zarray.$(OBJ) $(C_) $(PSSRC)zarray.c + + $(PSOBJ)zcontrol.$(OBJ) : $(PSSRC)zcontrol.c $(OP) $(string__h)\ +- $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h) ++ $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)\ ++ $(interp_h) + $(PSCC) $(PSO_)zcontrol.$(OBJ) $(C_) $(PSSRC)zcontrol.c + + $(PSOBJ)zdict.$(OBJ) : $(PSSRC)zdict.c $(OP)\ +diff -up ghostscript-9.07/psi/zcontrol.c.cve-2018-18073 ghostscript-9.07/psi/zcontrol.c +--- ghostscript-9.07/psi/zcontrol.c.cve-2018-18073 2013-02-14 08:58:13.000000000 +0100 ++++ ghostscript-9.07/psi/zcontrol.c 2018-12-05 15:15:27.077274220 +0100 +@@ -24,6 +24,7 @@ + #include "ipacked.h" + #include "iutil.h" + #include "store.h" ++#include "interp.h" + + /* Forward references */ + static int check_for_exec(const_os_ptr); +@@ -785,7 +786,7 @@ zexecstack2(i_ctx_t *i_ctx_p) + /* Continuation operator to do the actual transfer. */ + /* r_size(op1) was set just above. */ + static int +-do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1) ++do_execstack(i_ctx_t *i_ctx_p, bool include_marks, bool include_oparrays, os_ptr op1) + { + os_ptr op = osp; + ref *arefs = op1->value.refs; +@@ -827,6 +828,12 @@ do_execstack(i_ctx_t *i_ctx_p, bool incl + strlen(tname), (const byte *)tname); + break; + } ++ case t_array: ++ case t_shortarray: ++ case t_mixedarray: ++ if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0) ++ make_null(rq); ++ break; + default: + ; + } +@@ -839,14 +846,14 @@ execstack_continue(i_ctx_t *i_ctx_p) + { + os_ptr op = osp; + +- return do_execstack(i_ctx_p, false, op); ++ return do_execstack(i_ctx_p, false, false, op); + } + static int + execstack2_continue(i_ctx_t *i_ctx_p) + { + os_ptr op = osp; + +- return do_execstack(i_ctx_p, op->value.boolval, op - 1); ++ return do_execstack(i_ctx_p, op->value.boolval, true, op - 1); + } + + /* - .needinput - */ +diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18073 ghostscript-9.07/Resource/Init/gs_init.ps +--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18073 2018-12-05 15:15:27.073274252 +0100 ++++ ghostscript-9.07/Resource/Init/gs_init.ps 2018-12-05 15:18:55.848645627 +0100 +@@ -839,12 +839,26 @@ userdict /.currentresourcefile //null pu + /.runstring { + 0 0 .systemvmstring .systemvmSFD cvx { .runexec } execute0 + } bind def ++ + % Define the procedure that the C code uses to set up for executing + % a string that may be received in pieces. ++% ++% Immediate evaluation doesn't work on operators (like .needinput) ++% so calling .runstringbegin will throw an undefined error if we ++% undefined .needinput so it cannot be accessed outside the init ++% code. But, we can store the operator in an array, use immediate ++% evaluation on the array to get the operator, then undefined the ++% array (and because they are both of the same name, the operator ++% get undefined too). ++% This prevents random Postscript from erroneously calling .needinput ++% and forcing the interpreter into an invalid state. ++/.needinput ++1 .systemvmarray dup 0 /.needinput load put ++def + /.runstringbegin { +- 1 .systemvmarray dup 0 /.needinput load put cvx % { .needinput } in systemvm ++ 1 .systemvmarray dup 0 //.needinput 0 get put cvx % { .needinput } in systemvm + 0 0 .systemvmstring .systemvmSFD cvx .runexec +-} bind def ++} bind executeonly def + + % Define a special version of runlibfile that aborts on errors. + /runlibfile0 +@@ -2147,7 +2161,7 @@ SAFER { .setsafe } if + %% but can be easily restored (just delete the name from the list in the array). In future + %% we may remove the operator and the code implementation entirely. + [ +-/.bitadd /.charboxpath /.currentblackptcomp /.setblackptcomp /.cond /.countexecstack /.execstack /.runandhide /.popdevicefilter ++/.bitadd /.charboxpath /.cond /.runandhide /.popdevicefilter + /.execfile /.filenamesplit /.file_name_parent + /.setdefaultmatrix /.isprocfilter /.unread /.psstringencode + /.buildsampledfunction /.isencapfunction /.currentaccuratecurves /.currentcurvejoin /.currentdashadapt /.currentdotlength +@@ -2186,6 +2200,7 @@ SAFER { .setsafe } if + /.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 /.currentoutputdevice ++/.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +@@ -2204,7 +2219,7 @@ SAFER { .setsafe } if + % test files/utilities, or engineers expressed a desire to keep them visible. + % + %/currentdevice /.sort /.buildfont0 /.buildfont1 /.buildfont2 /.buildfont3 /.buildfont4 /.buildfont9 /.buildfont10 /.buildfont11 +-%/.buildfotn32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors ++%/.buildfont32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors + %/currentdevice /.quit /.setuseciecolor /.needinput /.setoverprintmode /.special_op /.dicttomark /.knownget + %/.FAPIavailable /.FAPIpassfont /.FAPIrebuildfont /.FAPIBuildGlyph /.FAPIBuildChar /.FAPIBuildGlyph9 + %/.tempfile /.numicc_components /.set_outputintent /.max /.min /.vmreclaim /.getpath /.setglobal +diff -up ghostscript-9.07/Resource/Init/gs_resmp.ps.cve-2018-18073 ghostscript-9.07/Resource/Init/gs_resmp.ps +--- ghostscript-9.07/Resource/Init/gs_resmp.ps.cve-2018-18073 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_resmp.ps 2018-12-05 15:15:27.078274212 +0100 +@@ -183,7 +183,7 @@ setpacking + % We don't check them. + + currentglobal //false setglobal % bGlobal +- countexecstack array execstack % bGlobal [execstack] ++ //false .countexecstack array //false .execstack % bGlobal [execstack] + dup //null exch % bGlobal [execstack] null [execstack] + length 3 sub -1 0 { % bGlobal [execstack] null i + 2 index exch get % bGlobal [execstack] null proc diff --git a/SOURCES/ghostscript-cve-2018-18284.patch b/SOURCES/ghostscript-cve-2018-18284.patch new file mode 100644 index 0000000..9f91d78 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-18284.patch @@ -0,0 +1,226 @@ +From: Ken Sharp +Date: Mon, 15 Oct 2018 10:28:28 +0000 (+0100) +Subject: Make .forceput unavailable from '.policyprocs' helper dictionary + +Make .forceput unavailable from '.policyprocs' helper dictionary + +Bug #69963 "1Policy is a dangerous operator, any callers should be odef" + +Leaving the .policyprocs dictionary with a procedure which is a simple +wrapper for .forceput effectively leaves .forceput available. + +It seems that the only reason to have .policyprocs is to minimise the +code in .applypolicies, so we can remove the dictionary and put the +code straight into .applypolicies, which we can then bind and make +executeonly, which hides the .forceput. Also, since we don't need +.applypolicies after startup, we can undefine that from systemdict too. + +While we're here, review all the uses of .force* to make certain that +there are no other similar cases. This showed a few places where we +hadn't made a function executeonly, so do that too. Its probably not +required, since I'm reasonably sure its impossible to load those +functions as packed arrays (they are all defined as operators), but lets +have a belt and braces approach, the additional time cost is negligible. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=8d19fdf63f91f50466b08f23e2d93d37a4c5ea0b +--- + +diff -up ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_diskn.ps +--- ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-18284 2018-12-05 18:48:43.460994455 +0100 ++++ ghostscript-9.07/Resource/Init/gs_diskn.ps 2018-12-05 18:49:15.314745554 +0100 +@@ -61,7 +61,7 @@ systemdict begin + % doesn't get run enough to justify the complication + //.putdevparams + //systemdict /.searchabledevs .forceundef +-} .bind odef % must be bound and hidden for .forceundef ++} .bind executeonly odef % must be bound and hidden for .forceundef + + % ------ extend filenameforall to handle wildcards in %dev% part of pattern -------% + /filenameforall { +diff -up ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_dps.ps +--- ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-18284 2018-12-05 18:48:43.460994455 +0100 ++++ ghostscript-9.07/Resource/Init/gs_dps.ps 2018-12-05 18:48:43.471994369 +0100 +@@ -125,7 +125,7 @@ + /savedinitialgstate .systemvar setgstate gsave + % Wrap up. + end .setglobal +-} odef ++} bind executeonly odef + + % Check whether an object is a procedure. + /.proccheck { % .proccheck +diff -up ghostscript-9.07/Resource/Init/gs_epsf.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_epsf.ps +--- ghostscript-9.07/Resource/Init/gs_epsf.ps.cve-2018-18284 2013-02-14 08:58:16.000000000 +0100 ++++ ghostscript-9.07/Resource/Init/gs_epsf.ps 2018-12-05 18:48:43.472994362 +0100 +@@ -31,7 +31,7 @@ + /EPSBoundingBoxState 5 def + /EPSBoundingBoxSetState { + //systemdict /EPSBoundingBoxState 3 -1 roll .forceput +-} .bind odef % .forceput must be bound and hidden ++} .bind executeonly odef % .forceput must be bound and hidden + + % Parse 4 numbers for a bounding box + /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false +diff -up ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_fonts.ps +--- ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-18284 2018-12-05 18:48:43.461994448 +0100 ++++ ghostscript-9.07/Resource/Init/gs_fonts.ps 2018-12-05 18:48:43.472994362 +0100 +@@ -572,7 +572,7 @@ buildfontdict 3 /.buildfont3 cvx put + } bind def + /.setloadingfont { + //systemdict /.loadingfont 3 -1 roll .forceput +-} .bind odef % .forceput must be bound and hidden ++} .bind executeonly odef % .forceput must be bound and hidden + /.loadfont + { % Some buggy fonts leave extra junk on the stack, + % so we have to make a closure that records the stack depth +@@ -985,7 +985,7 @@ $error /SubstituteFont { } put + dup length string copy + .forceput setglobal + } ifelse +-} .bind odef % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Attempt to load a font from a file. + /.tryloadfont { % .tryloadfont true +diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_init.ps +--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18284 2018-12-05 18:48:43.454994502 +0100 ++++ ghostscript-9.07/Resource/Init/gs_init.ps 2018-12-05 18:48:43.473994354 +0100 +@@ -2200,7 +2200,7 @@ SAFER { .setsafe } if + /.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 /.currentoutputdevice +-/.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack ++/.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack /.applypolicies + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_setpd.ps +--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-18284 2018-12-05 18:48:43.462994440 +0100 ++++ ghostscript-9.07/Resource/Init/gs_setpd.ps 2018-12-05 18:48:43.473994354 +0100 +@@ -545,6 +545,23 @@ NOMEDIAATTRS { + % and we replace the key in the dictionary with its prior value + % (or remove it if it had no prior value). + ++% These procedures are called with the following on the stack: ++% ++% They are expected to consume the top 2 operands. ++% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) ++% the same as 0, i.e., we signal an error. ++/0Policy { % Set errorinfo and signal a configurationerror. ++ NOMEDIAATTRS { ++ % NOMEDIAATTRS means that the default policy is 7... ++ pop 2 index exch 7 put ++ } { ++ pop dup 4 index exch get 2 array astore ++ $error /errorinfo 3 -1 roll put ++ cleartomark ++ /setpagedevice .systemvar /configurationerror signalerror ++ } ifelse ++} bind executeonly odef ++ + % Making this an operator means we can properly hide + % the contents - specifically .forceput + /1Policy +@@ -553,59 +570,46 @@ NOMEDIAATTRS { + SETPDDEBUG { (Rolling back.) = pstack flush } if + 3 index 2 index 3 -1 roll .forceput + 4 index 1 index .knownget +- { 4 index 3 1 roll .forceput } +- { 3 index exch .undef } ++ { 4 index 3 1 roll .forceput } ++ { 3 index exch .undef } + ifelse + } bind executeonly odef + +-/.policyprocs mark +-% These procedures are called with the following on the stack: +-% +-% They are expected to consume the top 2 operands. +-% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) +-% the same as 0, i.e., we signal an error. +-% +-% M. Sweet, Easy Software Products: +-% +-% Define NOMEDIAATTRS to turn off the default (but unimplementable) media +-% selection policies for setpagedevice. This is used by CUPS to support +-% the standard Adobe media attributes. +- 0 { % Set errorinfo and signal a configurationerror. +- NOMEDIAATTRS { +- % NOMEDIAATTRS means that the default policy is 7... +- pop 2 index exch 7 put +- } { +- pop dup 4 index exch get 2 array astore +- $error /errorinfo 3 -1 roll put +- cleartomark +- /setpagedevice .systemvar /configurationerror signalerror +- } ifelse +- } bind +- 1 /1Policy load +- 7 { % For PageSize only, just impose the request. +- 1 index /PageSize eq +- { pop pop 1 index /PageSize 7 put } +- { .policyprocs 0 get exec } +- ifelse +- } bind +-.dicttomark readonly def +-currentdict /1Policy undef ++/7Policy { % For PageSize only, just impose the request. ++ 1 index /PageSize eq ++ { pop pop 1 index /PageSize 7 put } ++ { .policyprocs 0 get exec } ++ ifelse ++} bind executeonly odef + + /.applypolicies % .applypolicies + % +- { 1 index /Policies get 1 index +- { type /integertype eq +- { pop % already processed +- } +- { 2 copy .knownget not { 1 index /PolicyNotFound get } if +- % Stack: +- % +- .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec +- } +- ifelse +- } +- forall pop +- } bind def ++{ ++ 1 index /Policies get 1 index ++ { type /integertype eq ++ { ++ pop % already processed ++ }{ ++ 2 copy .knownget not { 1 index /PolicyNotFound get } if ++ % Stack: ++ % ++ dup 1 eq { ++ 1Policy ++ }{ ++ dup 7 eq { ++ 7Policy ++ }{ ++ 0Policy ++ } ifelse ++ } ifelse ++ } ifelse ++ } ++ forall pop ++} bind executeonly odef ++ ++currentdict /0Policy undef ++currentdict /1Policy undef ++currentdict /7Policy undef + + % Prepare to present parameters to the device, by spreading them onto the + % operand stack and removing any that shouldn't be presented. +@@ -907,7 +911,7 @@ SETPDDEBUG { (Installing.) = pstack flus + } { + .postinstall + } ifelse +-} odef ++} bind executeonly odef + + % We break out the code after calling the Install procedure into a + % separate procedure, since it is executed even if Install causes an error. diff --git a/SOURCES/ghostscript-cve-2018-19134.patch b/SOURCES/ghostscript-cve-2018-19134.patch new file mode 100644 index 0000000..948c993 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19134.patch @@ -0,0 +1,110 @@ +From: Ken Sharp +Date: Thu, 8 Nov 2018 14:43:32 +0000 (+0000) +Subject: PS interpreter - check the Implementation of a Pattern before use + +PS interpreter - check the Implementation of a Pattern before use + +Bug #700141 "Type confusion in setpattern" + +As the bug thread says, we were not checking that the Implementation +of a pattern dictionary was a structure type, leading to a crash when +we tried to treat it as one. + +Here we make the st_pattern1_instance and st_pattern2_instance +structures public definitions and in zsetcolor we check the object +stored under the Implementation key in the supplied dictionary to see if +its a t_struct or t_astruct type, and if it is that its a +st_pattern1_instance or st_pattern2_instance structure. + +If either check fails we throw a typecheck error. + +We need to make the st_pattern1_instance and st_pattern2_instance +definitions public as they are defined in the graphics library and we +need to check in the interpreter. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=693baf02152119af6e6afd30bb8ec76d14f84bbf +--- + +diff -up ghostscript-9.07/base/gsptype1.c.cve-2018-19134 ghostscript-9.07/base/gsptype1.c +--- ghostscript-9.07/base/gsptype1.c.cve-2018-19134 2018-12-06 14:24:51.562580221 +0100 ++++ ghostscript-9.07/base/gsptype1.c 2018-12-06 14:25:19.570310740 +0100 +@@ -50,7 +50,7 @@ + + /* GC descriptors */ + private_st_pattern1_template(); +-private_st_pattern1_instance(); ++public_st_pattern1_instance(); + + /* GC procedures */ + static ENUM_PTRS_BEGIN(pattern1_instance_enum_ptrs) { +diff -up ghostscript-9.07/base/gsptype2.c.cve-2018-19134 ghostscript-9.07/base/gsptype2.c +--- ghostscript-9.07/base/gsptype2.c.cve-2018-19134 2018-12-06 14:25:51.442004068 +0100 ++++ ghostscript-9.07/base/gsptype2.c 2018-12-06 14:27:26.160092718 +0100 +@@ -33,7 +33,7 @@ + + /* GC descriptors */ + private_st_pattern2_template(); +-private_st_pattern2_instance(); ++public_st_pattern2_instance(); + + /* GC procedures */ + static ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs) { +@@ -208,7 +208,7 @@ gs_pattern2_set_color(const gs_client_co + + num_comps = pgs->device->color_info.num_components; + for (k = 0; k < num_comps; k++) { +- pgs->color_component_map.color_map[k] = ++ pgs->color_component_map.color_map[k] = + pinst->saved->color_component_map.color_map[k]; + } + code = pcs->type->set_overprint(pcs, pgs); +diff -up ghostscript-9.07/base/gsptype2.h.cve-2018-19134 ghostscript-9.07/base/gsptype2.h +--- ghostscript-9.07/base/gsptype2.h.cve-2018-19134 2018-12-06 14:28:16.159611632 +0100 ++++ ghostscript-9.07/base/gsptype2.h 2018-12-06 14:28:53.499252361 +0100 +@@ -57,8 +57,8 @@ typedef struct gs_pattern2_instance_s { + bool shfill; + } gs_pattern2_instance_t; + +-#define private_st_pattern2_instance() /* in gsptype2.c */\ +- gs_private_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ ++#define public_st_pattern2_instance() /* in gsptype2.c */\ ++ gs_public_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ + "gs_pattern2_instance_t", pattern2_instance_enum_ptrs,\ + pattern2_instance_reloc_ptrs) + +diff -up ghostscript-9.07/base/gxcolor2.h.cve-2018-19134 ghostscript-9.07/base/gxcolor2.h +--- ghostscript-9.07/base/gxcolor2.h.cve-2018-19134 2018-12-06 14:29:16.623029864 +0100 ++++ ghostscript-9.07/base/gxcolor2.h 2018-12-06 14:29:49.115717229 +0100 +@@ -92,8 +92,8 @@ struct gs_pattern1_instance_s { + gx_bitmap_id id; /* key for cached bitmap (= id of mask) */ + }; + +-#define private_st_pattern1_instance() /* in gsptype1.c */\ +- gs_private_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ ++#define public_st_pattern1_instance() /* in gsptype1.c */\ ++ gs_public_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ + "gs_pattern1_instance_t", pattern1_instance_enum_ptrs,\ + pattern1_instance_reloc_ptrs) + +diff -up ghostscript-9.07/psi/zcolor.c.cve-2018-19134 ghostscript-9.07/psi/zcolor.c +--- ghostscript-9.07/psi/zcolor.c.cve-2018-19134 2018-12-06 14:30:27.229350513 +0100 ++++ ghostscript-9.07/psi/zcolor.c 2018-12-06 14:31:52.650528604 +0100 +@@ -57,6 +57,8 @@ + + /* imported from gsht.c */ + extern void gx_set_effective_transfer(gs_state *); ++extern_st(st_pattern1_instance); ++extern_st(st_pattern2_instance); + + /* Essential forward declarations */ + static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth); +@@ -283,6 +285,9 @@ zsetcolor(i_ctx_t * i_ctx_p) + code = array_get(imemory, pImpl, 0, &pPatInst); + if (code < 0) + return code; ++ if (!r_is_struct(&pPatInst) || (!r_has_stype(&pPatInst, imemory, st_pattern1_instance) && !r_has_stype(&pPatInst, imemory, st_pattern2_instance))) ++ return_error(gs_error_typecheck); ++ + cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t); + n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern) + ? n_comps - 1 diff --git a/SOURCES/ghostscript-cve-2018-19409.patch b/SOURCES/ghostscript-cve-2018-19409.patch new file mode 100644 index 0000000..cbec39a --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19409.patch @@ -0,0 +1,257 @@ +From: Chris Liddell +Date: Wed, 14 Nov 2018 09:50:08 +0000 (+0000) +Subject: Bug 700176: check the *output* device for LockSafetyParams + +Bug 700176: check the *output* device for LockSafetyParams + +When calling .setdevice we were checking if LockSafetyParams was set, and if so +throwing an invalidaccess error. + +The problem is, if another device, for example the pdf14 compositor is the 'top' +device, that does not (and cannot) honour LockSafetyParams. + +To solve this, we'll now use the (relatively new) gxdso_current_output_device +spec_op to retrieve the *actual* output device, and check the LockSafetyParams +flag in that. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=661e8d8fb8248c38d67958beda32f3a5876d0c3f + +From: Chris Liddell +Date: Wed, 14 Nov 2018 21:04:46 +0000 (+0000) +Subject: Bug 700176: Use the actual output device for both devices in setdevice + +Bug 700176: Use the actual output device for both devices in setdevice + +Also fixes bug 700189. + +The pdf14 compositor device, despite being a forwarding device, does not forward +all spec_ops to it's target, only a select few are special cased for that. +gxdso_current_output_device needs to be included in those special cases. + +The original commit (661e8d8fb8248) changed the code to use the spec_op to +retrieve the output device, checking that for LockSafetyParams. If +LockSafetyParams is set, it returns an invalidaccess error if the new device +differs from the current device. + +When we do the comparison between the two devices, we need to check the +output device in both cases. + +This is complicated by the fact that the new device may not have ever been set +(and thus fully initialised), and may not have a spec_op method available at +that point. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=ea1b3ef437f39e45874f821c06bd953196625ac5 + +From: Chris Liddell +Date: Mon, 17 Sep 2018 13:06:12 +0000 (+0100) +Subject: Implement .currentoutputdevice operator + +Implement .currentoutputdevice operator + +The currentdevice operator returns the device currently installed in the +graphics state. This can be the output/page device, but also could be a +forwarding device (bbox device), compositor (pdf14) or subclass device +(erasepage optimisation, First/Last page etc). + +In certain circumstances (for example during a setpagedevice) we want to be +sure we're retrieving the *actual* output/page device. + +The new .currentoutputdevice operator uses the spec_op device method to traverse +any chain of devices and retrieve the final device in the chain, which +should always be the output/page device. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=7c3e7eee829cc3d2582e4aa7ae1fd495ca72cef1 + +From: Ken Sharp +Date: Mon, 19 Nov 2018 09:00:54 +0000 (+0000) +Subject: Coverity ID 327264 - move pointer NULL check + +Coverity ID 327264 - move pointer NULL check + +Due to recent changes in this code, the pointer was being dereferenced +before we checked it to see if it was NULL. Moe the check so that we +check for NULL before dereferencing. + +The 'pvalue' of the operand can be NULL, even if the object is a t_device +type, because invalidate_stack_devices traverses the operand stack +looking for devices, and sets their pvalue member to NULL in order to +invalidate them so that they cannot be used. + +https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=a4228a0d8d657fca3bb3becb93a43fae061beae8 +--- + +diff -up ghostscript-9.07/base/gdevdflt.c.cve-2018-19409 ghostscript-9.07/base/gdevdflt.c +--- ghostscript-9.07/base/gdevdflt.c.cve-2018-19409 2013-02-14 08:58:13.000000000 +0100 ++++ ghostscript-9.07/base/gdevdflt.c 2018-11-29 12:42:59.882160045 +0100 +@@ -954,6 +954,11 @@ gx_default_dev_spec_op(gx_device *pdev, + return 4; + } + return 0; /* Otherwise no change */ ++ case gxdso_current_output_device: ++ { ++ *(gx_device **)data = pdev; ++ return 0; ++ } + } + return gs_error_undefined; + } +diff -up ghostscript-9.07/base/gdevp14.c.cve-2018-19409 ghostscript-9.07/base/gdevp14.c +--- ghostscript-9.07/base/gdevp14.c.cve-2018-19409 2018-11-29 12:42:59.784161429 +0100 ++++ ghostscript-9.07/base/gdevp14.c 2018-11-29 13:15:49.265339432 +0100 +@@ -5089,6 +5089,11 @@ pdf14_dev_spec_op(gx_device *pdev, int d + return 0; + } + } ++ if (dev_spec_op == gxdso_current_output_device) { ++ gx_device * target = ((gx_device_forward *)pdev)->target; ++ return dev_proc(target, dev_spec_op)(target, dev_spec_op, data, size); ++ } ++ + return gx_default_dev_spec_op(pdev, dev_spec_op, data, size); + } + +diff -up ghostscript-9.07/base/gxdevsop.h.cve-2018-19409 ghostscript-9.07/base/gxdevsop.h +--- ghostscript-9.07/base/gxdevsop.h.cve-2018-19409 2013-02-14 08:58:13.000000000 +0100 ++++ ghostscript-9.07/base/gxdevsop.h 2018-11-29 12:42:59.884160017 +0100 +@@ -253,6 +253,10 @@ enum { + * Return 0 for 'no special treatment', or 1 for the anitdropout + * downscaler. */ + gxdso_interpolate_antidropout, ++ /* Retrieve the last device in a device chain ++ (either forwarding or subclass devices). ++ */ ++ gxdso_current_output_device, + /* Add new gxdso_ keys above this. */ + gxdso_pattern__LAST + }; +diff -up ghostscript-9.07/psi/zdevice.c.cve-2018-19409 ghostscript-9.07/psi/zdevice.c +--- ghostscript-9.07/psi/zdevice.c.cve-2018-19409 2013-02-14 08:58:13.000000000 +0100 ++++ ghostscript-9.07/psi/zdevice.c 2018-11-29 12:42:59.884160017 +0100 +@@ -34,6 +34,7 @@ + #include "gxgetbit.h" + #include "store.h" + #include "gsicc_manage.h" ++#include "gxdevsop.h" + + /* .copydevice2 */ + static int +@@ -56,6 +57,7 @@ zcopydevice2(i_ctx_t *i_ctx_p) + } + + /* - currentdevice */ ++/* Returns the current device in the graphics state */ + int + zcurrentdevice(i_ctx_t *i_ctx_p) + { +@@ -70,6 +72,34 @@ zcurrentdevice(i_ctx_t *i_ctx_p) + return 0; + } + ++/* - .currentoutputdevice */ ++/* Returns the *output* device - which will often ++ be the same as above, but not always: if a compositor ++ or other forwarding device, or subclassing device is ++ in force, that will be referenced by the graphics state ++ rather than the output device. ++ This is equivalent of currentdevice device, but returns ++ the *device* object, rather than the dictionary describing ++ the device and device state. ++ */ ++static int ++zcurrentoutputdevice(i_ctx_t *i_ctx_p) ++{ ++ os_ptr op = osp; ++ gx_device *odev = NULL, *dev = gs_currentdevice(igs); ++ gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory; ++ int code = dev_proc(dev, dev_spec_op)(dev, ++ gxdso_current_output_device, (void *)&odev, 0); ++ if (code < 0) ++ return code; ++ ++ push(1); ++ make_tav(op, t_device, ++ (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all, ++ pdevice, odev); ++ return 0; ++} ++ + /* .devicename */ + static int + zdevicename(i_ctx_t *i_ctx_p) +@@ -450,13 +480,34 @@ zputdeviceparams(i_ctx_t *i_ctx_p) + int + zsetdevice(i_ctx_t *i_ctx_p) + { +- gx_device *dev = gs_currentdevice(igs); ++ gx_device *odev = NULL, *dev = gs_currentdevice(igs); ++ gx_device *ndev = NULL; + os_ptr op = osp; +- int code = 0; ++ int code = dev_proc(dev, dev_spec_op)(dev, ++ gxdso_current_output_device, (void *)&odev, 0); + ++ if (code < 0) ++ return code; + check_write_type(*op, t_device); +- if (dev->LockSafetyParams) { /* do additional checking if locked */ +- if(op->value.pdevice != dev) /* don't allow a different device */ ++ ++ if (op->value.pdevice == 0) ++ return gs_note_error(gs_error_undefined); ++ ++ /* slightly icky special case: the new device may not have had ++ * it's procs initialised, at this point - but we need to check ++ * whether we're being asked to change the device here ++ */ ++ if (dev_proc((op->value.pdevice), dev_spec_op) == NULL) ++ ndev = op->value.pdevice; ++ else ++ code = dev_proc((op->value.pdevice), dev_spec_op)(op->value.pdevice, ++ gxdso_current_output_device, (void *)&ndev, 0); ++ ++ if (code < 0) ++ return code; ++ ++ if (odev->LockSafetyParams) { /* do additional checking if locked */ ++ if(ndev != odev) /* don't allow a different device */ + return_error(e_invalidaccess); + } + #ifndef PSI_INCLUDED +@@ -480,6 +531,7 @@ const op_def zdevice_op_defs[] = + { + {"1.copydevice2", zcopydevice2}, + {"0currentdevice", zcurrentdevice}, ++ {"0.currentoutputdevice", zcurrentoutputdevice}, + {"1.devicename", zdevicename}, + {"0.doneshowpage", zdoneshowpage}, + {"0flushpage", zflushpage}, +diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-19409 ghostscript-9.07/Resource/Init/gs_init.ps +--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-19409 2018-11-29 12:42:59.873160172 +0100 ++++ ghostscript-9.07/Resource/Init/gs_init.ps 2018-11-29 12:42:59.884160017 +0100 +@@ -2160,7 +2160,7 @@ SAFER { .setsafe } if + /.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 ++/.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-19409 ghostscript-9.07/Resource/Init/gs_setpd.ps +--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-19409 2018-11-29 12:42:59.880160073 +0100 ++++ ghostscript-9.07/Resource/Init/gs_setpd.ps 2018-11-29 12:42:59.885160002 +0100 +@@ -772,7 +772,13 @@ SETPDDEBUG { (Selecting.) = pstack flush + % Stack: mark + SETPDDEBUG { (Constructing.) = pstack flush } if + +- currentdevice .devicename 2 index /OutputDevice get eq ++ % Non-obvious: we need to check the name of the output device, to tell ++ % whether we're going to have to replace the entire device chain (which ++ % may be only one device, or may be multiple devices. ++ % If we're not replacing the entire change, we have to use the device in ++ % the graphics state, so the configuration of the entire device chain is ++ % correctly set. ++ .currentoutputdevice .devicename 2 index /OutputDevice get eq + { currentdevice } + { 1 index /OutputDevice get finddevice } + ifelse diff --git a/SPECS/ghostscript.spec b/SPECS/ghostscript.spec index 8f76361..47efee6 100644 --- a/SPECS/ghostscript.spec +++ b/SPECS/ghostscript.spec @@ -5,7 +5,7 @@ Summary: A PostScript interpreter and renderer Name: ghostscript Version: %{gs_ver} -Release: 31%{?dist}.3 +Release: 31%{?dist}.6 # Included CMap data is Redistributable, no modification permitted, # see http://bugzilla.redhat.com/487510 @@ -71,6 +71,15 @@ Patch43: ghostscript-cve-2018-16539.patch Patch44: ghostscript-cve-2018-15908.patch Patch45: ghostscript-cve-2018-15909.patch Patch46: ghostscript-cve-2018-16863.patch +Patch48: ghostscript-cve-2018-15911.patch +Patch49: ghostscript-cve-2018-16802.patch +Patch50: ghostscript-cve-2018-19409.patch +Patch51: ghostscript-cve-2018-16541.patch +Patch52: ghostscript-cve-2018-17183.patch +Patch53: ghostscript-cve-2018-18073.patch +Patch54: ghostscript-cve-2018-17961.patch +Patch55: ghostscript-cve-2018-18284.patch +Patch56: ghostscript-cve-2018-19134.patch # Upstream is not versioning the SONAME correctly, thus the rpmbuild is unable # to recognize we need a newer version of lcms2. This 'hackish' workaround @@ -301,6 +310,33 @@ rm -rf expat freetype icclib jasper jpeg lcms lcms2 libpng openjpeg zlib cups/li # ghostscript update breaks xdvi (gs: Error: /undefined in flushpage) (bug #1654290): %patch47 -p1 +# CVE-2018-15911 (bug #1651149): +%patch48 -p1 + +# CVE-2018-16802 (bug #1650060): +%patch49 -p1 + +# CVE-2018-19409 (bug #1652935): +%patch50 -p1 + +# CVE-2018-16541 (bug #1654621): +%patch51 -p1 + +# CVE-2018-17183 (bug #1650210): +%patch52 -p1 + +# CVE-2018-18073 (bug #1645516): +%patch53 -p1 + +# CVE-2018-17961 (bug #1648891): +%patch54 -p1 + +# CVE-2018-18284 (bug #1643115): +%patch55 -p1 + +# CVE-2018-19134 (bug #1655937): +%patch56 -p1 + # Remove pdfopt man pages which were mistakenly left in (bug #963882). rm man/{de/,}pdfopt.1 @@ -500,6 +536,32 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/libgs.so %changelog +* Mon Dec 10 2018 Martin Osvald - 9.07-31.el7_6.6 +- Resolves: #1657822 - ghostscript: Regression: Warning: Dropping incorrect + smooth shading object (Error: /rangecheck in --run--) + +* Wed Dec 05 2018 Martin Osvald - 9.07-31.el7_6.5 +- Resolves: #1654621 - CVE-2018-16541 ghostscript: incorrect free logic in + pagedevice replacement (699664) +- Resolves: #1650210 - CVE-2018-17183 ghostscript: User-writable error + exception table +- Resolves: #1645516 - CVE-2018-18073 ghostscript: saved execution stacks + can leak operator arrays +- Resolves: #1648891 - CVE-2018-17961 ghostscript: saved execution stacks + can leak operator arrays (incomplete fix for CVE-2018-17183) +- Resolves: #1643115 - CVE-2018-18284 ghostscript: 1Policy operator + allows a sandbox protection bypass +- Resolves: #1655937 - CVE-2018-19134 ghostscript: Type confusion in + setpattern (700141) + +* Thu Nov 29 2018 Martin Osvald - 9.07-31.el7_6.4 +- Resolves: #1651149 - CVE-2018-15911 ghostscript: uninitialized memory + access in the aesdecode operator (699665) +- Resolves: #1650060 - CVE-2018-16802 ghostscript: Incorrect "restoration of + privilege" checking when running out of stack during exception handling +- Resolves: #1652935 - CVE-2018-19409 ghostscript: Improperly implemented + security check in zsetdevice function in psi/zdevice.c + * Wed Nov 28 2018 Martin Osvald - 9.07-31.el7_6.3 - Resolves: #1654290 ghostscript update breaks xdvi (gs: Error: /undefined in flushpage)