changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/gs/src/zdevice2.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) 1993, 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: zdevice2.c,v 1.10 2005/10/04 06:30:02 ray Exp $ */
18 /* Level 2 device operators */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "ghost.h"
22 #include "oper.h"
23 #include "dstack.h" /* for dict_find_name */
24 #include "estack.h"
25 #include "idict.h"
26 #include "idparam.h"
27 #include "igstate.h"
28 #include "iname.h"
29 #include "iutil.h"
30 #include "isave.h"
31 #include "store.h"
32 #include "gxdevice.h"
33 #include "gsstate.h"
34 
35 /* Exported for zfunc4.c */
36 int z2copy(i_ctx_t *);
37 
38 /* Forward references */
39 private int z2copy_gstate(i_ctx_t *);
40 private int push_callout(i_ctx_t *, const char *);
41 
42 /* Extend the `copy' operator to deal with gstates. */
43 /* This is done with a hack -- we know that gstates are the only */
44 /* t_astruct subtype that implements copy. */
45 /* We export this for recognition in FunctionType 4 functions. */
46 int
47 z2copy(i_ctx_t *i_ctx_p)
48 {
49  os_ptr op = osp;
50  int code = zcopy(i_ctx_p);
51 
52  if (code >= 0)
53  return code;
54  if (!r_has_type(op, t_astruct))
55  return code;
56  return z2copy_gstate(i_ctx_p);
57 }
58 
59 /* - .currentshowpagecount <count> true */
60 /* - .currentshowpagecount false */
61 private int
62 zcurrentshowpagecount(i_ctx_t *i_ctx_p)
63 {
64  os_ptr op = osp;
65  gx_device *dev = gs_currentdevice(igs);
66 
67  if ((*dev_proc(dev, get_page_device))(dev) == 0) {
68  push(1);
69  make_false(op);
70  } else {
71  push(2);
72  make_int(op - 1, dev->ShowpageCount);
73  make_true(op);
74  }
75  return 0;
76 }
77 
78 /* - .currentpagedevice <dict> <bool> */
79 private int
80 zcurrentpagedevice(i_ctx_t *i_ctx_p)
81 {
82  os_ptr op = osp;
83  gx_device *dev = gs_currentdevice(igs);
84 
85  push(2);
86  if ((*dev_proc(dev, get_page_device))(dev) != 0) {
87  op[-1] = istate->pagedevice;
88  make_true(op);
89  } else {
90  make_null(op - 1);
91  make_false(op);
92  }
93  return 0;
94 }
95 
96 /* <local_dict|null> .setpagedevice - */
97 private int
98 zsetpagedevice(i_ctx_t *i_ctx_p)
99 {
100  os_ptr op = osp;
101  int code;
102 
103 /******
104  if ( igs->in_cachedevice )
105  return_error(e_undefined);
106  ******/
107  if (r_has_type(op, t_dictionary)) {
108  check_dict_read(*op);
109 #if 0 /****************/
110  /*
111  * In order to avoid invalidaccess errors on setpagedevice,
112  * the dictionary must be allocated in local VM.
113  */
114  if (!(r_is_local(op)))
115  return_error(e_invalidaccess);
116 #endif /****************/
117  /* Make the dictionary read-only. */
118  code = zreadonly(i_ctx_p);
119  if (code < 0)
120  return code;
121  } else {
122  check_type(*op, t_null);
123  }
124  istate->pagedevice = *op;
125  pop(1);
126  return 0;
127 }
128 
129 /* Default Install/BeginPage/EndPage procedures */
130 /* that just call the procedure in the device. */
131 
132 /* - .callinstall - */
133 private int
134 zcallinstall(i_ctx_t *i_ctx_p)
135 {
136  gx_device *dev = gs_currentdevice(igs);
137 
138  if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
139  int code = (*dev->page_procs.install) (dev, igs);
140 
141  if (code < 0)
142  return code;
143  }
144  return 0;
145 }
146 
147 /* <showpage_count> .callbeginpage - */
148 private int
149 zcallbeginpage(i_ctx_t *i_ctx_p)
150 {
151  os_ptr op = osp;
152  gx_device *dev = gs_currentdevice(igs);
153 
154  check_type(*op, t_integer);
155  if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
156  int code = (*dev->page_procs.begin_page)(dev, igs);
157 
158  if (code < 0)
159  return code;
160  }
161  pop(1);
162  return 0;
163 }
164 
165 /* <showpage_count> <reason_int> .callendpage <flush_bool> */
166 private int
167 zcallendpage(i_ctx_t *i_ctx_p)
168 {
169  os_ptr op = osp;
170  gx_device *dev = gs_currentdevice(igs);
171  int code;
172 
173  check_type(op[-1], t_integer);
174  check_type(*op, t_integer);
175  if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
176  code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
177  if (code < 0)
178  return code;
179  if (code > 1)
180  return_error(e_rangecheck);
181  } else {
182  code = (op->value.intval == 2 ? 0 : 1);
183  }
184  make_bool(op - 1, code);
185  pop(1);
186  return 0;
187 }
188 
189 /* ------ Wrappers for operators that save the graphics state. ------ */
190 
191 /* When saving the state with the current device a page device, */
192 /* we need to make sure that the page device dictionary exists */
193 /* so that grestore can use it to reset the device parameters. */
194 /* This may have significant performance consequences, but we don't see */
195 /* any way around it. */
196 
197 /* Check whether we need to call out to create the page device dictionary. */
198 private bool
199 save_page_device(gs_state *pgs)
200 {
201  return
202  (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
203  (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
204 }
205 
206 /* - gsave - */
207 private int
208 z2gsave(i_ctx_t *i_ctx_p)
209 {
210  if (!save_page_device(igs))
211  return gs_gsave(igs);
212  return push_callout(i_ctx_p, "%gsavepagedevice");
213 }
214 
215 /* - save - */
216 private int
217 z2save(i_ctx_t *i_ctx_p)
218 {
219  if (!save_page_device(igs))
220  return zsave(i_ctx_p);
221  return push_callout(i_ctx_p, "%savepagedevice");
222 }
223 
224 /* - gstate <gstate> */
225 private int
226 z2gstate(i_ctx_t *i_ctx_p)
227 {
228  if (!save_page_device(igs))
229  return zgstate(i_ctx_p);
230  return push_callout(i_ctx_p, "%gstatepagedevice");
231 }
232 
233 /* <gstate1> <gstate2> copy <gstate2> */
234 private int
235 z2copy_gstate(i_ctx_t *i_ctx_p)
236 {
237  if (!save_page_device(igs))
238  return zcopy_gstate(i_ctx_p);
239  return push_callout(i_ctx_p, "%copygstatepagedevice");
240 }
241 
242 /* <gstate> currentgstate <gstate> */
243 private int
244 z2currentgstate(i_ctx_t *i_ctx_p)
245 {
246  if (!save_page_device(igs))
247  return zcurrentgstate(i_ctx_p);
248  return push_callout(i_ctx_p, "%currentgstatepagedevice");
249 }
250 
251 /* ------ Wrappers for operators that reset the graphics state. ------ */
252 
253 /* Check whether we need to call out to restore the page device. */
254 private bool
255 restore_page_device(const gs_state * pgs_old, const gs_state * pgs_new)
256 {
257  gx_device *dev_old = gs_currentdevice(pgs_old);
258  gx_device *dev_new;
259  gx_device *dev_t1;
260  gx_device *dev_t2;
261  bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
262  &gs_int_gstate(pgs_new)->pagedevice);
263 
264  if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
265  return false;
266  /* If we are going to putdeviceparams in a callout, we need to */
267  /* unlock temporarily. The device will be re-locked as needed */
268  /* by putdeviceparams from the pgs_old->pagedevice dict state. */
269  if (!samepagedevice)
270  dev_old->LockSafetyParams = false;
271  dev_new = gs_currentdevice(pgs_new);
272  if (dev_old != dev_new) {
273  if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
274  return false;
275  if (dev_t1 != dev_t2)
276  return true;
277  }
278  /*
279  * The current implementation of setpagedevice just sets new
280  * parameters in the same device object, so we have to check
281  * whether the page device dictionaries are the same.
282  */
283  return !samepagedevice;
284 }
285 
286 /* - grestore - */
287 private int
288 z2grestore(i_ctx_t *i_ctx_p)
289 {
290  if (!restore_page_device(igs, gs_state_saved(igs)))
291  return gs_grestore(igs);
292  return push_callout(i_ctx_p, "%grestorepagedevice");
293 }
294 
295 /* - grestoreall - */
296 private int
297 z2grestoreall(i_ctx_t *i_ctx_p)
298 {
299  for (;;) {
300  if (!restore_page_device(igs, gs_state_saved(igs))) {
301  bool done = !gs_state_saved(gs_state_saved(igs));
302 
303  gs_grestore(igs);
304  if (done)
305  break;
306  } else
307  return push_callout(i_ctx_p, "%grestoreallpagedevice");
308  }
309  return 0;
310 }
311 
312 /* <save> restore - */
313 private int
314 z2restore(i_ctx_t *i_ctx_p)
315 {
316  alloc_save_t *asave;
317  bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams;
318  int code = restore_check_save(i_ctx_p, &asave);
319 
320  if (code < 0) return code;
321 
322  while (gs_state_saved(gs_state_saved(igs))) {
323  if (restore_page_device(igs, gs_state_saved(igs)))
324  return push_callout(i_ctx_p, "%restore1pagedevice");
325  gs_grestore(igs);
326  }
327  if (restore_page_device(igs, gs_state_saved(igs)))
328  return push_callout(i_ctx_p, "%restorepagedevice");
329  code = dorestore(i_ctx_p, asave);
330  if (code < 0)
331  gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety;
332  return code;
333 }
334 
335 /* <gstate> setgstate - */
336 private int
337 z2setgstate(i_ctx_t *i_ctx_p)
338 {
339  os_ptr op = osp;
340 
341  check_stype(*op, st_igstate_obj);
342  if (!restore_page_device(igs, igstate_ptr(op)))
343  return zsetgstate(i_ctx_p);
344  return push_callout(i_ctx_p, "%setgstatepagedevice");
345 }
346 
347 /* ------ Initialization procedure ------ */
348 
349 const op_def zdevice2_l2_op_defs[] =
350 {
351  op_def_begin_level2(),
352  {"0.currentshowpagecount", zcurrentshowpagecount},
353  {"0.currentpagedevice", zcurrentpagedevice},
354  {"1.setpagedevice", zsetpagedevice},
355  /* Note that the following replace prior definitions */
356  /* in the indicated files: */
357  {"1copy", z2copy}, /* zdps1.c */
358  {"0gsave", z2gsave}, /* zgstate.c */
359  {"0save", z2save}, /* zvmem.c */
360  {"0gstate", z2gstate}, /* zdps1.c */
361  {"1currentgstate", z2currentgstate}, /* zdps1.c */
362  {"0grestore", z2grestore}, /* zgstate.c */
363  {"0grestoreall", z2grestoreall}, /* zgstate.c */
364  {"1restore", z2restore}, /* zvmem.c */
365  {"1setgstate", z2setgstate}, /* zdps1.c */
366  /* Default Install/BeginPage/EndPage procedures */
367  /* that just call the procedure in the device. */
368  {"0.callinstall", zcallinstall},
369  {"1.callbeginpage", zcallbeginpage},
370  {"2.callendpage", zcallendpage},
371  op_def_end(0)
372 };
373 
374 /* ------ Internal routines ------ */
375 
376 /* Call out to a PostScript procedure. */
377 private int
378 push_callout(i_ctx_t *i_ctx_p, const char *callout_name)
379 {
380  int code;
381 
382  check_estack(1);
383  code = name_enter_string(imemory, callout_name, esp + 1);
384  if (code < 0)
385  return code;
386  ++esp;
387  r_set_attrs(esp, a_executable);
388  return o_push_estack;
389 }