From: Ken Sharp Date: Mon, 15 Oct 2018 12:35:15 +0000 (+0100) Subject: font parsing - prevent SEGV in .cffparse font parsing - prevent SEGV in .cffparse Bug #699961 "currentcolortransfer procs crash .parsecff" zparsecff checked the operand for being an array (and not a packed array) but the returned procedures from the default currentcolortransfer are arrays, not packed arrays. This led to the code trying to dereference a NULL pointer. Add a specific check for the 'refs' pointer being NULL before we try to use it. Additionally, make the StartData procedure in the CFF Font Resource executeonly to prevent pulling the hidden .parsecff operator out and using it. Finally, extend this to other resource types. https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=30cd347f37bfb293ffdc407397d1023628400b81 From: Chris Liddell Date: Fri, 19 Oct 2018 12:14:24 +0000 (+0100) Subject: "Hide" a final use of a .force* operator "Hide" a final use of a .force* operator There was one use of .forceput remaining that was in a regular procedure rather than being "hidden" behind an operator. In this case, it's buried in the resource machinery, and hard to access (I would not be confident in claiming it was impossible). This ensures it's not accessible. https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=8e18fcdaa2e2247363c4cc8f851f3096cc5756fa From: Chris Liddell Date: Wed, 5 Dec 2018 12:22:13 +0000 (+0000) Subject: Sanitize op stack for error conditions Sanitize op stack for error conditions We save the stacks to an array and store the array for the error handler to access. For SAFER, we traverse the array, and deep copy any op arrays (procedures). As we make these copies, we check for operators that do *not* exist in systemdict, when we find one, we replace the operator with a name object (of the form "/--opname--"). https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=13b0a36f8181db66a91bcc8cea139998b53a8996 From: Chris Liddell Date: Thu, 13 Dec 2018 15:28:34 +0000 (+0000) Subject: Any transient procedures that call .force* operators Any transient procedures that call .force* operators (i.e. for conditionals or loops) make them executeonly. https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=2db98f9c66135601efb103d8db7d020a672308db From: Chris Liddell Date: Sat, 15 Dec 2018 09:08:32 +0000 (+0000) Subject: Bug700317: Fix logic for an older change Bug700317: Fix logic for an older change Unlike almost every other function in gs, dict_find_string() returns 1 on success 0 or <0 on failure. The logic for this case was wrong. https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=99f13091a3f309bdc95d275ea9fec10bb9f42d9a From: Chris Liddell Date: Tue, 18 Dec 2018 10:42:10 +0000 (+0000) Subject: Harden some uses of .force* operators Harden some uses of .force* operators by adding a few immediate evalutions https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=59d8f4deef90c1598ff50616519d5576756b4495 --- diff -up ghostscript-9.07/psi/interp.c.cve-2019-6116 ghostscript-9.07/psi/interp.c --- ghostscript-9.07/psi/interp.c.cve-2019-6116 2019-03-05 11:28:18.238244540 +0100 +++ ghostscript-9.07/psi/interp.c 2019-03-05 11:28:18.295243766 +0100 @@ -692,7 +692,7 @@ again: * i.e. it's an internal operator we have hidden */ code = dict_find_string(systemdict, (const char *)bufptr, &tobj); - if (code < 0) { + if (code <= 0) { buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; rlen += 4; bufptr = buf; @@ -751,6 +751,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, i; + ref *safety, *safe; if (size > 65535) size = 65535; @@ -768,6 +769,13 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_s make_null(&arr->value.refs[i]); } } + if (pstack == &o_stack && dict_find_string(systemdict, "SAFETY", &safety) > 0 && + dict_find_string(safety, "safe", &safe) > 0 && r_has_type(safe, t_boolean) && + safe->value.boolval == true) { + code = ref_stack_array_sanitize(i_ctx_p, arr, arr); + if (code < 0) + return code; + } ialloc_set_space(idmemory, save_space); return code; } diff -up ghostscript-9.07/psi/int.mak.cve-2019-6116 ghostscript-9.07/psi/int.mak --- ghostscript-9.07/psi/int.mak.cve-2019-6116 2019-03-05 11:28:18.265244173 +0100 +++ ghostscript-9.07/psi/int.mak 2019-03-05 11:28:18.296243753 +0100 @@ -199,7 +199,7 @@ $(PSOBJ)iparam.$(OBJ) : $(PSSRC)iparam.c $(PSOBJ)istack.$(OBJ) : $(PSSRC)istack.c $(GH) $(memory__h)\ $(ierrors_h) $(gsstruct_h) $(gsutil_h)\ $(ialloc_h) $(istack_h) $(istkparm_h) $(istruct_h) $(iutil_h) $(ivmspace_h)\ - $(store_h) + $(store_h) $(icstate_h) $(iname_h) $(dstack_h) $(idict_h) $(PSCC) $(PSO_)istack.$(OBJ) $(C_) $(PSSRC)istack.c $(PSOBJ)iutil.$(OBJ) : $(PSSRC)iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\ diff -up ghostscript-9.07/psi/istack.c.cve-2019-6116 ghostscript-9.07/psi/istack.c --- ghostscript-9.07/psi/istack.c.cve-2019-6116 2013-02-14 08:58:13.000000000 +0100 +++ ghostscript-9.07/psi/istack.c 2019-03-05 11:28:18.297243739 +0100 @@ -27,6 +27,10 @@ #include "iutil.h" #include "ivmspace.h" /* for local/global test */ #include "store.h" +#include "icstate.h" +#include "iname.h" +#include "dstack.h" +#include "idict.h" /* Forward references */ static void init_block(ref_stack_t *pstack, const ref *pblock_array, @@ -283,6 +287,80 @@ ref_stack_store_check(const ref_stack_t return 0; } +int +ref_stack_array_sanitize(i_ctx_t *i_ctx_p, ref *sarr, ref *darr) +{ + int i, code; + ref obj, arr2; + ref *pobj2; + gs_memory_t *mem = (gs_memory_t *)idmemory->current; + + if (!r_is_array(sarr) || !r_has_type(darr, t_array)) + return_error(gs_error_typecheck); + + for (i = 0; i < r_size(sarr); i++) { + code = array_get(mem, sarr, i, &obj); + if (code < 0) + make_null(&obj); + switch(r_type(&obj)) { + case t_operator: + { + int index = op_index(&obj); + + if (index > 0 && index < op_def_count) { + const byte *data = (const byte *)(op_index_def(index)->oname + 1); + if (dict_find_string(systemdict, (const char *)data, &pobj2) <= 0) { + byte *s = gs_alloc_bytes(mem, strlen((char *)data) + 5, "ref_stack_array_sanitize"); + if (s) { + s[0] = '\0'; + strcpy((char *)s, "--"); + strcpy((char *)s + 2, (char *)data); + strcpy((char *)s + strlen((char *)data) + 2, "--"); + } + else { + s = (byte *)data; + } + code = name_ref(imemory, s, strlen((char *)s), &obj, 1); + if (code < 0) make_null(&obj); + if (s != data) + gs_free_object(mem, s, "ref_stack_array_sanitize"); + } + } + else { + make_null(&obj); + } + ref_assign(darr->value.refs + i, &obj); + break; + } + case t_array: + case t_shortarray: + case t_mixedarray: + { + int attrs = r_type_attrs(&obj) & (a_write | a_read | a_execute | a_executable); + /* We only want to copy executable arrays */ + if (attrs & (a_execute | a_executable)) { + code = ialloc_ref_array(&arr2, attrs, r_size(&obj), "ref_stack_array_sanitize"); + if (code < 0) { + make_null(&arr2); + } + else { + code = ref_stack_array_sanitize(i_ctx_p, &obj, &arr2); + } + ref_assign(darr->value.refs + i, &arr2); + } + else { + ref_assign(darr->value.refs + i, &obj); + } + break; + } + default: + ref_assign(darr->value.refs + i, &obj); + } + } + return 0; +} + + /* * Store the top 'count' elements of a stack, starting 'skip' elements below * the top, into an array, with or without store/undo checking. age=-1 for diff -up ghostscript-9.07/psi/istack.h.cve-2019-6116 ghostscript-9.07/psi/istack.h --- ghostscript-9.07/psi/istack.h.cve-2019-6116 2013-02-14 08:58:13.000000000 +0100 +++ ghostscript-9.07/psi/istack.h 2019-03-05 11:28:18.297243739 +0100 @@ -129,6 +129,9 @@ int ref_stack_store(const ref_stack_t *p uint skip, int age, bool check, gs_dual_memory_t *idmem, client_name_t cname); +int +ref_stack_array_sanitize(i_ctx_t *i_ctx_p, ref *sarr, ref *darr); + /* * Pop the top N elements off a stack. * The number must not exceed the number of elements in use. diff -up ghostscript-9.07/psi/zfont2.c.cve-2019-6116 ghostscript-9.07/psi/zfont2.c --- ghostscript-9.07/psi/zfont2.c.cve-2019-6116 2019-03-05 11:28:18.063246914 +0100 +++ ghostscript-9.07/psi/zfont2.c 2019-03-05 11:28:18.297243739 +0100 @@ -2718,9 +2718,13 @@ zparsecff(i_ctx_t *i_ctx_p) ref blk_wrap[1]; check_read(*op); + if (r_has_type(op, t_array)) { /* no packedarrays */ int i, blk_sz, blk_cnt; + if (op->value.refs == NULL) + return_error(gs_error_typecheck); + data.blk_ref = op->value.refs; blk_cnt = r_size(op); blk_sz = r_size(data.blk_ref); diff -up ghostscript-9.07/Resource/Init/gs_cff.ps.cve-2019-6116 ghostscript-9.07/Resource/Init/gs_cff.ps --- ghostscript-9.07/Resource/Init/gs_cff.ps.cve-2019-6116 2013-02-14 08:58:16.000000000 +0100 +++ ghostscript-9.07/Resource/Init/gs_cff.ps 2019-03-05 11:28:18.299243712 +0100 @@ -719,7 +719,7 @@ dup % Format 2 % ordinary CFF font. /StartData { % StartData - currentfile exch subfilefilter //false //false ReadData pop -} bind def +} bind executeonly def /ReadData { % ReadData % Initialize. @@ -860,7 +860,7 @@ systemdict /OLDCFF known { end % FontSetInit ProcSet /FontSet defineresource -} bind def +} bind executeonly def % ---------------- Resource category definition ---------------- % diff -up ghostscript-9.07/Resource/Init/gs_cidcm.ps.cve-2019-6116 ghostscript-9.07/Resource/Init/gs_cidcm.ps --- ghostscript-9.07/Resource/Init/gs_cidcm.ps.cve-2019-6116 2013-02-14 08:58:16.000000000 +0100 +++ ghostscript-9.07/Resource/Init/gs_cidcm.ps 2019-03-05 11:28:18.299243712 +0100 @@ -327,7 +327,7 @@ currentdict end def //FindResource exec } ifelse } ifelse -} bind def +} bind executeonly def /ResourceStatus { % ResourceStatus true % ResourceStatus false @@ -359,7 +359,7 @@ currentdict end def //false } ifelse } ifelse -} bind def +} bind executeonly def /ResourceForAll { %