commit 30cd347f37bfb293ffdc407397d1023628400b81 Author: Ken Sharp Date: Mon Oct 15 13:35:15 2018 +0100 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. commit 8e18fcdaa2e2247363c4cc8f851f3096cc5756fa Author: Chris Liddell Date: Fri Oct 19 13:14:24 2018 +0100 "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. From d3537a54740d78c5895ec83694a07b3e4f616f61 Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Wed, 5 Dec 2018 12:22:13 +0000 Subject: [PATCH] Bug700317: Address .force* operators exposure 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. 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--"). Any transient procedures that call .force* operators (i.e. for conditionals or loops) make them executeonly. Harden some uses of .force* operators by adding a few immediate evalutions CVE-2019-6116 --- 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-01-24 12:20:06.802913354 +0100 +++ ghostscript-9.07/psi/interp.c 2019-01-24 12:20:06.843912826 +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-01-24 12:20:06.824913071 +0100 +++ ghostscript-9.07/psi/int.mak 2019-01-24 12:20:06.843912826 +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-01-24 12:20:06.844912813 +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-01-24 12:20:06.844912813 +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-01-24 12:20:06.601915943 +0100 +++ ghostscript-9.07/psi/zfont2.c 2019-01-24 12:20:06.844912813 +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-01-24 12:20:06.845912801 +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-01-24 12:20:06.845912801 +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 { %