Date: Sunday, September 9, 2018 @ 08:39:24 Author: andyrtr Revision: 334268
upgpkg: ghostscript 9.24-6 yet another security fix - FS#59982 Added: ghostscript/trunk/0006_stack_size_space_fix.patch Modified: ghostscript/trunk/PKGBUILD ---------------------------------+ 0006_stack_size_space_fix.patch | 254 ++++++++++++++++++++++++++++++++++++++ PKGBUILD | 10 + 2 files changed, 261 insertions(+), 3 deletions(-) Added: 0006_stack_size_space_fix.patch =================================================================== --- 0006_stack_size_space_fix.patch (rev 0) +++ 0006_stack_size_space_fix.patch 2018-09-09 08:39:24 UTC (rev 334268) @@ -0,0 +1,254 @@ +From 3e5d316b72e3965b7968bb1d96baa137cd063ac6 Mon Sep 17 00:00:00 2001 +From: Chris Liddell <[email protected]> +Date: Wed, 5 Sep 2018 17:14:59 +0100 +Subject: [PATCH] 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. +--- + Resource/Init/gs_setpd.ps | 20 +++++++++++------ + psi/zdevice2.c | 55 ++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 56 insertions(+), 19 deletions(-) + +diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps +index b75c431..8fa7c51 100644 +--- a/Resource/Init/gs_setpd.ps ++++ b/Resource/Init/gs_setpd.ps +@@ -96,7 +96,7 @@ level2dict begin + % we must (carefully) reinstall the old parameters in + % the same device. + .currentpagedevice pop //null currentdevice //null +- {.trysetparams} .internalstopped ++ { .trysetparams } .internalstopped + { + //null + } if +@@ -104,26 +104,32 @@ level2dict begin + { pop pop } + { + 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 pop +- /.LockSafetyParams .knownget not {//false} if .putdeviceparamsonly ++ 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/psi/zdevice2.c b/psi/zdevice2.c +index 0c7080d..5447c8c 100644 +--- a/psi/zdevice2.c ++++ b/psi/zdevice2.c +@@ -251,8 +251,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_gstate * pgs_old, const gs_gstate * pgs_new) ++static int ++restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate * pgs_new) + { + gx_device *dev_old = gs_currentdevice(pgs_old); + gx_device *dev_new; +@@ -260,9 +260,10 @@ restore_page_device(const gs_gstate * pgs_old, const gs_gstate * pgs_new) + 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. */ +@@ -271,23 +272,44 @@ restore_page_device(const gs_gstate * pgs_old, const gs_gstate * pgs_new) + 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) { ++ os_ptr op = osp; ++ const int max_ops = 512; ++ ++ /* 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 (max_ops > op - osbot) { ++ if (max_ops >= ref_stack_count(&o_stack)) ++ return_error(gs_error_stackoverflow); ++ } + } + /* + * 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_gstate_saved(igs))) ++ int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs)); ++ if (code < 0) return code; ++ ++ if (code == 0) + return gs_grestore(igs); + return push_callout(i_ctx_p, "%grestorepagedevice"); + } +@@ -297,7 +319,9 @@ static int + z2grestoreall(i_ctx_t *i_ctx_p) + { + for (;;) { +- if (!restore_page_device(igs, gs_gstate_saved(igs))) { ++ int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs)); ++ if (code < 0) return code; ++ if (code == 0) { + bool done = !gs_gstate_saved(gs_gstate_saved(igs)); + + gs_grestore(igs); +@@ -328,11 +352,15 @@ z2restore(i_ctx_t *i_ctx_p) + if (code < 0) return code; + + while (gs_gstate_saved(gs_gstate_saved(igs))) { +- if (restore_page_device(igs, gs_gstate_saved(igs))) ++ code = restore_page_device(i_ctx_p, igs, gs_gstate_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_gstate_saved(igs))) ++ code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs)); ++ if (code < 0) return code; ++ if (code > 0) + return push_callout(i_ctx_p, "%restorepagedevice"); + + code = dorestore(i_ctx_p, asave); +@@ -355,9 +383,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"); + } +-- +2.9.1 + +From 643b24dbd002fb9c131313253c307cf3951b3d47 Mon Sep 17 00:00:00 2001 +From: Chris Liddell <[email protected]> +Date: Fri, 7 Sep 2018 08:07:12 +0100 +Subject: [PATCH] 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. +--- + psi/zdevice2.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/psi/zdevice2.c b/psi/zdevice2.c +index 5447c8c..159a0c0 100644 +--- a/psi/zdevice2.c ++++ b/psi/zdevice2.c +@@ -278,8 +278,8 @@ restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate + } + + if (LockSafetyParams && !samepagedevice) { +- os_ptr op = osp; +- const int max_ops = 512; ++ 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 +@@ -289,9 +289,16 @@ restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate + 424 entries on the op stack. Allowing for working stack + space, and safety margin..... + */ +- if (max_ops > op - osbot) { +- if (max_ops >= ref_stack_count(&o_stack)) +- return_error(gs_error_stackoverflow); ++ 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); + } + } + /* +-- +2.9.1 + + Modified: PKGBUILD =================================================================== --- PKGBUILD 2018-09-09 08:22:41 UTC (rev 334267) +++ PKGBUILD 2018-09-09 08:39:24 UTC (rev 334268) @@ -4,7 +4,7 @@ pkgbase=ghostscript pkgname=(ghostscript ghostxps ghostpcl) pkgver=9.24 -pkgrel=5 +pkgrel=6 pkgdesc="An interpreter for the PostScript language" url="https://www.ghostscript.com/" arch=('x86_64') @@ -18,13 +18,15 @@ 0002_retain_LockSafetyParams_through_failed_installpagedevice.patch 0003_Fix_SEGV_seen_in_all-devices_test.patch 0004_Add_the_ICCProfilesDir_to_the_PermitReading_list.patch - 0005_add_wildcards_to_the_permissions_paths.patch) + 0005_add_wildcards_to_the_permissions_paths.patch + 0006_stack_size_space_fix.patch) sha512sums=('a0ed7235808ed79ad88ddf0808ef3eb667ffd1b0300ceda78eac3d0ad69d4a963821fa05319ed822db51911210c4fd7d8dbd4d73951e330fbc7b99e4f00a45fa' '6cfdd351e8e84968c20cf8f15e01a09a215b6132af89ca0e392716638d925a0f750dab3dbcbdf44f200fb9cc419be5dadccffc226c9a405e888f3580f98cf4ea' '670ccf36927904fc2e918847baf082753d3b4b81fd0ee2347feb6de5a0ab77eb9c00cb640fcb3c7a0f395694112f3921775a6f614bec08e3d4452155b030951e' '45be77dc890d9d251541d44fe0ad860a7d83d969ce697bbb32cb469d8837417020f1a017ae7aecbb8fbb45647ad9c3e6f92d321c2adfe6c8b3412c580f4058c5' 'e64bcf8e5b5f229ca14463477be21555e66a0f3c76e3c01eb9b4d8cbeebba683b9b33a624ac4617af715c281f93106ae5d8425a29ed35416fbd580242a1a27e0' - '52088ef6ca47c5ed6f34ccac2b5234bcd6561175ef35de90ede7322a98e617b37036bf8a092733bec11fea211c7e3806b98c4019b1a806f6616387ee48002ef3') + '52088ef6ca47c5ed6f34ccac2b5234bcd6561175ef35de90ede7322a98e617b37036bf8a092733bec11fea211c7e3806b98c4019b1a806f6616387ee48002ef3' + '4a09455d2e844cf1e8fc91fdfda5e1dd9160dd0a49bad4b1baea186d858bbdaa01980c81022c8f9fb209c329a3668575c47d879cc44db36df6a39bc86eab0928') prepare() { cd ghostpdl-${pkgver} @@ -42,6 +44,8 @@ # FS#59952;FS#59959 patch -Np1 -i ../0004_Add_the_ICCProfilesDir_to_the_PermitReading_list.patch patch -Np1 -i ../0005_add_wildcards_to_the_permissions_paths.patch + # FS#59982 + patch -Np1 -i ../0006_stack_size_space_fix.patch } build() {
