Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame^] | 1 | From 34a8c5aa987d4db5234172a62218b168371606b1 Mon Sep 17 00:00:00 2001 |
| 2 | From: Chris Liddell <chris.liddell@artifex.com> |
| 3 | Date: Tue, 2 Oct 2018 16:02:58 +0100 |
| 4 | Subject: [PATCH 4/5] For hidden operators, pass a name object to error |
| 5 | handler. |
| 6 | |
| 7 | In normal operation, Postscript error handlers are passed the object which |
| 8 | triggered the error: this is invariably an operator object. |
| 9 | |
| 10 | The issue arises when an error is triggered by an operator which is for internal |
| 11 | use only, and that operator is then passed to the error handler, meaning it |
| 12 | becomes visible to the error handler code. |
| 13 | |
| 14 | By converting to a name object, the error message is still valid, but we no |
| 15 | longer expose internal use only operators. |
| 16 | |
| 17 | The change in gs_dps1.ps is related to the above: previously an error in |
| 18 | scheck would throw an error against .gcheck, but as .gcheck is now a hidden |
| 19 | operator, it resulted in a name object being passed to the error handler. As |
| 20 | scheck is a 'real' operator, it's better to use the real operator, rather than |
| 21 | the name of an internal, hidden one. |
| 22 | |
| 23 | CVE: CVE-2018-17961 |
| 24 | Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git] |
| 25 | Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> |
| 26 | --- |
| 27 | Resource/Init/gs_dps1.ps | 2 +- |
| 28 | psi/interp.c | 33 ++++++++++++++++++++++++--------- |
| 29 | 2 files changed, 25 insertions(+), 10 deletions(-) |
| 30 | |
| 31 | diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps |
| 32 | index 1182f53..ec5db61 100644 |
| 33 | --- a/Resource/Init/gs_dps1.ps |
| 34 | +++ b/Resource/Init/gs_dps1.ps |
| 35 | @@ -21,7 +21,7 @@ level2dict begin |
| 36 | % ------ Virtual memory ------ % |
| 37 | |
| 38 | /currentshared /.currentglobal load def |
| 39 | -/scheck /.gcheck load def |
| 40 | +/scheck {.gcheck} bind odef |
| 41 | %****** FOLLOWING IS WRONG ****** |
| 42 | /shareddict currentdict /globaldict .knownget not { 20 dict } if def |
| 43 | |
| 44 | diff --git a/psi/interp.c b/psi/interp.c |
| 45 | index cd894f9..b70769d 100644 |
| 46 | --- a/psi/interp.c |
| 47 | +++ b/psi/interp.c |
| 48 | @@ -678,6 +678,8 @@ again: |
| 49 | epref = &doref; |
| 50 | /* Push the error object on the operand stack if appropriate. */ |
| 51 | if (!GS_ERROR_IS_INTERRUPT(code)) { |
| 52 | + byte buf[260], *bufptr; |
| 53 | + uint rlen; |
| 54 | /* Replace the error object if within an oparray or .errorexec. */ |
| 55 | osp++; |
| 56 | if (osp >= ostop) { |
| 57 | @@ -686,23 +688,36 @@ again: |
| 58 | } |
| 59 | *osp = *perror_object; |
| 60 | errorexec_find(i_ctx_p, osp); |
| 61 | - /* If using SAFER, hand a name object to the error handler, rather than the executable |
| 62 | - * object/operator itself. |
| 63 | - */ |
| 64 | - if (i_ctx_p->LockFilePermissions) { |
| 65 | + |
| 66 | + if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) { |
| 67 | code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr); |
| 68 | if (code < 0) { |
| 69 | const char *unknownstr = "--unknown--"; |
| 70 | rlen = strlen(unknownstr); |
| 71 | memcpy(buf, unknownstr, rlen); |
| 72 | + bufptr = buf; |
| 73 | } |
| 74 | else { |
| 75 | - buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; |
| 76 | - rlen += 4; |
| 77 | + ref *tobj; |
| 78 | + bufptr[rlen] = '\0'; |
| 79 | + /* Only pass a name object if the operator doesn't exist in systemdict |
| 80 | + * i.e. it's an internal operator we have hidden |
| 81 | + */ |
| 82 | + code = dict_find_string(systemdict, (const char *)bufptr, &tobj); |
| 83 | + if (code < 0) { |
| 84 | + buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; |
| 85 | + rlen += 4; |
| 86 | + bufptr = buf; |
| 87 | + } |
| 88 | + else { |
| 89 | + bufptr = NULL; |
| 90 | + } |
| 91 | + } |
| 92 | + if (bufptr) { |
| 93 | + code = name_ref(imemory, buf, rlen, osp, 1); |
| 94 | + if (code < 0) |
| 95 | + make_null(osp); |
| 96 | } |
| 97 | - code = name_ref(imemory, buf, rlen, osp, 1); |
| 98 | - if (code < 0) |
| 99 | - make_null(osp); |
| 100 | } |
| 101 | } |
| 102 | goto again; |
| 103 | -- |
| 104 | 2.7.4 |
| 105 | |