changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/gs/src/zvmem.c

changeset 7253: 986e26228cfe
parent: eaccc3e8d226
author: cinap_lenrek@felloff.net
date: Thu, 23 May 2019 14:59:28 +0200
permissions: -rw-r--r--
description: gs: apply fixes for CVE-2018-16509 (thanks jsmoody)
1 /* Copyright (C) 1989, 1995, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2 
3  This software is provided AS-IS with no warranty, either express or
4  implied.
5 
6  This software is distributed under license and may not be copied,
7  modified or distributed except as expressly authorized under the terms
8  of the license contained in the file LICENSE in this distribution.
9 
10  For more information about licensing, please refer to
11  http://www.ghostscript.com/licensing/. For information on
12  commercial licensing, go to http://www.artifex.com/licensing/ or
13  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14  San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: zvmem.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18 /* "Virtual memory" operators */
19 #include "ghost.h"
20 #include "gsstruct.h"
21 #include "oper.h"
22 #include "estack.h" /* for checking in restore */
23 #include "ialloc.h"
24 #include "idict.h" /* ditto */
25 #include "igstate.h"
26 #include "isave.h"
27 #include "dstack.h"
28 #include "stream.h" /* for files.h */
29 #include "files.h" /* for e-stack processing */
30 #include "store.h"
31 #include "gsmatrix.h" /* for gsstate.h */
32 #include "gsstate.h"
33 
34 /* Define whether we validate memory before/after save/restore. */
35 /* Note that we only actually do this if DEBUG is set and -Z? is selected. */
36 private const bool I_VALIDATE_BEFORE_SAVE = true;
37 private const bool I_VALIDATE_AFTER_SAVE = true;
38 private const bool I_VALIDATE_BEFORE_RESTORE = true;
39 private const bool I_VALIDATE_AFTER_RESTORE = true;
40 
41 /* 'Save' structure */
42 typedef struct vm_save_s vm_save_t;
43 struct vm_save_s {
44  gs_state *gsave; /* old graphics state */
45 };
46 
47 gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
48  vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
49 
50 /* Clean up the stacks and validate storage. */
51 private void
52 ivalidate_clean_spaces(i_ctx_t *i_ctx_p)
53 {
54  if (gs_debug_c('?')) {
55  ref_stack_cleanup(&d_stack);
56  ref_stack_cleanup(&e_stack);
57  ref_stack_cleanup(&o_stack);
58  ivalidate_spaces();
59  }
60 }
61 
62 /* - save <save> */
63 int
64 zsave(i_ctx_t *i_ctx_p)
65 {
66  os_ptr op = osp;
67  uint space = icurrent_space;
68  vm_save_t *vmsave;
69  ulong sid;
70  int code;
71  gs_state *prev;
72 
73  if (I_VALIDATE_BEFORE_SAVE)
74  ivalidate_clean_spaces(i_ctx_p);
75  ialloc_set_space(idmemory, avm_local);
76  vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
77  ialloc_set_space(idmemory, space);
78  if (vmsave == 0)
79  return_error(e_VMerror);
80  sid = alloc_save_state(idmemory, vmsave);
81  if (sid == 0) {
82  ifree_object(vmsave, "zsave");
83  return_error(e_VMerror);
84  }
85  if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
86  (ulong) vmsave, (ulong) sid);
87  code = gs_gsave_for_save(igs, &prev);
88  if (code < 0)
89  return code;
90  code = gs_gsave(igs);
91  if (code < 0)
92  return code;
93  vmsave->gsave = prev;
94  push(1);
95  make_tav(op, t_save, 0, saveid, sid);
96  if (I_VALIDATE_AFTER_SAVE)
97  ivalidate_clean_spaces(i_ctx_p);
98  return 0;
99 }
100 
101 /* <save> restore - */
102 private int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *);
103 private int restore_check_stack(const ref_stack_t *, const alloc_save_t *, bool);
104 private void restore_fix_stack(ref_stack_t *, const alloc_save_t *, bool);
105 
106 int
107 restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave)
108 {
109  os_ptr op = osp;
110  int code = restore_check_operand(op, asave, idmemory);
111  if (code < 0)
112  return code;
113  if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
114  (ulong) alloc_save_client_data(*asave),
115  (ulong) op->value.saveid);
116  if (I_VALIDATE_BEFORE_RESTORE)
117  ivalidate_clean_spaces(i_ctx_p);
118  /* Check the contents of the stacks. */
119  osp--;
120  if ((code = restore_check_stack(&o_stack, *asave, false)) < 0 ||
121  (code = restore_check_stack(&e_stack, *asave, true)) < 0 ||
122  (code = restore_check_stack(&d_stack, *asave, false)) < 0
123  ) {
124  osp++;
125  return code;
126  }
127  osp++;
128  return 0;
129 }
130 
131 /*
132  * the emantics of restore differ slightly between Level 1 and
133  * Level 2 and later - the latter inclues restoring the device
134  * state (whilst Level 1 didn't have "page devices" as such).
135  * Hence we have two restore operators - one here (Level 1)
136  * and one in zdevice2.c (Level 2+). For that reason, the
137  * operand checking and guts of the restore operation are
138  * separated so both implementations can use them to best
139  * effect.
140  */
141 int
142 dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave)
143 {
144  os_ptr op = osp;
145  bool last;
146  vm_save_t *vmsave;
147  int code;
148 
149  osp--;
150 
151  /* Reset l_new in all stack entries if the new save level is zero. */
152  /* Also do some special fixing on the e-stack. */
153  restore_fix_stack(&o_stack, asave, false);
154  restore_fix_stack(&e_stack, asave, true);
155  restore_fix_stack(&d_stack, asave, false);
156  /* Iteratively restore the state of memory, */
157  /* also doing a grestoreall at each step. */
158  do {
159  vmsave = alloc_save_client_data(alloc_save_current(idmemory));
160  /* Restore the graphics state. */
161  gs_grestoreall_for_restore(igs, vmsave->gsave);
162  /*
163  * If alloc_save_space decided to do a second save, the vmsave
164  * object was allocated one save level less deep than the
165  * current level, so ifree_object won't actually free it;
166  * however, it points to a gsave object that definitely
167  * *has* been freed. In order not to trip up the garbage
168  * collector, we clear the gsave pointer now.
169  */
170  vmsave->gsave = 0;
171  /* Now it's safe to restore the state of memory. */
172  last = alloc_restore_state_step(asave);
173  }
174  while (!last);
175  {
176  uint space = icurrent_space;
177 
178  ialloc_set_space(idmemory, avm_local);
179  ifree_object(vmsave, "zrestore");
180  ialloc_set_space(idmemory, space);
181  }
182  dict_set_top(); /* reload dict stack cache */
183  if (I_VALIDATE_AFTER_RESTORE)
184  ivalidate_clean_spaces(i_ctx_p);
185  /* If the i_ctx_p LockFilePermissions is true, but the userparams */
186  /* we just restored is false, we need to make sure that we do not */
187  /* cause an 'invalidaccess' in setuserparams. Temporarily set */
188  /* LockFilePermissions false until the gs_lev2.ps can do a */
189  /* setuserparams from the restored userparam dictionary. */
190  /* NOTE: This is safe to do here, since the restore has */
191  /* successfully completed - this should never come before any */
192  /* operation that can trigger an error */
193  i_ctx_p->LockFilePermissions = false;
194  return 0;
195 }
196 
197 int
198 zrestore(i_ctx_t *i_ctx_p)
199 {
200  alloc_save_t *asave;
201  int code = restore_check_save(i_ctx_p, &asave);
202  if (code < 0)
203  return code;
204  return dorestore(i_ctx_p, asave);
205 }
206 
207 /* Check the operand of a restore. */
208 private int
209 restore_check_operand(os_ptr op, alloc_save_t ** pasave,
210  gs_dual_memory_t *idmem)
211 {
212  vm_save_t *vmsave;
213  ulong sid;
214  alloc_save_t *asave;
215 
216  check_type(*op, t_save);
217  vmsave = r_ptr(op, vm_save_t);
218  if (vmsave == 0) /* invalidated save */
219  return_error(e_invalidrestore);
220  sid = op->value.saveid;
221  asave = alloc_find_save(idmem, sid);
222  if (asave == 0)
223  return_error(e_invalidrestore);
224  *pasave = asave;
225  return 0;
226 }
227 /* Check a stack to make sure all its elements are older than a save. */
228 private int
229 restore_check_stack(const ref_stack_t * pstack, const alloc_save_t * asave,
230  bool is_estack)
231 {
232  ref_stack_enum_t rsenum;
233 
234  ref_stack_enum_begin(&rsenum, pstack);
235  do {
236  const ref *stkp = rsenum.ptr;
237  uint size = rsenum.size;
238 
239  for (; size; stkp++, size--) {
240  const void *ptr;
241 
242  switch (r_type(stkp)) {
243  case t_array:
244  ptr = stkp->value.refs;
245  break;
246  case t_dictionary:
247  ptr = stkp->value.pdict;
248  break;
249  case t_file:
250  /* Don't check executable or closed literal */
251  /* files on the e-stack. */
252  {
253  stream *s;
254 
255  if (is_estack &&
256  (r_has_attr(stkp, a_executable) ||
257  file_is_invalid(s, stkp))
258  )
259  continue;
260  }
261  ptr = stkp->value.pfile;
262  break;
263  case t_name:
264  /* Names are special because of how they are allocated. */
265  if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory,
266  stkp, asave))
267  return_error(e_invalidrestore);
268  continue;
269  case t_string:
270  /* Don't check empty executable strings */
271  /* on the e-stack. */
272  if (r_size(stkp) == 0 &&
273  r_has_attr(stkp, a_executable) && is_estack
274  )
275  continue;
276  ptr = stkp->value.bytes;
277  break;
278  case t_mixedarray:
279  case t_shortarray:
280  ptr = stkp->value.packed;
281  break;
282  case t_device:
283  ptr = stkp->value.pdevice;
284  break;
285  case t_fontID:
286  case t_struct:
287  case t_astruct:
288  ptr = stkp->value.pstruct;
289  break;
290  default:
291  continue;
292  }
293  if (alloc_is_since_save(ptr, asave))
294  return_error(e_invalidrestore);
295  }
296  } while (ref_stack_enum_next(&rsenum));
297  return 0; /* OK */
298 }
299 /*
300  * If the new save level is zero, fix up the contents of a stack
301  * by clearing the l_new bit in all the entries (since we can't tolerate
302  * values with l_new set if the save level is zero).
303  * Also, in any case, fix up the e-stack by replacing empty executable
304  * strings and closed executable files that are newer than the save
305  * with canonical ones that aren't.
306  *
307  * Note that this procedure is only called if restore_check_stack succeeded.
308  */
309 private void
310 restore_fix_stack(ref_stack_t * pstack, const alloc_save_t * asave,
311  bool is_estack)
312 {
313  ref_stack_enum_t rsenum;
314 
315  ref_stack_enum_begin(&rsenum, pstack);
316  do {
317  ref *stkp = rsenum.ptr;
318  uint size = rsenum.size;
319 
320  for (; size; stkp++, size--) {
321  r_clear_attrs(stkp, l_new); /* always do it, no harm */
322  if (is_estack) {
323  ref ofile;
324 
325  ref_assign(&ofile, stkp);
326  switch (r_type(stkp)) {
327  case t_string:
328  if (r_size(stkp) == 0 &&
329  alloc_is_since_save(stkp->value.bytes,
330  asave)
331  ) {
332  make_empty_const_string(stkp,
333  avm_foreign);
334  break;
335  }
336  continue;
337  case t_file:
338  if (alloc_is_since_save(stkp->value.pfile,
339  asave)
340  ) {
341  make_invalid_file(stkp);
342  break;
343  }
344  continue;
345  default:
346  continue;
347  }
348  r_copy_attrs(stkp, a_all | a_executable,
349  &ofile);
350  }
351  }
352  } while (ref_stack_enum_next(&rsenum));
353 }
354 
355 /* - vmstatus <save_level> <vm_used> <vm_maximum> */
356 private int
357 zvmstatus(i_ctx_t *i_ctx_p)
358 {
359  os_ptr op = osp;
360  gs_memory_status_t mstat, dstat;
361 
362  gs_memory_status(imemory, &mstat);
363  if (imemory == imemory_global) {
364  gs_memory_status_t sstat;
365 
366  gs_memory_status(imemory_system, &sstat);
367  mstat.allocated += sstat.allocated;
368  mstat.used += sstat.used;
369  }
370  gs_memory_status(imemory->non_gc_memory, &dstat);
371  push(3);
372  make_int(op - 2, imemory_save_level(iimemory_local));
373  make_int(op - 1, mstat.used);
374  make_int(op, mstat.allocated + dstat.allocated - dstat.used);
375  return 0;
376 }
377 
378 /* ------ Non-standard extensions ------ */
379 
380 /* <save> .forgetsave - */
381 private int
382 zforgetsave(i_ctx_t *i_ctx_p)
383 {
384  os_ptr op = osp;
385  alloc_save_t *asave;
386  vm_save_t *vmsave;
387  int code = restore_check_operand(op, &asave, idmemory);
388 
389  if (code < 0)
390  return 0;
391  vmsave = alloc_save_client_data(asave);
392  /* Reset l_new in all stack entries if the new save level is zero. */
393  restore_fix_stack(&o_stack, asave, false);
394  restore_fix_stack(&e_stack, asave, false);
395  restore_fix_stack(&d_stack, asave, false);
396  /*
397  * Forget the gsaves, by deleting the bottom gstate on
398  * the current stack and the top one on the saved stack and then
399  * concatenating the stacks together.
400  */
401  {
402  gs_state *pgs = igs;
403  gs_state *last;
404 
405  while (gs_state_saved(last = gs_state_saved(pgs)) != 0)
406  pgs = last;
407  gs_state_swap_saved(last, vmsave->gsave);
408  gs_grestore(last);
409  gs_grestore(last);
410  }
411  /* Forget the save in the memory manager. */
412  alloc_forget_save(asave);
413  {
414  uint space = icurrent_space;
415 
416  ialloc_set_space(idmemory, avm_local);
417  /* See above for why we clear the gsave pointer here. */
418  vmsave->gsave = 0;
419  ifree_object(vmsave, "zrestore");
420  ialloc_set_space(idmemory, space);
421  }
422  pop(1);
423  return 0;
424 }
425 
426 /* ------ Initialization procedure ------ */
427 
428 const op_def zvmem_op_defs[] =
429 {
430  {"1.forgetsave", zforgetsave},
431  {"1restore", zrestore},
432  {"0save", zsave},
433  {"0vmstatus", zvmstatus},
434  op_def_end(0)
435 };