| From 34a8c5aa987d4db5234172a62218b168371606b1 Mon Sep 17 00:00:00 2001 |
| From: Chris Liddell <chris.liddell@artifex.com> |
| Date: Tue, 2 Oct 2018 16:02:58 +0100 |
| Subject: [PATCH 4/5] For hidden operators, pass a name object to error |
| handler. |
| |
| In normal operation, Postscript error handlers are passed the object which |
| triggered the error: this is invariably an operator object. |
| |
| The issue arises when an error is triggered by an operator which is for internal |
| use only, and that operator is then passed to the error handler, meaning it |
| becomes visible to the error handler code. |
| |
| By converting to a name object, the error message is still valid, but we no |
| longer expose internal use only operators. |
| |
| The change in gs_dps1.ps is related to the above: previously an error in |
| scheck would throw an error against .gcheck, but as .gcheck is now a hidden |
| operator, it resulted in a name object being passed to the error handler. As |
| scheck is a 'real' operator, it's better to use the real operator, rather than |
| the name of an internal, hidden one. |
| |
| CVE: CVE-2018-17961 |
| Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git] |
| Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> |
| --- |
| Resource/Init/gs_dps1.ps | 2 +- |
| psi/interp.c | 33 ++++++++++++++++++++++++--------- |
| 2 files changed, 25 insertions(+), 10 deletions(-) |
| |
| diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps |
| index 1182f53..ec5db61 100644 |
| --- a/Resource/Init/gs_dps1.ps |
| +++ b/Resource/Init/gs_dps1.ps |
| @@ -21,7 +21,7 @@ level2dict begin |
| % ------ Virtual memory ------ % |
| |
| /currentshared /.currentglobal load def |
| -/scheck /.gcheck load def |
| +/scheck {.gcheck} bind odef |
| %****** FOLLOWING IS WRONG ****** |
| /shareddict currentdict /globaldict .knownget not { 20 dict } if def |
| |
| diff --git a/psi/interp.c b/psi/interp.c |
| index cd894f9..b70769d 100644 |
| --- a/psi/interp.c |
| +++ b/psi/interp.c |
| @@ -678,6 +678,8 @@ again: |
| epref = &doref; |
| /* Push the error object on the operand stack if appropriate. */ |
| if (!GS_ERROR_IS_INTERRUPT(code)) { |
| + byte buf[260], *bufptr; |
| + uint rlen; |
| /* Replace the error object if within an oparray or .errorexec. */ |
| osp++; |
| if (osp >= ostop) { |
| @@ -686,23 +688,36 @@ again: |
| } |
| *osp = *perror_object; |
| errorexec_find(i_ctx_p, osp); |
| - /* If using SAFER, hand a name object to the error handler, rather than the executable |
| - * object/operator itself. |
| - */ |
| - if (i_ctx_p->LockFilePermissions) { |
| + |
| + if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) { |
| code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr); |
| if (code < 0) { |
| const char *unknownstr = "--unknown--"; |
| rlen = strlen(unknownstr); |
| memcpy(buf, unknownstr, rlen); |
| + bufptr = buf; |
| } |
| else { |
| - buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; |
| - rlen += 4; |
| + ref *tobj; |
| + bufptr[rlen] = '\0'; |
| + /* Only pass a name object if the operator doesn't exist in systemdict |
| + * i.e. it's an internal operator we have hidden |
| + */ |
| + code = dict_find_string(systemdict, (const char *)bufptr, &tobj); |
| + if (code < 0) { |
| + buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; |
| + rlen += 4; |
| + bufptr = buf; |
| + } |
| + else { |
| + bufptr = NULL; |
| + } |
| + } |
| + if (bufptr) { |
| + code = name_ref(imemory, buf, rlen, osp, 1); |
| + if (code < 0) |
| + make_null(osp); |
| } |
| - code = name_ref(imemory, buf, rlen, osp, 1); |
| - if (code < 0) |
| - make_null(osp); |
| } |
| } |
| goto again; |
| -- |
| 2.7.4 |
| |