summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Sharp <ken.sharp@artifex.com>2018-09-07 15:22:29 +0100
committerKen Sharp <ken.sharp@artifex.com>2018-09-07 15:34:58 +0100
commit65a9046ded8e9edd5d33bc812a9e94ae29607a1e (patch)
tree2195c2b596572e0bbe805f979272287b9b284f81
parent0da9680ca0506fd3cdf70840ad5387d85cab4996 (diff)
Bug #699707 "Security review bug - continuation procedures"
As a result of the recent security review, this bug was raised to go through the PostScript interpreter looking for places where we exit the 'C' level and return control to PostScript. This is done when we need to evaluate something in the PostScript environment, such as a transfer function or a tint transform. Because these functions are written in PostScript we need to run them in the PostScript environment. To do this we push the procedure (or at least 'a' procedure) onto the exec stack and exit with an o_push_estack error. In many cases that's all we need to do, but sometimes we want to return control back to the 'C' environment and, in some of those cases, we want to store some state for the C code. We can't use the operand stack (because the PostScript function will alter that) so we store stuff on the exec stack instead. When we complete the C level, we should restore the exec stack, so if we stored any state on it, we should remove it. Sometimes we were not doing so if there was an error. Generally this did not cause a problem, because in general on an error we would stop. However if the error handler had been altered it was possible we might carry on. 'Sometimes' that would mean we tried to execute something which wasn't executable, and sometimes it might mean that we tried to return to the C level, but without the expected state on the exec stack. This could lead to memory corruption and crashes. This commit tries to find everywhere where we might end up leaving extra items on the exec stack in the case of an error, and either removes the required number of items from the exec stack or uses whatever cleanup routine was established for the C code. Its important to note that, in normal use, none of these could actually cause a problem. This makes it hard to test. all the cases here I have tested, though in many cases the only way I could produce an error was by forcing an error return in the debugger. I suspect some error cases simply aren't possible but its good practice to check the return codes anyway, even if its only a theoretical problem.
-rw-r--r--psi/zalg.c5
-rw-r--r--psi/zcie.c82
-rw-r--r--psi/zcolor1.c9
-rw-r--r--psi/zcontrol.c4
-rw-r--r--psi/zfile.c8
-rw-r--r--psi/zht1.c5
-rw-r--r--psi/zht2.c5
-rw-r--r--psi/zpath1.c2
-rw-r--r--psi/zpcolor.c12
9 files changed, 86 insertions, 46 deletions
diff --git a/psi/zalg.c b/psi/zalg.c
index e2400d93d..2677e62c4 100644
--- a/psi/zalg.c
+++ b/psi/zalg.c
@@ -165,8 +165,10 @@ H6: H = 6;
165 ref_assign(&op[0], &Rn[j]); 165 ref_assign(&op[0], &Rn[j]);
166 break; 166 break;
167 case 6: 167 case 6:
168/*H6_cont:*/if (!r_has_type(&op[0], t_boolean)) 168 /*H6_cont:*/if (!r_has_type(&op[0], t_boolean)) {
169 esp -= 9;
169 return_error(gs_error_typecheck); 170 return_error(gs_error_typecheck);
171 }
170 if (op[0].value.boolval) { 172 if (op[0].value.boolval) {
171/* H7: */ ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)"); 173/* H7: */ ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)");
172 goto H4; 174 goto H4;
@@ -176,6 +178,7 @@ H8: ref_assign_old(&arry, &Rn[i], &R, ".sort(H8)");
176 } 178 }
177 default: 179 default:
178 pop(1); 180 pop(1);
181 esp -= 9;
179 return_error(gs_error_unregistered); /* Must not happen. */ 182 return_error(gs_error_unregistered); /* Must not happen. */
180 } 183 }
181 esp += 2; 184 esp += 2;
diff --git a/psi/zcie.c b/psi/zcie.c
index c3c2cb4d0..efe2a2f63 100644
--- a/psi/zcie.c
+++ b/psi/zcie.c
@@ -455,25 +455,29 @@ ciedefgspace(i_ctx_t *i_ctx_p, ref *CIEDict, ulong dictkey)
455 push(1); /* Sacrificial */ 455 push(1); /* Sacrificial */
456 procs = istate->colorspace[0].procs.cie; 456 procs = istate->colorspace[0].procs.cie;
457 if (pcs == NULL ) { 457 if (pcs == NULL ) {
458 if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) 458 if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) {
459 return (code < 0 ? code : gs_note_error(gs_error_rangecheck)); 459 if (code == 0)
460 check_read_type(*ptref, t_array); 460 gs_note_error(cie_set_finish(i_ctx_p, pcs, &procs, edepth, gs_error_rangecheck));
461 if (r_size(ptref) != 5) 461 else
462 return_error(gs_error_rangecheck); 462 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
463 /* Stable memory due to current caching of color space */ 463 }
464 code = gs_cspace_build_CIEDEFG(&pcs, NULL, mem->stable_memory); 464 check_read_type(*ptref, t_array);
465 if (code < 0) 465 if (r_size(ptref) != 5)
466 return code; 466 return_error(gs_error_rangecheck);
467 pcie = pcs->params.defg; 467 /* Stable memory due to current caching of color space */
468 pcie->Table.n = 4; 468 code = gs_cspace_build_CIEDEFG(&pcs, NULL, mem->stable_memory);
469 pcie->Table.m = 3; 469 if (code < 0)
470 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
471 pcie = pcs->params.defg;
472 pcie->Table.n = 4;
473 pcie->Table.m = 3;
470 code = cie_cache_push_finish(i_ctx_p, cie_defg_finish, imem, pcie); 474 code = cie_cache_push_finish(i_ctx_p, cie_defg_finish, imem, pcie);
471 if (code < 0) 475 if (code < 0)
472 return code; 476 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
473 code = cie_defg_param(i_ctx_p, imemory, CIEDict, pcie, &procs, 477 code = cie_defg_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
474 &has_abc_procs, &has_lmn_procs, &has_defg_procs,ptref); 478 &has_abc_procs, &has_lmn_procs, &has_defg_procs,ptref);
475 if (code < 0) 479 if (code < 0)
476 return code; 480 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
477 /* Add the color space to the profile cache */ 481 /* Add the color space to the profile cache */
478 gsicc_add_cs(igs, pcs,dictkey); 482 gsicc_add_cs(igs, pcs,dictkey);
479 } else { 483 } else {
@@ -561,25 +565,29 @@ ciedefspace(i_ctx_t *i_ctx_p, ref *CIEDict, ulong dictkey)
561 push(1); /* Sacrificial */ 565 push(1); /* Sacrificial */
562 procs = istate->colorspace[0].procs.cie; 566 procs = istate->colorspace[0].procs.cie;
563 if (pcs == NULL ) { 567 if (pcs == NULL ) {
564 if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) 568 if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) {
565 return (code < 0 ? code : gs_note_error(gs_error_rangecheck)); 569 if (code == 0)
566 check_read_type(*ptref, t_array); 570 gs_note_error(cie_set_finish(i_ctx_p, pcs, &procs, edepth, gs_error_rangecheck));
567 if (r_size(ptref) != 4) 571 else
568 return_error(gs_error_rangecheck); 572 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
569 /* Stable memory due to current caching of color space */ 573 }
570 code = gs_cspace_build_CIEDEF(&pcs, NULL, mem->stable_memory); 574 check_read_type(*ptref, t_array);
571 if (code < 0) 575 if (r_size(ptref) != 4)
572 return code; 576 return_error(gs_error_rangecheck);
573 pcie = pcs->params.def; 577 /* Stable memory due to current caching of color space */
574 pcie->Table.n = 3; 578 code = gs_cspace_build_CIEDEF(&pcs, NULL, mem->stable_memory);
575 pcie->Table.m = 3; 579 if (code < 0)
580 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
581 pcie = pcs->params.def;
582 pcie->Table.n = 3;
583 pcie->Table.m = 3;
576 code = cie_cache_push_finish(i_ctx_p, cie_def_finish, imem, pcie); 584 code = cie_cache_push_finish(i_ctx_p, cie_def_finish, imem, pcie);
577 if (code < 0) 585 if (code < 0)
578 return code; 586 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
579 code = cie_def_param(i_ctx_p, imemory, CIEDict, pcie, &procs, 587 code = cie_def_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
580 &has_abc_procs, &has_lmn_procs, &has_def_procs, ptref); 588 &has_abc_procs, &has_lmn_procs, &has_def_procs, ptref);
581 if (code < 0) 589 if (code < 0)
582 return code; 590 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
583 /* Add the color space to the profile cache */ 591 /* Add the color space to the profile cache */
584 gsicc_add_cs(igs, pcs,dictkey); 592 gsicc_add_cs(igs, pcs,dictkey);
585 } else { 593 } else {
@@ -629,15 +637,15 @@ cieabcspace(i_ctx_t *i_ctx_p, ref *CIEDict, ulong dictkey)
629 /* Stable memory due to current caching of color space */ 637 /* Stable memory due to current caching of color space */
630 code = gs_cspace_build_CIEABC(&pcs, NULL, mem->stable_memory); 638 code = gs_cspace_build_CIEABC(&pcs, NULL, mem->stable_memory);
631 if (code < 0) 639 if (code < 0)
632 return code; 640 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
633 pcie = pcs->params.abc; 641 pcie = pcs->params.abc;
634 code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie); 642 code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie);
635 if (code < 0) 643 if (code < 0)
636 return code; 644 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
637 code = cie_abc_param(i_ctx_p, imemory, CIEDict, pcie, &procs, 645 code = cie_abc_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
638 &has_abc_procs, &has_lmn_procs); 646 &has_abc_procs, &has_lmn_procs);
639 if (code < 0) 647 if (code < 0)
640 return code; 648 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
641 /* Set the color space in the graphic state. The ICC profile 649 /* Set the color space in the graphic state. The ICC profile
642 will be set later if we actually use the space. Procs will be 650 will be set later if we actually use the space. Procs will be
643 sampled now though. Also, the finish procedure is on the stack 651 sampled now though. Also, the finish procedure is on the stack
@@ -692,16 +700,16 @@ cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict, ulong dictkey)
692 /* Stable memory due to current caching of color space */ 700 /* Stable memory due to current caching of color space */
693 code = gs_cspace_build_CIEA(&pcs, NULL, mem->stable_memory); 701 code = gs_cspace_build_CIEA(&pcs, NULL, mem->stable_memory);
694 if (code < 0) 702 if (code < 0)
695 return code; 703 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
696 pcie = pcs->params.a; 704 pcie = pcs->params.a;
697 code = cie_a_param(imemory, CIEdict, pcie, &procs, &has_a_procs, 705 code = cie_a_param(imemory, CIEdict, pcie, &procs, &has_a_procs,
698 &has_lmn_procs); 706 &has_lmn_procs);
699 if (code < 0) 707 if (code < 0)
700 return code; 708 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
701 /* Push finalize procedure on the execution stack */ 709 /* Push finalize procedure on the execution stack */
702 code = cie_cache_push_finish(i_ctx_p, cie_a_finish, (gs_ref_memory_t *)imem, pcie); 710 code = cie_cache_push_finish(i_ctx_p, cie_a_finish, (gs_ref_memory_t *)imem, pcie);
703 if (code < 0) 711 if (code < 0)
704 return code; 712 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
705 if (!has_a_procs && !has_lmn_procs) { 713 if (!has_a_procs && !has_lmn_procs) {
706 pcie->common.caches.DecodeLMN->floats 714 pcie->common.caches.DecodeLMN->floats
707 .params.is_identity = true; 715 .params.is_identity = true;
@@ -713,7 +721,7 @@ cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict, ulong dictkey)
713 code = cie_prepare_iccproc(i_ctx_p, &pcie->RangeA, 721 code = cie_prepare_iccproc(i_ctx_p, &pcie->RangeA,
714 &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A"); 722 &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A");
715 if (code < 0) 723 if (code < 0)
716 return code; 724 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
717 } else { 725 } else {
718 pcie->caches.DecodeA.floats.params.is_identity = true; 726 pcie->caches.DecodeA.floats.params.is_identity = true;
719 } 727 }
@@ -842,8 +850,10 @@ cie_cache_finish_store(i_ctx_t *i_ctx_p, bool replicate)
842 code = float_param(ref_stack_index(&o_stack, 850 code = float_param(ref_stack_index(&o_stack,
843 (replicate ? 0 : gx_cie_cache_size - 1 - i)), 851 (replicate ? 0 : gx_cie_cache_size - 1 - i)),
844 &pcache->values[i]); 852 &pcache->values[i]);
845 if (code < 0) 853 if (code < 0) {
854 esp -= 2; /* pop pointer to cache */
846 return code; 855 return code;
856 }
847 } 857 }
848 } 858 }
849#ifdef DEBUG 859#ifdef DEBUG
diff --git a/psi/zcolor1.c b/psi/zcolor1.c
index 56dcf71d8..1a341ff41 100644
--- a/psi/zcolor1.c
+++ b/psi/zcolor1.c
@@ -94,6 +94,7 @@ static int
94zsetcolortransfer(i_ctx_t *i_ctx_p) 94zsetcolortransfer(i_ctx_t *i_ctx_p)
95{ 95{
96 os_ptr op = osp; 96 os_ptr op = osp;
97 os_ptr ep = esp;
97 int code; 98 int code;
98 99
99 check_proc(op[-3]); 100 check_proc(op[-3]);
@@ -130,8 +131,14 @@ zsetcolortransfer(i_ctx_t *i_ctx_p)
130 (code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.gray, 131 (code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.gray,
131 igs->set_transfer.gray, igs, 132 igs->set_transfer.gray, igs,
132 zcolor_remap_one_finish)) < 0 133 zcolor_remap_one_finish)) < 0
133 ) 134 )
135 {
136 /* Return the exec stack to the state it was in before we started the setup
137 * for the transfer function evaluation.
138 */
139 esp = ep;
134 return code; 140 return code;
141 }
135 return o_push_estack; 142 return o_push_estack;
136} 143}
137 144
diff --git a/psi/zcontrol.c b/psi/zcontrol.c
index ebcd5e385..36da22ca0 100644
--- a/psi/zcontrol.c
+++ b/psi/zcontrol.c
@@ -239,8 +239,10 @@ end_runandhide(i_ctx_t *i_ctx_p)
239{ 239{
240 int code; 240 int code;
241 241
242 if ((code = runandhide_restore_hidden(i_ctx_p, esp, esp - 1)) < 0) 242 if ((code = runandhide_restore_hidden(i_ctx_p, esp, esp - 1)) < 0) {
243 esp -= 2;
243 return code; 244 return code;
245 }
244 esp -= 2; /* pop the hidden value and its atributes */ 246 esp -= 2; /* pop the hidden value and its atributes */
245 return o_pop_estack; 247 return o_pop_estack;
246} 248}
diff --git a/psi/zfile.c b/psi/zfile.c
index b30784029..d6575ea86 100644
--- a/psi/zfile.c
+++ b/psi/zfile.c
@@ -425,8 +425,10 @@ file_continue(i_ctx_t *i_ctx_p)
425 uint len = r_size(pscratch); 425 uint len = r_size(pscratch);
426 uint code; 426 uint code;
427 427
428 if (len < devlen) 428 if (len < devlen) {
429 esp -= 5; /* pop proc, pfen, devlen, iodev , mark */
429 return_error(gs_error_rangecheck); /* not even room for device len */ 430 return_error(gs_error_rangecheck); /* not even room for device len */
431 }
430 432
431 do { 433 do {
432 memcpy((char *)pscratch->value.bytes, iodev->dname, devlen); 434 memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
@@ -435,8 +437,10 @@ file_continue(i_ctx_t *i_ctx_p)
435 if (code == ~(uint) 0) { /* all done */ 437 if (code == ~(uint) 0) { /* all done */
436 esp -= 5; /* pop proc, pfen, devlen, iodev , mark */ 438 esp -= 5; /* pop proc, pfen, devlen, iodev , mark */
437 return o_pop_estack; 439 return o_pop_estack;
438 } else if (code > len) /* overran string */ 440 } else if (code > len) { /* overran string */
441 esp -= 5; /* pop proc, pfen, devlen, iodev , mark */
439 return_error(gs_error_rangecheck); 442 return_error(gs_error_rangecheck);
443 }
440 else if (iodev != iodev_default(imemory) 444 else if (iodev != iodev_default(imemory)
441 || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) { 445 || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) {
442 push(1); 446 push(1);
diff --git a/psi/zht1.c b/psi/zht1.c
index 86f32e858..7265abbcf 100644
--- a/psi/zht1.c
+++ b/psi/zht1.c
@@ -115,8 +115,11 @@ setcolorscreen_finish(i_ctx_t *i_ctx_p)
115 115
116 pdht->order = pdht->components[0].corder; 116 pdht->order = pdht->components[0].corder;
117 code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht); 117 code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
118 if (code < 0) 118 if (code < 0) {
119 esp -= 7;
120 setcolorscreen_cleanup(i_ctx_p);
119 return code; 121 return code;
122 }
120 istate->screen_procs.red = esp[-5]; 123 istate->screen_procs.red = esp[-5];
121 istate->screen_procs.green = esp[-4]; 124 istate->screen_procs.green = esp[-4];
122 istate->screen_procs.blue = esp[-3]; 125 istate->screen_procs.blue = esp[-3];
diff --git a/psi/zht2.c b/psi/zht2.c
index 48d7dd3b8..60bd6567e 100644
--- a/psi/zht2.c
+++ b/psi/zht2.c
@@ -558,8 +558,11 @@ sethalftone_finish(i_ctx_t *i_ctx_p)
558 if (pdht->components) 558 if (pdht->components)
559 pdht->order = pdht->components[0].corder; 559 pdht->order = pdht->components[0].corder;
560 code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht); 560 code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
561 if (code < 0) 561 if (code < 0) {
562 esp -= 4;
563 sethalftone_cleanup(i_ctx_p);
562 return code; 564 return code;
565 }
563 istate->halftone = esp[-2]; 566 istate->halftone = esp[-2];
564 esp -= 4; 567 esp -= 4;
565 sethalftone_cleanup(i_ctx_p); 568 sethalftone_cleanup(i_ctx_p);
diff --git a/psi/zpath1.c b/psi/zpath1.c
index e9eca1c44..b9fb2e593 100644
--- a/psi/zpath1.c
+++ b/psi/zpath1.c
@@ -232,6 +232,8 @@ path_continue(i_ctx_t *i_ctx_p)
232 path_cleanup(i_ctx_p); 232 path_cleanup(i_ctx_p);
233 return o_pop_estack; 233 return o_pop_estack;
234 default: /* error */ 234 default: /* error */
235 esp -= 6;
236 path_cleanup(i_ctx_p);
235 return code; 237 return code;
236 case gs_pe_moveto: 238 case gs_pe_moveto:
237 esp[2] = esp[-4]; /* moveto proc */ 239 esp[2] = esp[-4]; /* moveto proc */
diff --git a/psi/zpcolor.c b/psi/zpcolor.c
index fb601a303..3c3e29e21 100644
--- a/psi/zpcolor.c
+++ b/psi/zpcolor.c
@@ -351,8 +351,10 @@ pattern_paint_finish(i_ctx_t *i_ctx_p)
351 } 351 }
352 pinst = (gs_pattern1_instance_t *)gs_currentcolor(igs->saved)->pattern; 352 pinst = (gs_pattern1_instance_t *)gs_currentcolor(igs->saved)->pattern;
353 /* If pinst is NULL after all of that then we are not going to recover */ 353 /* If pinst is NULL after all of that then we are not going to recover */
354 if (pinst == NULL) 354 if (pinst == NULL) {
355 esp -= 5;
355 return_error(gs_error_unknownerror); 356 return_error(gs_error_unknownerror);
357 }
356 } 358 }
357 pgs = igs; 359 pgs = igs;
358 360
@@ -360,8 +362,10 @@ pattern_paint_finish(i_ctx_t *i_ctx_p)
360 if (pinst->is_clist) { 362 if (pinst->is_clist) {
361 /* Send the compositor command to close the PDF14 device */ 363 /* Send the compositor command to close the PDF14 device */
362 code = gs_pop_pdf14trans_device(pgs, true); 364 code = gs_pop_pdf14trans_device(pgs, true);
363 if (code < 0) 365 if (code < 0) {
366 esp -= 5;
364 return code; 367 return code;
368 }
365 } else { 369 } else {
366 /* Not a clist, get PDF14 buffer information */ 370 /* Not a clist, get PDF14 buffer information */
367 code = pdf14_get_buffer_information(pgs->device, 371 code = pdf14_get_buffer_information(pgs->device,
@@ -369,8 +373,10 @@ pattern_paint_finish(i_ctx_t *i_ctx_p)
369 true); 373 true);
370 /* PDF14 device (and buffer) is destroyed when pattern cache 374 /* PDF14 device (and buffer) is destroyed when pattern cache
371 entry is removed */ 375 entry is removed */
372 if (code < 0) 376 if (code < 0) {
377 esp -= 5;
373 return code; 378 return code;
379 }
374 } 380 }
375 } 381 }
376 code = gx_pattern_cache_add_entry(igs, pdev, &ctile); 382 code = gx_pattern_cache_add_entry(igs, pdev, &ctile);