From 1f9a91c86bd56acf57826b9b0e020ebe1953e2ae Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Thu, 4 Oct 2018 10:42:13 +0100 Subject: [PATCH 3/5] Bug 699832: add control over hiding error handlers. With a previous commit changing error handling in SAFER so the handler gets passed a name object (rather than executable object), it is less critical to hide the error handlers. This introduces a -dSAFERERRORS option to force only use of the default error handlers. It also adds a .setsafererrors Postscript call, meaning a caller, without -dSAFERERRORS, can create their own default error handlers (in errordict, as normal), and then call .setsafererrors meaning their own handlers are always called. With -dSAFERERRORS or after a call to .setsafererrors, .setsafererrors is removed. CVE: CVE-2018-17961 Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git] Signed-off-by: Hongxu Jia --- Resource/Init/gs_init.ps | 42 +++++++++++++++++++++++++++++------------ psi/interp.c | 49 ++++++++++++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps index bec307d..f952f32 100644 --- a/Resource/Init/gs_init.ps +++ b/Resource/Init/gs_init.ps @@ -188,6 +188,16 @@ currentdict /DELAYSAFER known { /DELAYSAFER //true def /NOSAFER //true def } if currentdict /PARANOIDSAFER known or % PARANOIDSAFER is equivalent } ifelse def + +/SAFERERRORS +currentdict /NOSAFERERRORS known +{ + //false +} +{ + currentdict /SAFERERRORS known +} ifelse def + currentdict /SHORTERRORS known /SHORTERRORS exch def currentdict /TTYPAUSE known /TTYPAUSE exch def currentdict /WRITESYSTEMDICT known /WRITESYSTEMDICT exch def @@ -1123,12 +1133,23 @@ errordict begin } bind def end % errordict -% Put all the default handlers in gserrordict -gserrordict -errordict {2 index 3 1 roll put} forall -noaccess pop -% remove the non-standard errors from errordict +gserrordict /unknownerror errordict /unknownerror get put errordict /unknownerror .undef + +/.SAFERERRORLIST ErrorNames def +/.setsafererrors +{ +% Put all the requested handlers in gserrordict + gserrordict + //.SAFERERRORLIST + {dup errordict exch get 2 index 3 1 roll put} forall + noaccess pop + systemdict /.setsafeerrors .forceundef + systemdict /.SAFERERRORLIST .forceundef +} bind executeonly odef + +SAFERERRORS {.setsafererrors} if + % Define a stable private copy of handleerror that we will always use under % JOBSERVER mode. /.GShandleerror errordict /handleerror get def @@ -1760,18 +1781,15 @@ currentdict /.runlibfile .undef % Bind all the operators defined as procedures. /.bindoperators % binds operators in currentdict - { % Temporarily disable the typecheck error. - errordict /typecheck 2 copy get - errordict /typecheck { pop } put % pop the command + { currentdict { dup type /operatortype eq - { % This might be a real operator, so bind might cause a typecheck, - % but we've made the error a no-op temporarily. - .bind + { + % This might be a real operator, so bind might cause a typecheck + {.bind} .internalstopped pop } if pop pop } forall - put } def DELAYBIND not { .bindoperators } if diff --git a/psi/interp.c b/psi/interp.c index 3dd5f7a..cd894f9 100644 --- a/psi/interp.c +++ b/psi/interp.c @@ -662,27 +662,18 @@ again: if (gs_errorname(i_ctx_p, code, &error_name) < 0) return code; /* out-of-range error code! */ - /* If LockFilePermissions is true, we only refer to gserrordict, which - * is not accessible to Postcript jobs + /* We refer to gserrordict first, which is not accessible to Postcript jobs + * If we're running with SAFERERRORS all the handlers are copied to gserrordict + * so we'll always find the default one. If not SAFERERRORS, only gs specific + * errors are in gserrordict. */ - if (i_ctx_p->LockFilePermissions) { - if (((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || - dict_find(perrordict, &error_name, &epref) <= 0)) - ) - return code; /* error name not in errordict??? */ - } - else { - /* - * For greater Adobe compatibility, only the standard PostScript errors - * are defined in errordict; the rest are in gserrordict. - */ - if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || - (dict_find(perrordict, &error_name, &epref) <= 0 && - (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || - dict_find(perrordict, &error_name, &epref) <= 0)) - ) - return code; /* error name not in errordict??? */ - } + if (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || + (dict_find(perrordict, &error_name, &epref) <= 0 && + (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || + dict_find(perrordict, &error_name, &epref) <= 0)) + ) + return code; /* error name not in errordict??? */ + doref = *epref; epref = &doref; /* Push the error object on the operand stack if appropriate. */ @@ -695,6 +686,24 @@ 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) { + 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); + } + else { + buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; + rlen += 4; + } + code = name_ref(imemory, buf, rlen, osp, 1); + if (code < 0) + make_null(osp); + } } goto again; } -- 2.7.4