Brad Bishop | d89cb5f | 2019-04-10 09:02:41 -0400 | [diff] [blame^] | 1 | From c8c77690199b677f70093824382f0881e643e17b Mon Sep 17 00:00:00 2001 |
| 2 | From: Chris Liddell <chris.liddell@artifex.com> |
| 3 | Date: Wed, 5 Dec 2018 12:22:13 +0000 |
| 4 | Subject: [PATCH 1/7] Sanitize op stack for error conditions |
| 5 | |
| 6 | We save the stacks to an array and store the array for the error handler to |
| 7 | access. |
| 8 | |
| 9 | For SAFER, we traverse the array, and deep copy any op arrays (procedures). As |
| 10 | we make these copies, we check for operators that do *not* exist in systemdict, |
| 11 | when we find one, we replace the operator with a name object (of the form |
| 12 | "/--opname--"). |
| 13 | |
| 14 | CVE: CVE-2019-6116 |
| 15 | Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git] |
| 16 | |
| 17 | Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com> |
| 18 | --- |
| 19 | psi/int.mak | 3 +- |
| 20 | psi/interp.c | 8 ++++++ |
| 21 | psi/istack.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 22 | psi/istack.h | 3 ++ |
| 23 | 4 files changed, 91 insertions(+), 1 deletion(-) |
| 24 | |
| 25 | diff --git a/psi/int.mak b/psi/int.mak |
| 26 | index 6ab5bf0..6b349cb 100644 |
| 27 | --- a/psi/int.mak |
| 28 | +++ b/psi/int.mak |
| 29 | @@ -204,7 +204,8 @@ $(PSOBJ)iparam.$(OBJ) : $(PSSRC)iparam.c $(GH)\ |
| 30 | $(PSOBJ)istack.$(OBJ) : $(PSSRC)istack.c $(GH) $(memory__h)\ |
| 31 | $(ierrors_h) $(gsstruct_h) $(gsutil_h)\ |
| 32 | $(ialloc_h) $(istack_h) $(istkparm_h) $(istruct_h) $(iutil_h) $(ivmspace_h)\ |
| 33 | - $(store_h) $(INT_MAK) $(MAKEDIRS) |
| 34 | + $(store_h) $(icstate_h) $(iname_h) $(dstack_h) $(idict_h) \ |
| 35 | + $(INT_MAK) $(MAKEDIRS) |
| 36 | $(PSCC) $(PSO_)istack.$(OBJ) $(C_) $(PSSRC)istack.c |
| 37 | |
| 38 | $(PSOBJ)iutil.$(OBJ) : $(PSSRC)iutil.c $(GH) $(math__h) $(memory__h) $(string__h)\ |
| 39 | diff --git a/psi/interp.c b/psi/interp.c |
| 40 | index 6dc0dda..aa5779c 100644 |
| 41 | --- a/psi/interp.c |
| 42 | +++ b/psi/interp.c |
| 43 | @@ -761,6 +761,7 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_stack_t * pstack, int skip, ref * arr) |
| 44 | uint size = ref_stack_count(pstack) - skip; |
| 45 | uint save_space = ialloc_space(idmemory); |
| 46 | int code, i; |
| 47 | + ref *safety, *safe; |
| 48 | |
| 49 | if (size > 65535) |
| 50 | size = 65535; |
| 51 | @@ -778,6 +779,13 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_stack_t * pstack, int skip, ref * arr) |
| 52 | make_null(&arr->value.refs[i]); |
| 53 | } |
| 54 | } |
| 55 | + if (pstack == &o_stack && dict_find_string(systemdict, "SAFETY", &safety) > 0 && |
| 56 | + dict_find_string(safety, "safe", &safe) > 0 && r_has_type(safe, t_boolean) && |
| 57 | + safe->value.boolval == true) { |
| 58 | + code = ref_stack_array_sanitize(i_ctx_p, arr, arr); |
| 59 | + if (code < 0) |
| 60 | + return code; |
| 61 | + } |
| 62 | ialloc_set_space(idmemory, save_space); |
| 63 | return code; |
| 64 | } |
| 65 | diff --git a/psi/istack.c b/psi/istack.c |
| 66 | index 8fe151f..f1a3e51 100644 |
| 67 | --- a/psi/istack.c |
| 68 | +++ b/psi/istack.c |
| 69 | @@ -27,6 +27,10 @@ |
| 70 | #include "iutil.h" |
| 71 | #include "ivmspace.h" /* for local/global test */ |
| 72 | #include "store.h" |
| 73 | +#include "icstate.h" |
| 74 | +#include "iname.h" |
| 75 | +#include "dstack.h" |
| 76 | +#include "idict.h" |
| 77 | |
| 78 | /* Forward references */ |
| 79 | static void init_block(ref_stack_t *pstack, const ref *pblock_array, |
| 80 | @@ -294,6 +298,80 @@ ref_stack_store_check(const ref_stack_t *pstack, ref *parray, uint count, |
| 81 | return 0; |
| 82 | } |
| 83 | |
| 84 | +int |
| 85 | +ref_stack_array_sanitize(i_ctx_t *i_ctx_p, ref *sarr, ref *darr) |
| 86 | +{ |
| 87 | + int i, code; |
| 88 | + ref obj, arr2; |
| 89 | + ref *pobj2; |
| 90 | + gs_memory_t *mem = (gs_memory_t *)idmemory->current; |
| 91 | + |
| 92 | + if (!r_is_array(sarr) || !r_has_type(darr, t_array)) |
| 93 | + return_error(gs_error_typecheck); |
| 94 | + |
| 95 | + for (i = 0; i < r_size(sarr); i++) { |
| 96 | + code = array_get(mem, sarr, i, &obj); |
| 97 | + if (code < 0) |
| 98 | + make_null(&obj); |
| 99 | + switch(r_type(&obj)) { |
| 100 | + case t_operator: |
| 101 | + { |
| 102 | + int index = op_index(&obj); |
| 103 | + |
| 104 | + if (index > 0 && index < op_def_count) { |
| 105 | + const byte *data = (const byte *)(op_index_def(index)->oname + 1); |
| 106 | + if (dict_find_string(systemdict, (const char *)data, &pobj2) <= 0) { |
| 107 | + byte *s = gs_alloc_bytes(mem, strlen((char *)data) + 5, "ref_stack_array_sanitize"); |
| 108 | + if (s) { |
| 109 | + s[0] = '\0'; |
| 110 | + strcpy((char *)s, "--"); |
| 111 | + strcpy((char *)s + 2, (char *)data); |
| 112 | + strcpy((char *)s + strlen((char *)data) + 2, "--"); |
| 113 | + } |
| 114 | + else { |
| 115 | + s = (byte *)data; |
| 116 | + } |
| 117 | + code = name_ref(imemory, s, strlen((char *)s), &obj, 1); |
| 118 | + if (code < 0) make_null(&obj); |
| 119 | + if (s != data) |
| 120 | + gs_free_object(mem, s, "ref_stack_array_sanitize"); |
| 121 | + } |
| 122 | + } |
| 123 | + else { |
| 124 | + make_null(&obj); |
| 125 | + } |
| 126 | + ref_assign(darr->value.refs + i, &obj); |
| 127 | + break; |
| 128 | + } |
| 129 | + case t_array: |
| 130 | + case t_shortarray: |
| 131 | + case t_mixedarray: |
| 132 | + { |
| 133 | + int attrs = r_type_attrs(&obj) & (a_write | a_read | a_execute | a_executable); |
| 134 | + /* We only want to copy executable arrays */ |
| 135 | + if (attrs & (a_execute | a_executable)) { |
| 136 | + code = ialloc_ref_array(&arr2, attrs, r_size(&obj), "ref_stack_array_sanitize"); |
| 137 | + if (code < 0) { |
| 138 | + make_null(&arr2); |
| 139 | + } |
| 140 | + else { |
| 141 | + code = ref_stack_array_sanitize(i_ctx_p, &obj, &arr2); |
| 142 | + } |
| 143 | + ref_assign(darr->value.refs + i, &arr2); |
| 144 | + } |
| 145 | + else { |
| 146 | + ref_assign(darr->value.refs + i, &obj); |
| 147 | + } |
| 148 | + break; |
| 149 | + } |
| 150 | + default: |
| 151 | + ref_assign(darr->value.refs + i, &obj); |
| 152 | + } |
| 153 | + } |
| 154 | + return 0; |
| 155 | +} |
| 156 | + |
| 157 | + |
| 158 | /* |
| 159 | * Store the top 'count' elements of a stack, starting 'skip' elements below |
| 160 | * the top, into an array, with or without store/undo checking. age=-1 for |
| 161 | diff --git a/psi/istack.h b/psi/istack.h |
| 162 | index 051dcbe..54be405 100644 |
| 163 | --- a/psi/istack.h |
| 164 | +++ b/psi/istack.h |
| 165 | @@ -129,6 +129,9 @@ int ref_stack_store(const ref_stack_t *pstack, ref *parray, uint count, |
| 166 | uint skip, int age, bool check, |
| 167 | gs_dual_memory_t *idmem, client_name_t cname); |
| 168 | |
| 169 | +int |
| 170 | +ref_stack_array_sanitize(i_ctx_t *i_ctx_p, ref *sarr, ref *darr); |
| 171 | + |
| 172 | /* |
| 173 | * Pop the top N elements off a stack. |
| 174 | * The number must not exceed the number of elements in use. |
| 175 | -- |
| 176 | 2.18.1 |
| 177 | |