diff --git a/.ghostscript.metadata b/.ghostscript.metadata new file mode 100644 index 0000000..cc5991b --- /dev/null +++ b/.ghostscript.metadata @@ -0,0 +1 @@ +9d8ddff3382113bf4a1640368350e05652c93613 SOURCES/ghostscript-9.25.tar.xz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7c760a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/ghostscript-9.25.tar.xz diff --git a/SOURCES/ghostscript-9.23-100-run-dvipdf-securely.patch b/SOURCES/ghostscript-9.23-100-run-dvipdf-securely.patch new file mode 100644 index 0000000..80b0b7d --- /dev/null +++ b/SOURCES/ghostscript-9.23-100-run-dvipdf-securely.patch @@ -0,0 +1,22 @@ +From 91c9c6d17d445781ee572c281b8b9d75d96f9df8 Mon Sep 17 00:00:00 2001 +From: "David Kaspar [Dee'Kej]" +Date: Fri, 7 Oct 2016 13:57:01 +0200 +Subject: [PATCH] Make sure 'dvipdf' is being run securely + +--- + lib/dvipdf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/dvipdf b/lib/dvipdf +index 802aeab..c92dfb0 100755 +--- a/lib/dvipdf ++++ b/lib/dvipdf +@@ -43,4 +43,4 @@ fi + + # We have to include the options twice because -I only takes effect if it + # appears before other options. +-exec dvips -Ppdf $DVIPSOPTIONS -q -f "$infile" | $GS_EXECUTABLE $OPTIONS -q -P- -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sstdout=%stderr -sOutputFile="$outfile" $OPTIONS -c .setpdfwrite - ++exec dvips -R -Ppdf $DVIPSOPTIONS -q -f "$infile" | $GS_EXECUTABLE $OPTIONS -q -P- -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sstdout=%stderr -sOutputFile="$outfile" $OPTIONS -c .setpdfwrite - +-- +2.14.3 + diff --git a/SOURCES/ghostscript-cve-2018-17961.patch b/SOURCES/ghostscript-cve-2018-17961.patch new file mode 100644 index 0000000..9f8653c --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-17961.patch @@ -0,0 +1,842 @@ +From b0222e5e39712999f22084996a6b85a120b9389e Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Thu, 20 Sep 2018 16:35:28 +0100 +Subject: [PATCH 1/6] Bug 699795: add operand checking to + .setnativefontmapbuilt + +.setnativefontmapbuilt .forceputs a value into systemdict - it is intended +to be a boolean, but in this case was being called with a compound object +(a dictionary). Such an object, in local VM, being forced into systemdict +would then confuse the garbager, since it could be restored away with the +reference remaining. + +This adds operand checking, so .setnativefontmapbuilt will simply ignore +anything other than a boolean value, and also removes the definition of +.setnativefontmapbuilt after use, since it is only used in two, closely +related places. +--- + Resource/Init/gs_fonts.ps | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 38f0f6c..45b6613 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -372,9 +372,13 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if + % of strings: what the system thinks is the ps name, + % and the access path. + /.setnativefontmapbuilt { % set whether we've been run +- systemdict exch /.nativefontmapbuilt exch .forceput ++ dup type /booleantype eq { ++ systemdict exch /.nativefontmapbuilt exch .forceput ++ } ++ {pop} ++ ifelse + } .bind executeonly def +-systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt ++systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec + /.buildnativefontmap { % - .buildnativefontmap + systemdict /.nativefontmapbuilt .knownget not + { //false} if +@@ -415,9 +419,10 @@ systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt + } forall + } if + % record that we've been run +- //true .setnativefontmapbuilt ++ //true //.setnativefontmapbuilt exec + } ifelse + } bind def ++currentdict /.setnativefontmapbuilt .forceundef + + % Create the dictionary that registers the .buildfont procedure + % (called by definefont) for each FontType. +-- +2.17.2 + + +From a54c9e61e7d02bbc620bcba9b1c208462a876afb Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Sat, 29 Sep 2018 15:34:55 +0100 +Subject: [PATCH 2/6] Bug 699816: Improve hiding of security critical custom + operators + +Make procedures that use .forceput/.forcedef/.forceundef into operators. + +The result of this is that errors get reported against the "top" operator, +rather than the "called" operator within the procedure. + +For example: +/myproc +{ + myop +} bind def + +If 'myop' throws an error, the error handler will be passed the 'myop' +operator. Promoting 'myproc' to a operator means the error handler will be +passed 'myproc'. +--- + Resource/Init/gs_diskn.ps | 2 +- + Resource/Init/gs_dps.ps | 2 +- + Resource/Init/gs_fntem.ps | 2 +- + Resource/Init/gs_fonts.ps | 10 +++++----- + Resource/Init/gs_lev2.ps | 13 +++++++++---- + Resource/Init/gs_pdfwr.ps | 2 +- + Resource/Init/gs_setpd.ps | 25 +++++++++++++++++-------- + Resource/Init/gs_typ32.ps | 14 +++++++++----- + Resource/Init/gs_type1.ps | 2 +- + Resource/Init/pdf_base.ps | 2 +- + Resource/Init/pdf_draw.ps | 10 +++++----- + Resource/Init/pdf_font.ps | 8 ++++---- + Resource/Init/pdf_main.ps | 4 ++-- + Resource/Init/pdf_ops.ps | 8 ++++---- + 14 files changed, 61 insertions(+), 43 deletions(-) + +diff --git a/Resource/Init/gs_diskn.ps b/Resource/Init/gs_diskn.ps +index 5540715..26ec0b5 100644 +--- a/Resource/Init/gs_diskn.ps ++++ b/Resource/Init/gs_diskn.ps +@@ -53,7 +53,7 @@ systemdict begin + exch .setglobal + } + if +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Modify .putdevparams to force regeneration of .searchabledevs list + /.putdevparams { +diff --git a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps +index cad7056..daf7b0f 100644 +--- a/Resource/Init/gs_dps.ps ++++ b/Resource/Init/gs_dps.ps +@@ -70,7 +70,7 @@ + % Save a copy of the initial gstate. + //systemdict /savedinitialgstate gstate readonly .forceput + .setglobal +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Initialize local dictionaries and gstate when creating a new context. + % Note that until this completes, we are in the anomalous situation of +diff --git a/Resource/Init/gs_fntem.ps b/Resource/Init/gs_fntem.ps +index 3ceee18..c1f7651 100644 +--- a/Resource/Init/gs_fntem.ps ++++ b/Resource/Init/gs_fntem.ps +@@ -408,7 +408,7 @@ currentdict end def + exit + } loop + exch setglobal +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + currentdict end /ProcSet defineresource pop + +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 45b6613..89c3ab7 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -377,8 +377,8 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if + } + {pop} + ifelse +-} .bind executeonly def +-systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec ++} .bind executeonly odef ++systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt + /.buildnativefontmap { % - .buildnativefontmap + systemdict /.nativefontmapbuilt .knownget not + { //false} if +@@ -419,7 +419,7 @@ systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec + } forall + } if + % record that we've been run +- //true //.setnativefontmapbuilt exec ++ //true .setnativefontmapbuilt + } ifelse + } bind def + currentdict /.setnativefontmapbuilt .forceundef +@@ -1103,7 +1103,7 @@ $error /SubstituteFont { } put + + % Check to make sure the font was actually loaded. + dup 3 index .fontknownget +- { dup /PathLoad 4 index //.putgstringcopy exec ++ { dup /PathLoad 4 index .putgstringcopy + 4 1 roll pop pop pop //true exit + } if + +@@ -1115,7 +1115,7 @@ $error /SubstituteFont { } put + { % Stack: origfontname fontdirectory path filefontname + 2 index 1 index .fontknownget + { % Yes. Stack: origfontname fontdirectory path filefontname fontdict +- dup 4 -1 roll /PathLoad exch //.putgstringcopy exec ++ dup 4 -1 roll /PathLoad exch .putgstringcopy + % Stack: origfontname fontdirectory filefontname fontdict + 3 -1 roll pop + % Stack: origfontname filefontname fontdict +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index eee0b9f..a8ed892 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -163,10 +163,11 @@ end + % Set them again to the new values. From here on, we are safe, + % since a context switch will consult userparams. + .setuserparams +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + /setuserparams { % setuserparams - +- .setuserparams2 ++ {.setuserparams2} stopped ++ {/setuserparams load $error /errorname get signalerror} if + } .bind odef + % Initialize user parameters managed here. + /JobName () .definepsuserparam +@@ -415,7 +416,9 @@ psuserparams /ProcessDSCComment {.checkprocesscomment} put + + % VMReclaim and VMThreshold are user parameters. + /setvmthreshold { % setvmthreshold - +- mark /VMThreshold 2 .argindex .dicttomark .setuserparams2 pop ++ mark /VMThreshold 2 .argindex .dicttomark {.setuserparams2} stopped ++ {pop /setvmthreshold load $error /errorname get signalerror} ++ {pop} ifelse + } odef + /vmreclaim { % vmreclaim - + dup 0 gt { +@@ -427,7 +430,9 @@ psuserparams /ProcessDSCComment {.checkprocesscomment} put + ifelse + } { + % VMReclaim userparam controls enable/disable GC +- mark /VMReclaim 2 index .dicttomark .setuserparams2 pop ++ mark /VMReclaim 2 index .dicttomark {.setuserparams2} stopped ++ {pop /vmreclaim load $error /errorname get signalerror} ++ {pop} ifelse + } ifelse + } odef + -1 setvmthreshold +diff --git a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps +index fb1c419..58e75d3 100644 +--- a/Resource/Init/gs_pdfwr.ps ++++ b/Resource/Init/gs_pdfwr.ps +@@ -660,7 +660,7 @@ currentdict /.pdfmarkparams .undef + { + pop + } ifelse +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Use the DSC processing hook to pass DSC comments to the driver. + % We use a pseudo-parameter named DSC whose value is an array: +diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps +index 8fa7c51..afb4ffa 100644 +--- a/Resource/Init/gs_setpd.ps ++++ b/Resource/Init/gs_setpd.ps +@@ -608,6 +608,20 @@ NOMEDIAATTRS { + % in the dictionary with the policy value, + % and we replace the key in the dictionary with its prior value + % (or remove it if it had no prior value). ++ ++% Making this an operator means we can properly hide ++% the contents - specifically .forceput ++/1Policy ++{ ++ % Roll back the failed request to its previous status. ++ SETPDDEBUG { (Rolling back.) = pstack flush } if ++ 3 index 2 index 3 -1 roll .forceput ++ 4 index 1 index .knownget ++ { 4 index 3 1 roll .forceput } ++ { 3 index exch .undef } ++ ifelse ++} bind executeonly odef ++ + /.policyprocs mark + % These procedures are called with the following on the stack: + % +@@ -631,14 +645,7 @@ NOMEDIAATTRS { + /setpagedevice .systemvar /configurationerror signalerror + } ifelse + } bind +- 1 { % Roll back the failed request to its previous status. +-SETPDDEBUG { (Rolling back.) = pstack flush } if +- 3 index 2 index 3 -1 roll .forceput +- 4 index 1 index .knownget +- { 4 index 3 1 roll .forceput } +- { 3 index exch .undef } +- ifelse +- } .bind executeonly % must be bound and hidden for .forceput ++ 1 /1Policy load + 7 { % For PageSize only, just impose the request. + 1 index /PageSize eq + { pop pop 1 index /PageSize 7 put } +@@ -646,6 +653,8 @@ SETPDDEBUG { (Rolling back.) = pstack flush } if + ifelse + } bind + .dicttomark readonly def ++currentdict /1Policy undef ++ + /.applypolicies % .applypolicies + % + { 1 index /Policies get 1 index +diff --git a/Resource/Init/gs_typ32.ps b/Resource/Init/gs_typ32.ps +index b6600b0..9150f71 100644 +--- a/Resource/Init/gs_typ32.ps ++++ b/Resource/Init/gs_typ32.ps +@@ -79,15 +79,19 @@ systemdict /.removeglyphs .undef + .dicttomark /ProcSet defineresource pop + + /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse +-.cidfonttypes begin +- +-4 % CIDFontType 4 = FontType 32 +-{ dup /FontType 32 .forceput ++/CIDFontType4 ++{ ++ dup /FontType 32 .forceput + dup /CharStrings 20 dict .forceput + 1 index exch .buildfont32 exch pop +-} .bind executeonly def % must be bound and hidden for .forceput ++} .bind executeonly odef ++.cidfonttypes begin ++ ++ ++4 /CIDFontType4 load def % CIDFontType 4 = FontType 32 + + end % .cidfonttypes ++currentdict /CIDFontType4 .forceundef + + % Define the BuildGlyph procedure. + % Since Type 32 fonts are indexed by CID, there is no BuildChar procedure. +diff --git a/Resource/Init/gs_type1.ps b/Resource/Init/gs_type1.ps +index efdae48..2935d9c 100644 +--- a/Resource/Init/gs_type1.ps ++++ b/Resource/Init/gs_type1.ps +@@ -283,7 +283,7 @@ currentdict /closesourcedict .undef + } if + 2 copy /WeightVector exch .forceput + .setweightvector +-} .bind executeonly def ++} .bind executeonly odef + end + + % Register the font types for definefont. +diff --git a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps +index a82a2a3..7ccd4cd 100644 +--- a/Resource/Init/pdf_base.ps ++++ b/Resource/Init/pdf_base.ps +@@ -218,7 +218,7 @@ currentdict /num-chars-dict .undef + } ifelse + } ifelse + } ifelse +-} bind executeonly def ++} bind executeonly odef + /PDFScanRules_true << /PDFScanRules //true >> def + /PDFScanRules_null << /PDFScanRules //null >> def + /.pdfrun { % .pdfrun - +diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps +index d1b6ac9..c239daf 100644 +--- a/Resource/Init/pdf_draw.ps ++++ b/Resource/Init/pdf_draw.ps +@@ -1158,7 +1158,7 @@ currentdict end readonly def + Q + PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if + PDFfile exch setfileposition +-} bind executeonly def ++} bind executeonly odef + + /.pdfpaintproc { + %% Get the /m from pdfopdict (must be present) +@@ -1189,7 +1189,7 @@ currentdict end readonly def + { + switch_to_text_marking_ops + } if +-}bind executeonly def ++}bind executeonly odef + + /resolvepattern { % resolvepattern + % Don't do the resolvestream now: just capture the data +@@ -2353,7 +2353,7 @@ currentdict /last-ditch-bpc-csp undef + }{ + pdfdict /AppearanceNumber 0 .forceput + } ifelse +-}bind executeonly def ++}bind executeonly odef + + /MakeAppearanceName { + pdfdict /AppearanceNumber get +@@ -2382,7 +2382,7 @@ currentdict /last-ditch-bpc-csp undef + DoForm + pdfdict /.PreservePDFForm 3 -1 roll .forceput + grestore +-} bind executeonly def ++} bind executeonly odef + + /DoForm { + %% save the current value, if its true we will set it to false later, in order +@@ -2541,7 +2541,7 @@ currentdict /last-ditch-bpc-csp undef + end + } if + pdfdict /.PreservePDFForm 3 -1 roll .forceput +-} bind executeonly def ++} bind executeonly odef + + /_dops_save 1 array def + +diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps +index feaf0d0..535b14a 100644 +--- a/Resource/Init/pdf_font.ps ++++ b/Resource/Init/pdf_font.ps +@@ -718,7 +718,7 @@ currentdict end readonly def + {pop pop pop} + ifelse + +-} bind executeonly def ++} bind executeonly odef + + currentdict /.DoToUnicode? .forceundef + +@@ -1241,7 +1241,7 @@ currentdict /eexec_pdf_param_dict .undef + } bdef + dup currentdict Encoding .processToUnicode + currentdict end .completefont exch pop +-} bind executeonly def ++} bind executeonly odef + /.adjustcharwidth { % .adjustcharwidth + % Enforce the metrics, in glyph space, to the values found in the PDF Font object + % - force wy == 0 (assumed, and not stored in the PDF font) +@@ -2026,7 +2026,7 @@ currentdict /CMap_read_dict undef + } if + /findresource cvx /undefined signalerror + } loop +-} bind executeonly def ++} bind executeonly odef + + /buildCIDType0 { % buildCIDType0 + dup /BaseFont get findCIDFont exch pop +@@ -2211,7 +2211,7 @@ currentdict /CMap_read_dict undef + /Type0 //buildType0 + /Type1 //buildType1 + /MMType1 //buildType1 +- /Type3 //buildType3 ++ /Type3 /buildType3 load + /TrueType //buildTrueType + /CIDFontType0 //buildCIDType0 + /CIDFontType2 //buildCIDType2 +diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps +index 09f8735..c823e69 100644 +--- a/Resource/Init/pdf_main.ps ++++ b/Resource/Init/pdf_main.ps +@@ -660,7 +660,7 @@ currentdict /runpdfstring .undef + } forall + pop + } ifelse +-} bind executeonly def ++} bind executeonly odef + + currentdict /pdf_collection_files .undef + +@@ -2715,7 +2715,7 @@ currentdict /PDF2PS_matrix_key undef + .setglobal + /RepairedAnError exch def + /Repaired exch def +-} bind executeonly def ++} bind executeonly odef + + % Display the contents of a page (including annotations). + /showpagecontents { % showpagecontents - +diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps +index c45fc51..8672d61 100644 +--- a/Resource/Init/pdf_ops.ps ++++ b/Resource/Init/pdf_ops.ps +@@ -193,7 +193,7 @@ currentdict /gput_always_allow .undef + pdfformaterror + } ifelse + } if +-} bind executeonly def ++} bind executeonly odef + + % Save PDF gstate + /qstate { % - qstate +@@ -451,7 +451,7 @@ currentdict /gput_always_allow .undef + %% a gsave, so we haven't copied it to /self, if we don't do that here + %% then transparent annotations cause an invalid access error. + currentdict //nodict eq {/self dup load end 5 dict begin def} if +-} bind executeonly def ++} bind executeonly odef + /AIS { .setalphaisshape } bind executeonly def + /BM { + /.setblendmode where { +@@ -1077,7 +1077,7 @@ end readonly def + pdfopdict /v {inside_text_v} bind .forceput + pdfopdict /y {inside_text_y} bind .forceput + pdfopdict /re {inside_text_re} bind .forceput +-} bind executeonly def ++} bind executeonly odef + + /switch_to_normal_marking_ops { + pdfopdict /m {normal_m} bind .forceput +@@ -1086,7 +1086,7 @@ end readonly def + pdfopdict /v {normal_v} bind .forceput + pdfopdict /y {normal_y} bind .forceput + pdfopdict /re {normal_re} bind .forceput +-} bind executeonly def ++} bind executeonly odef + + /BT { + currentdict /TextSaveMatrix known { +-- +2.17.2 + + +From 1778db6bc10a8d60dfe986b22d2300326733ddd6 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Thu, 4 Oct 2018 10:42:13 +0100 +Subject: [PATCH 3/6] 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. +--- + 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 b94f873..a627eec 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 +@@ -1137,12 +1147,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 +@@ -1774,18 +1795,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 1dec9b6..d60c733 100644 +--- a/psi/interp.c ++++ b/psi/interp.c +@@ -661,27 +661,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. */ +@@ -694,6 +685,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.17.2 + + +From a6807394bd94b708be24758287b606154daaaed9 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Tue, 2 Oct 2018 16:02:58 +0100 +Subject: [PATCH 4/6] 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. +--- + 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 d60c733..6dc0dda 100644 +--- a/psi/interp.c ++++ b/psi/interp.c +@@ -677,6 +677,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) { +@@ -685,23 +687,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.17.2 + + +From a5a9bf8c6a63aa4ac6874234fe8cd63e72077291 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 10 Oct 2018 23:25:51 +0100 +Subject: [PATCH 5/6] Bug 699938: .loadfontloop must be an operator + +In the fix for Bug 699816, I omitted to make .loadfontloop into an operator, to +better hide .forceundef and .putgstringcopy. +--- + Resource/Init/gs_fonts.ps | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 89c3ab7..72feff2 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -1148,7 +1148,7 @@ $error /SubstituteFont { } put + + } loop % end of loop + +- } bind executeonly def % must be bound and hidden for .putgstringcopy ++ } bind executeonly odef % must be bound and hidden for .putgstringcopy + + currentdict /.putgstringcopy .undef + +-- +2.17.2 + + +From 2756f0efae1d3966989b15a6526c5d80848b5015 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 28 Nov 2018 17:12:08 +0000 +Subject: [PATCH 6/6] Bug 700290: Fix problems with DELAYBIND and font + substitution + +Judicious use of immediate evaluation for .setnativefontmapbuilt and +.putgstringcopy to avoid problems with DELAYBIND +--- + Resource/Init/gs_fonts.ps | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 72feff2..7a57366 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -419,7 +419,7 @@ systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt + } forall + } if + % record that we've been run +- //true .setnativefontmapbuilt ++ //true //.setnativefontmapbuilt + } ifelse + } bind def + currentdict /.setnativefontmapbuilt .forceundef +@@ -1103,7 +1103,7 @@ $error /SubstituteFont { } put + + % Check to make sure the font was actually loaded. + dup 3 index .fontknownget +- { dup /PathLoad 4 index .putgstringcopy ++ { dup /PathLoad 4 index //.putgstringcopy + 4 1 roll pop pop pop //true exit + } if + +@@ -1115,7 +1115,7 @@ $error /SubstituteFont { } put + { % Stack: origfontname fontdirectory path filefontname + 2 index 1 index .fontknownget + { % Yes. Stack: origfontname fontdirectory path filefontname fontdict +- dup 4 -1 roll /PathLoad exch .putgstringcopy ++ dup 4 -1 roll /PathLoad exch //.putgstringcopy + % Stack: origfontname fontdirectory filefontname fontdict + 3 -1 roll pop + % Stack: origfontname filefontname fontdict +@@ -1149,8 +1149,7 @@ $error /SubstituteFont { } put + } loop % end of loop + + } bind executeonly odef % must be bound and hidden for .putgstringcopy +- +-currentdict /.putgstringcopy .undef ++currentdict /.putgstringcopy .forceundef + + % Define a procedure to load all known fonts. + % This isn't likely to be very useful. +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-18073.patch b/SOURCES/ghostscript-cve-2018-18073.patch new file mode 100644 index 0000000..846afed --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-18073.patch @@ -0,0 +1,289 @@ +From c76bf1cb7cc419534006631ea139ae20801fd824 Mon Sep 17 00:00:00 2001 +From: Nancy Durgin +Date: Tue, 18 Sep 2018 11:54:58 -0700 +Subject: [PATCH 1/3] Undefine some additional internal operators. + +.type, .writecvs, .setSMask, .currentSMask + +These don't seem to be referenced anywhere outside of the initialization code, +which binds their usages. Passes cluster if they are removed. +--- + Resource/Init/gs_init.ps | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 55d6923..4aff036 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2212,6 +2212,7 @@ SAFER { .setsafeglobal } if + /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice ++ /.type /.writecvs /.setSMask /.currentSMask + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +@@ -2230,7 +2231,7 @@ SAFER { .setsafeglobal } if + % test files/utilities, or engineers expressed a desire to keep them visible. + % + %/currentdevice /.sort /.buildfont0 /.buildfont1 /.buildfont2 /.buildfont3 /.buildfont4 /.buildfont9 /.buildfont10 /.buildfont11 +- %/.buildfotn32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors ++ %/.buildfont32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors + %/currentdevice /.quit /.setuseciecolor /.needinput /.setoverprintmode /.special_op /.dicttomark /.knownget + %/.FAPIavailable /.FAPIpassfont /.FAPIrebuildfont /.FAPIBuildGlyph /.FAPIBuildChar /.FAPIBuildGlyph9 + %/.tempfile /.numicc_components /.set_outputintent /.max /.min /.vmreclaim /.getpath /.setglobal +-- +2.17.2 + + +From f8ccc7dfb990336b1ca55f65f2e1a8ecdcb76adf Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Tue, 25 Sep 2018 15:38:14 +0100 +Subject: [PATCH 2/3] Bug 699793: Hide the .needinput operator + +This removes the .needinput operator from systemdict, ensuring it can only +be used in the initialization code, and not called erroneously from random +Postscript. +--- + Resource/Init/gs_init.ps | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 4aff036..6a5c1df 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -831,12 +831,26 @@ userdict /.currentresourcefile //null put + /.runstring { + 0 0 .systemvmstring .systemvmSFD cvx { .runexec } execute0 + } bind def ++ + % Define the procedure that the C code uses to set up for executing + % a string that may be received in pieces. ++% ++% Immediate evaluation doesn't work on operators (like .needinput) ++% so calling .runstringbegin will throw an undefined error if we ++% undefined .needinput so it cannot be accessed outside the init ++% code. But, we can store the operator in an array, use immediate ++% evaluation on the array to get the operator, then undefined the ++% array (and because they are both of the same name, the operator ++% get undefined too). ++% This prevents random Postscript from erroneously calling .needinput ++% and forcing the interpreter into an invalid state. ++/.needinput ++1 .systemvmarray dup 0 /.needinput load put ++def + /.runstringbegin { +- 1 .systemvmarray dup 0 /.needinput load put cvx % { .needinput } in systemvm ++ 1 .systemvmarray dup 0 //.needinput 0 get put cvx % { .needinput } in systemvm + 0 0 .systemvmstring .systemvmSFD cvx .runexec +-} bind def ++} bind executeonly def + + % Define a special version of runlibfile that aborts on errors. + /runlibfile0 +@@ -2212,7 +2226,7 @@ SAFER { .setsafeglobal } if + /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice +- /.type /.writecvs /.setSMask /.currentSMask ++ /.type /.writecvs /.setSMask /.currentSMask /.needinput + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +-- +2.17.2 + + +From 34cc326eb2c5695833361887fe0b32e8d987741c Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 10 Oct 2018 15:38:10 +0100 +Subject: [PATCH 3/3] Bug 699927: don't include operator arrays in execstack + output + +When we transfer the contents of the execution stack into the array, take the +extra step of replacing any operator arrays on the stack with the operator +that reference them. + +This prevents the contents of Postscript defined, internal only operators (those +created with .makeoperator) being exposed via execstack (and thus, via error +handling). + +This necessitates a change in the resource remapping 'resource', which contains +a procedure which relies on the contents of the operators arrays being present. +As we already had internal-only variants of countexecstack and execstack +(.countexecstack and .execstack) - using those, and leaving thier operation +including the operator arrays means the procedure continues to work correctly. + +Both .countexecstack and .execstack are undefined after initialization. + +Also, when we store the execstack (or part thereof) for an execstackoverflow +error, make the same oparray/operator substitution as above for execstack. +--- + Resource/Init/gs_init.ps | 4 ++-- + Resource/Init/gs_resmp.ps | 2 +- + psi/int.mak | 2 +- + psi/interp.c | 14 +++++++++++--- + psi/interp.h | 2 ++ + psi/zcontrol.c | 13 ++++++++++--- + 6 files changed, 27 insertions(+), 10 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 6a5c1df..5bec480 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2187,7 +2187,7 @@ SAFER { .setsafeglobal } if + %% but can be easily restored (just delete the name from the list in the array). In future + %% we may remove the operator and the code implementation entirely. + [ +- /.bitadd /.charboxpath /.cond /.countexecstack /.execstack /.runandhide /.popdevicefilter ++ /.bitadd /.charboxpath /.cond /.runandhide /.popdevicefilter + /.execfile /.filenamesplit /.file_name_parent + /.setdefaultmatrix /.isprocfilter /.unread /.psstringencode + /.buildsampledfunction /.isencapfunction /.currentaccuratecurves /.currentcurvejoin /.currentdashadapt /.currentdotlength +@@ -2226,7 +2226,7 @@ SAFER { .setsafeglobal } if + /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice +- /.type /.writecvs /.setSMask /.currentSMask /.needinput ++ /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +diff --git a/Resource/Init/gs_resmp.ps b/Resource/Init/gs_resmp.ps +index 7cacaf8..9bb4263 100644 +--- a/Resource/Init/gs_resmp.ps ++++ b/Resource/Init/gs_resmp.ps +@@ -183,7 +183,7 @@ setpacking + % We don't check them. + + currentglobal //false setglobal % bGlobal +- countexecstack array execstack % bGlobal [execstack] ++ //false .countexecstack array //false .execstack % bGlobal [execstack] + dup //null exch % bGlobal [execstack] null [execstack] + length 3 sub -1 0 { % bGlobal [execstack] null i + 2 index exch get % bGlobal [execstack] null proc +diff --git a/psi/int.mak b/psi/int.mak +index 5d9b3d5..6ab5bf0 100644 +--- a/psi/int.mak ++++ b/psi/int.mak +@@ -323,7 +323,7 @@ $(PSOBJ)zarray.$(OBJ) : $(PSSRC)zarray.c $(OP) $(memory__h)\ + + $(PSOBJ)zcontrol.$(OBJ) : $(PSSRC)zcontrol.c $(OP) $(string__h)\ + $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)\ +- $(INT_MAK) $(MAKEDIRS) ++ $(interp_h) $(INT_MAK) $(MAKEDIRS) + $(PSCC) $(PSO_)zcontrol.$(OBJ) $(C_) $(PSSRC)zcontrol.c + + $(PSOBJ)zdict.$(OBJ) : $(PSSRC)zdict.c $(OP)\ +diff --git a/psi/interp.c b/psi/interp.c +index 3dd5f7a..1dec9b6 100644 +--- a/psi/interp.c ++++ b/psi/interp.c +@@ -142,7 +142,6 @@ static int oparray_pop(i_ctx_t *); + static int oparray_cleanup(i_ctx_t *); + static int zerrorexec(i_ctx_t *); + static int zfinderrorobject(i_ctx_t *); +-static int errorexec_find(i_ctx_t *, ref *); + static int errorexec_pop(i_ctx_t *); + static int errorexec_cleanup(i_ctx_t *); + static int zsetstackprotect(i_ctx_t *); +@@ -737,7 +736,7 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_stack_t * pstack, int skip, ref * arr) + { + uint size = ref_stack_count(pstack) - skip; + uint save_space = ialloc_space(idmemory); +- int code; ++ int code, i; + + if (size > 65535) + size = 65535; +@@ -746,6 +745,15 @@ copy_stack(i_ctx_t *i_ctx_p, const ref_stack_t * pstack, int skip, ref * arr) + if (code >= 0) + code = ref_stack_store(pstack, arr, size, 0, 1, true, idmemory, + "copy_stack"); ++ /* If we are copying the exec stack, try to replace any oparrays with ++ * with the operator than references them ++ */ ++ if (pstack == &e_stack) { ++ for (i = 0; i < size; i++) { ++ if (errorexec_find(i_ctx_p, &arr->value.refs[i]) < 0) ++ make_null(&arr->value.refs[i]); ++ } ++ } + ialloc_set_space(idmemory, save_space); + return code; + } +@@ -1910,7 +1918,7 @@ zfinderrorobject(i_ctx_t *i_ctx_p) + * .errorexec with errobj != null, store it in *perror_object and return 1, + * otherwise return 0; + */ +-static int ++int + errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object) + { + long i; +diff --git a/psi/interp.h b/psi/interp.h +index e9275b9..4f551d1 100644 +--- a/psi/interp.h ++++ b/psi/interp.h +@@ -91,5 +91,7 @@ void gs_interp_reset(i_ctx_t *i_ctx_p); + /* Define the top-level interface to the interpreter. */ + int gs_interpret(i_ctx_t **pi_ctx_p, ref * pref, int user_errors, + int *pexit_code, ref * perror_object); ++int ++errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object); + + #endif /* interp_INCLUDED */ +diff --git a/psi/zcontrol.c b/psi/zcontrol.c +index 36da22c..0362cf4 100644 +--- a/psi/zcontrol.c ++++ b/psi/zcontrol.c +@@ -24,6 +24,7 @@ + #include "ipacked.h" + #include "iutil.h" + #include "store.h" ++#include "interp.h" + + /* Forward references */ + static int check_for_exec(const_os_ptr); +@@ -787,7 +788,7 @@ zexecstack2(i_ctx_t *i_ctx_p) + /* Continuation operator to do the actual transfer. */ + /* r_size(op1) was set just above. */ + static int +-do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1) ++do_execstack(i_ctx_t *i_ctx_p, bool include_marks, bool include_oparrays, os_ptr op1) + { + os_ptr op = osp; + ref *arefs = op1->value.refs; +@@ -829,6 +830,12 @@ do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1) + strlen(tname), (const byte *)tname); + break; + } ++ case t_array: ++ case t_shortarray: ++ case t_mixedarray: ++ if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0) ++ make_null(rq); ++ break; + default: + ; + } +@@ -841,14 +848,14 @@ execstack_continue(i_ctx_t *i_ctx_p) + { + os_ptr op = osp; + +- return do_execstack(i_ctx_p, false, op); ++ return do_execstack(i_ctx_p, false, false, op); + } + static int + execstack2_continue(i_ctx_t *i_ctx_p) + { + os_ptr op = osp; + +- return do_execstack(i_ctx_p, op->value.boolval, op - 1); ++ return do_execstack(i_ctx_p, op->value.boolval, true, op - 1); + } + + /* - .needinput - */ +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-18284.patch b/SOURCES/ghostscript-cve-2018-18284.patch new file mode 100644 index 0000000..8e765f5 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-18284.patch @@ -0,0 +1,240 @@ +From 8d19fdf63f91f50466b08f23e2d93d37a4c5ea0b Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Mon, 15 Oct 2018 11:28:28 +0100 +Subject: [PATCH] Make .forceput unavailable from '.policyprocs' helper + dictionary + +Bug #69963 "1Policy is a dangerous operator, any callers should be odef" + +Leaving the .policyprocs dictionary with a procedure which is a simple +wrapper for .forceput effectively leaves .forceput available. + +It seems that the only reason to have .policyprocs is to minimise the +code in .applypolicies, so we can remove the dictionary and put the +code straight into .applypolicies, which we can then bind and make +executeonly, which hides the .forceput. Also, since we don't need +.applypolicies after startup, we can undefine that from systemdict too. + +While we're here, review all the uses of .force* to make certain that +there are no other similar cases. This showed a few places where we +hadn't made a function executeonly, so do that too. Its probably not +required, since I'm reasonably sure its impossible to load those +functions as packed arrays (they are all defined as operators), but lets +have a belt and braces approach, the additional time cost is negligible. +--- + Resource/Init/gs_diskn.ps | 2 +- + Resource/Init/gs_dps.ps | 2 +- + Resource/Init/gs_epsf.ps | 2 +- + Resource/Init/gs_fonts.ps | 4 +- + Resource/Init/gs_init.ps | 2 +- + Resource/Init/gs_setpd.ps | 100 ++++++++++++++++++++------------------ + 6 files changed, 58 insertions(+), 54 deletions(-) + +diff --git a/Resource/Init/gs_diskn.ps b/Resource/Init/gs_diskn.ps +index 26ec0b5..fd694bc 100644 +--- a/Resource/Init/gs_diskn.ps ++++ b/Resource/Init/gs_diskn.ps +@@ -61,7 +61,7 @@ systemdict begin + % doesn't get run enough to justify the complication + //.putdevparams + //systemdict /.searchabledevs .forceundef +-} .bind odef % must be bound and hidden for .forceundef ++} .bind executeonly odef % must be bound and hidden for .forceundef + + % ------ extend filenameforall to handle wildcards in %dev% part of pattern -------% + /filenameforall { +diff --git a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps +index daf7b0f..00c14d5 100644 +--- a/Resource/Init/gs_dps.ps ++++ b/Resource/Init/gs_dps.ps +@@ -124,7 +124,7 @@ + /savedinitialgstate .systemvar setgstate gsave + % Wrap up. + end .setglobal +-} odef ++} bind executeonly odef + + % Check whether an object is a procedure. + /.proccheck { % .proccheck +diff --git a/Resource/Init/gs_epsf.ps b/Resource/Init/gs_epsf.ps +index e4037d9..2d0f677 100644 +--- a/Resource/Init/gs_epsf.ps ++++ b/Resource/Init/gs_epsf.ps +@@ -31,7 +31,7 @@ + /EPSBoundingBoxState 5 def + /EPSBoundingBoxSetState { + //systemdict /EPSBoundingBoxState 3 -1 roll .forceput +-} .bind odef % .forceput must be bound and hidden ++} .bind executeonly odef % .forceput must be bound and hidden + + % Parse 4 numbers for a bounding box + /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 7a57366..052a191 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -583,7 +583,7 @@ buildfontdict 3 /.buildfont3 cvx put + } bind def + /.setloadingfont { + //systemdict /.loadingfont 3 -1 roll .forceput +-} .bind odef % .forceput must be bound and hidden ++} .bind executeonly odef % .forceput must be bound and hidden + /.loadfont + { % Some buggy fonts leave extra junk on the stack, + % so we have to make a closure that records the stack depth +@@ -1012,7 +1012,7 @@ $error /SubstituteFont { } put + dup length string copy + .forceput setglobal + } ifelse +-} .bind odef % must be bound and hidden for .forceput ++} .bind executeonly odef % must be bound and hidden for .forceput + + % Attempt to load a font from a file. + /.tryloadfont { % .tryloadfont true +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 2114a2a..0b900e6 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2244,7 +2244,7 @@ SAFER { .setsafeglobal } if + /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice +- /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack ++ /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack /.applypolicies + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps +index fab8b84..71eb622 100644 +--- a/Resource/Init/gs_setpd.ps ++++ b/Resource/Init/gs_setpd.ps +@@ -609,6 +609,23 @@ NOMEDIAATTRS { + % and we replace the key in the dictionary with its prior value + % (or remove it if it had no prior value). + ++% These procedures are called with the following on the stack: ++% ++% They are expected to consume the top 2 operands. ++% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) ++% the same as 0, i.e., we signal an error. ++/0Policy { % Set errorinfo and signal a configurationerror. ++ NOMEDIAATTRS { ++ % NOMEDIAATTRS means that the default policy is 7... ++ pop 2 index exch 7 put ++ } { ++ pop dup 4 index exch get 2 array astore ++ $error /errorinfo 3 -1 roll put ++ cleartomark ++ /setpagedevice .systemvar /configurationerror signalerror ++ } ifelse ++} bind executeonly odef ++ + % Making this an operator means we can properly hide + % the contents - specifically .forceput + /1Policy +@@ -617,59 +634,46 @@ NOMEDIAATTRS { + SETPDDEBUG { (Rolling back.) = pstack flush } if + 3 index 2 index 3 -1 roll .forceput + 4 index 1 index .knownget +- { 4 index 3 1 roll .forceput } +- { 3 index exch .undef } ++ { 4 index 3 1 roll .forceput } ++ { 3 index exch .undef } + ifelse + } bind executeonly odef + +-/.policyprocs mark +-% These procedures are called with the following on the stack: +-% +-% They are expected to consume the top 2 operands. +-% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) +-% the same as 0, i.e., we signal an error. +-% +-% M. Sweet, Easy Software Products: +-% +-% Define NOMEDIAATTRS to turn off the default (but unimplementable) media +-% selection policies for setpagedevice. This is used by CUPS to support +-% the standard Adobe media attributes. +- 0 { % Set errorinfo and signal a configurationerror. +- NOMEDIAATTRS { +- % NOMEDIAATTRS means that the default policy is 7... +- pop 2 index exch 7 put +- } { +- pop dup 4 index exch get 2 array astore +- $error /errorinfo 3 -1 roll put +- cleartomark +- /setpagedevice .systemvar /configurationerror signalerror +- } ifelse +- } bind +- 1 /1Policy load +- 7 { % For PageSize only, just impose the request. +- 1 index /PageSize eq +- { pop pop 1 index /PageSize 7 put } +- { .policyprocs 0 get exec } +- ifelse +- } bind +-.dicttomark readonly def +-currentdict /1Policy undef ++/7Policy { % For PageSize only, just impose the request. ++ 1 index /PageSize eq ++ { pop pop 1 index /PageSize 7 put } ++ { .policyprocs 0 get exec } ++ ifelse ++} bind executeonly odef + + /.applypolicies % .applypolicies + % +- { 1 index /Policies get 1 index +- { type /integertype eq +- { pop % already processed +- } +- { 2 copy .knownget not { 1 index /PolicyNotFound get } if +- % Stack: +- % +- .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec +- } +- ifelse +- } +- forall pop +- } bind def ++{ ++ 1 index /Policies get 1 index ++ { type /integertype eq ++ { ++ pop % already processed ++ }{ ++ 2 copy .knownget not { 1 index /PolicyNotFound get } if ++ % Stack: ++ % ++ dup 1 eq { ++ 1Policy ++ }{ ++ dup 7 eq { ++ 7Policy ++ }{ ++ 0Policy ++ } ifelse ++ } ifelse ++ } ifelse ++ } ++ forall pop ++} bind executeonly odef ++ ++currentdict /0Policy undef ++currentdict /1Policy undef ++currentdict /7Policy undef + + % Prepare to present parameters to the device, by spreading them onto the + % operand stack and removing any that shouldn't be presented. +@@ -1012,7 +1016,7 @@ SETPDDEBUG { (Installing.) = pstack flush } if + .postinstall + } ifelse + setglobal % return to original VM allocation mode +-} odef ++} bind executeonly odef + + % We break out the code after calling the Install procedure into a + % separate procedure, since it is executed even if Install causes an error. +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-19134.patch b/SOURCES/ghostscript-cve-2018-19134.patch new file mode 100644 index 0000000..98f378a --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19134.patch @@ -0,0 +1,153 @@ +From 693baf02152119af6e6afd30bb8ec76d14f84bbf Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Thu, 8 Nov 2018 14:43:32 +0000 +Subject: [PATCH] PS interpreter - check the Implementation of a Pattern before + use + +Bug #700141 "Type confusion in setpattern" + +As the bug thread says, we were not checking that the Implementation +of a pattern dictionary was a structure type, leading to a crash when +we tried to treat it as one. + +Here we make the st_pattern1_instance and st_pattern2_instance +structures public definitions and in zsetcolor we check the object +stored under the Implementation key in the supplied dictionary to see if +its a t_struct or t_astruct type, and if it is that its a +st_pattern1_instance or st_pattern2_instance structure. + +If either check fails we throw a typecheck error. + +We need to make the st_pattern1_instance and st_pattern2_instance +definitions public as they are defined in the graphics library and we +need to check in the interpreter. +--- + base/gsptype1.c | 2 +- + base/gsptype2.c | 6 +++--- + base/gsptype2.h | 4 ++-- + base/gxcolor2.h | 4 ++-- + psi/zcolor.c | 11 ++++++++--- + 5 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/base/gsptype1.c b/base/gsptype1.c +index 27fdd5a..e98dde1 100644 +--- a/base/gsptype1.c ++++ b/base/gsptype1.c +@@ -50,7 +50,7 @@ + + /* GC descriptors */ + private_st_pattern1_template(); +-private_st_pattern1_instance(); ++public_st_pattern1_instance(); + + /* GC procedures */ + static ENUM_PTRS_BEGIN(pattern1_instance_enum_ptrs) { +diff --git a/base/gsptype2.c b/base/gsptype2.c +index 791e538..c53eb2e 100644 +--- a/base/gsptype2.c ++++ b/base/gsptype2.c +@@ -33,7 +33,7 @@ + + /* GC descriptors */ + private_st_pattern2_template(); +-private_st_pattern2_instance(); ++public_st_pattern2_instance(); + + /* GC procedures */ + static ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs) { +@@ -206,10 +206,10 @@ gs_pattern2_set_color(const gs_client_color * pcc, gs_gstate * pgs) + + pinst->saved->overprint_mode = pgs->overprint_mode; + pinst->saved->overprint = pgs->overprint; +- ++ + num_comps = pgs->device->color_info.num_components; + for (k = 0; k < num_comps; k++) { +- pgs->color_component_map.color_map[k] = ++ pgs->color_component_map.color_map[k] = + pinst->saved->color_component_map.color_map[k]; + } + code = pcs->type->set_overprint(pcs, pgs); +diff --git a/base/gsptype2.h b/base/gsptype2.h +index f0f26d1..4186201 100644 +--- a/base/gsptype2.h ++++ b/base/gsptype2.h +@@ -57,8 +57,8 @@ typedef struct gs_pattern2_instance_s { + bool shfill; + } gs_pattern2_instance_t; + +-#define private_st_pattern2_instance() /* in gsptype2.c */\ +- gs_private_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ ++#define public_st_pattern2_instance() /* in gsptype2.c */\ ++ gs_public_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ + "gs_pattern2_instance_t", pattern2_instance_enum_ptrs,\ + pattern2_instance_reloc_ptrs) + +diff --git a/base/gxcolor2.h b/base/gxcolor2.h +index 62ec05e..d5b1095 100644 +--- a/base/gxcolor2.h ++++ b/base/gxcolor2.h +@@ -92,8 +92,8 @@ struct gs_pattern1_instance_s { + gx_bitmap_id id; /* key for cached bitmap (= id of mask) */ + }; + +-#define private_st_pattern1_instance() /* in gsptype1.c */\ +- gs_private_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ ++#define public_st_pattern1_instance() /* in gsptype1.c */\ ++ gs_public_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ + "gs_pattern1_instance_t", pattern1_instance_enum_ptrs,\ + pattern1_instance_reloc_ptrs) + +diff --git a/psi/zcolor.c b/psi/zcolor.c +index 7a00d4e..fe81e79 100644 +--- a/psi/zcolor.c ++++ b/psi/zcolor.c +@@ -65,6 +65,8 @@ static const float default_0_1[] = {0, 1, 0, 1, 0, 1, 0, 1}; + + /* imported from gsht.c */ + extern void gx_set_effective_transfer(gs_gstate *); ++extern_st(st_pattern1_instance); ++extern_st(st_pattern2_instance); + + /* Essential forward declarations */ + static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth); +@@ -289,6 +291,9 @@ zsetcolor(i_ctx_t * i_ctx_p) + code = array_get(imemory, pImpl, 0, &pPatInst); + if (code < 0) + return code; ++ if (!r_is_struct(&pPatInst) || (!r_has_stype(&pPatInst, imemory, st_pattern1_instance) && !r_has_stype(&pPatInst, imemory, st_pattern2_instance))) ++ return_error(gs_error_typecheck); ++ + cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t); + n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern) + ? n_comps - 1 +@@ -4421,7 +4426,7 @@ static int setindexedspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int + /* If we have a named color profile and the base space is DeviceN or + Separation use a different set of procedures to ensure the named + color remapping code is used */ +- if (igs->icc_manager->device_named != NULL && ++ if (igs->icc_manager->device_named != NULL && + (base_type == gs_color_space_index_Separation || + base_type == gs_color_space_index_DeviceN)) + pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed_Named); +@@ -5573,7 +5578,7 @@ static int iccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace) + return 0; + + /* As a quick check see if current is same as new */ +- if (ICCdict1.value.bytes == ICCdict2.value.bytes) ++ if (ICCdict1.value.bytes == ICCdict2.value.bytes) + return 1; + + /* Need to check all the various parts */ +@@ -5593,7 +5598,7 @@ static int iccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace) + code2 = dict_find_string(&ICCdict2, "DataSource", &tempref2); + if (code2 <= 0) + return 0; +- if (r_size(tempref1) != r_size(tempref2)) ++ if (r_size(tempref1) != r_size(tempref2)) + return 0; + + buff_size = r_size(tempref1); +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-19409.patch b/SOURCES/ghostscript-cve-2018-19409.patch new file mode 100644 index 0000000..9accb69 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19409.patch @@ -0,0 +1,322 @@ +From 661e8d8fb8248c38d67958beda32f3a5876d0c3f Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 14 Nov 2018 09:50:08 +0000 +Subject: [PATCH 1/4] Bug 700176: check the *output* device for + LockSafetyParams + +When calling .setdevice we were checking if LockSafetyParams was set, and if so +throwing an invalidaccess error. + +The problem is, if another device, for example the pdf14 compositor is the 'top' +device, that does not (and cannot) honour LockSafetyParams. + +To solve this, we'll now use the (relatively new) gxdso_current_output_device +spec_op to retrieve the *actual* output device, and check the LockSafetyParams +flag in that. +--- + psi/zdevice.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/psi/zdevice.c b/psi/zdevice.c +index 8d48b74..c276746 100644 +--- a/psi/zdevice.c ++++ b/psi/zdevice.c +@@ -461,13 +461,17 @@ zputdeviceparams(i_ctx_t *i_ctx_p) + int + zsetdevice(i_ctx_t *i_ctx_p) + { +- gx_device *dev = gs_currentdevice(igs); ++ gx_device *odev = NULL, *dev = gs_currentdevice(igs); + os_ptr op = osp; +- int code = 0; ++ int code = dev_proc(dev, dev_spec_op)(dev, ++ gxdso_current_output_device, (void *)&odev, 0); ++ ++ if (code < 0) ++ return code; + + check_write_type(*op, t_device); +- if (dev->LockSafetyParams) { /* do additional checking if locked */ +- if(op->value.pdevice != dev) /* don't allow a different device */ ++ if (odev->LockSafetyParams) { /* do additional checking if locked */ ++ if(op->value.pdevice != odev) /* don't allow a different device */ + return_error(gs_error_invalidaccess); + } + dev->ShowpageCount = 0; +-- +2.17.2 + + +From ea1b3ef437f39e45874f821c06bd953196625ac5 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 14 Nov 2018 21:04:46 +0000 +Subject: [PATCH 2/4] Bug 700176: Use the actual output device for both devices + in setdevice + +Also fixes bug 700189. + +The pdf14 compositor device, despite being a forwarding device, does not forward +all spec_ops to it's target, only a select few are special cased for that. +gxdso_current_output_device needs to be included in those special cases. + +The original commit (661e8d8fb8248) changed the code to use the spec_op to +retrieve the output device, checking that for LockSafetyParams. If +LockSafetyParams is set, it returns an invalidaccess error if the new device +differs from the current device. + +When we do the comparison between the two devices, we need to check the +output device in both cases. + +This is complicated by the fact that the new device may not have ever been set +(and thus fully initialised), and may not have a spec_op method available at +that point. +--- + base/gdevp14.c | 3 ++- + psi/zdevice.c | 18 ++++++++++++++++-- + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/base/gdevp14.c b/base/gdevp14.c +index f89bc04..f47ed30 100644 +--- a/base/gdevp14.c ++++ b/base/gdevp14.c +@@ -5618,7 +5618,8 @@ pdf14_dev_spec_op(gx_device *pdev, int dev_spec_op, + return 0; + } + } +- if (dev_spec_op == gxdso_get_dev_param || dev_spec_op == gxdso_restrict_bbox) { ++ if (dev_spec_op == gxdso_get_dev_param || dev_spec_op == gxdso_restrict_bbox ++ || dev_spec_op == gxdso_current_output_device) { + return dev_proc(p14dev->target, dev_spec_op)(p14dev->target, dev_spec_op, data, size); + } + +diff --git a/psi/zdevice.c b/psi/zdevice.c +index c276746..4beda04 100644 +--- a/psi/zdevice.c ++++ b/psi/zdevice.c +@@ -462,16 +462,30 @@ int + zsetdevice(i_ctx_t *i_ctx_p) + { + gx_device *odev = NULL, *dev = gs_currentdevice(igs); ++ gx_device *ndev = NULL; + os_ptr op = osp; + int code = dev_proc(dev, dev_spec_op)(dev, + gxdso_current_output_device, (void *)&odev, 0); + + if (code < 0) + return code; +- + check_write_type(*op, t_device); ++ ++ /* slightly icky special case: the new device may not have had ++ * it's procs initialised, at this point - but we need to check ++ * whether we're being asked to change the device here ++ */ ++ if (dev_proc((op->value.pdevice), dev_spec_op) == NULL) ++ ndev = op->value.pdevice; ++ else ++ code = dev_proc((op->value.pdevice), dev_spec_op)(op->value.pdevice, ++ gxdso_current_output_device, (void *)&ndev, 0); ++ ++ if (code < 0) ++ return code; ++ + if (odev->LockSafetyParams) { /* do additional checking if locked */ +- if(op->value.pdevice != odev) /* don't allow a different device */ ++ if(ndev != odev) /* don't allow a different device */ + return_error(gs_error_invalidaccess); + } + dev->ShowpageCount = 0; +-- +2.17.2 + + +From 7c3e7eee829cc3d2582e4aa7ae1fd495ca72cef1 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Mon, 17 Sep 2018 14:06:12 +0100 +Subject: [PATCH 3/4] Implement .currentoutputdevice operator + +The currentdevice operator returns the device currently installed in the +graphics state. This can be the output/page device, but also could be a +forwarding device (bbox device), compositor (pdf14) or subclass device +(erasepage optimisation, First/Last page etc). + +In certain circumstances (for example during a setpagedevice) we want to be +sure we're retrieving the *actual* output/page device. + +The new .currentoutputdevice operator uses the spec_op device method to traverse +any chain of devices and retrieve the final device in the chain, which +should always be the output/page device. +--- + Resource/Init/gs_init.ps | 2 +- + Resource/Init/gs_setpd.ps | 8 +++++++- + base/gdevdflt.c | 5 +++++ + base/gxdevsop.h | 4 ++++ + psi/zdevice.c | 30 ++++++++++++++++++++++++++++++ + 5 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index bec307d..55d6923 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2211,7 +2211,7 @@ SAFER { .setsafeglobal } if + /.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring + /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams +- /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath ++ /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps +index 8fa7c51..aa79b3f 100644 +--- a/Resource/Init/gs_setpd.ps ++++ b/Resource/Init/gs_setpd.ps +@@ -877,7 +877,13 @@ SETPDDEBUG { (Selecting.) = pstack flush } if + % Stack: mark + SETPDDEBUG { (Constructing.) = pstack flush } if + +- currentdevice .devicename 2 index /OutputDevice get eq ++ % Non-obvious: we need to check the name of the output device, to tell ++ % whether we're going to have to replace the entire device chain (which ++ % may be only one device, or may be multiple devices. ++ % If we're not replacing the entire change, we have to use the device in ++ % the graphics state, so the configuration of the entire device chain is ++ % correctly set. ++ .currentoutputdevice .devicename 2 index /OutputDevice get eq + { currentdevice } + { 1 index /OutputDevice get finddevice } + ifelse +diff --git a/base/gdevdflt.c b/base/gdevdflt.c +index 3cb9fbd..b5bd82b 100644 +--- a/base/gdevdflt.c ++++ b/base/gdevdflt.c +@@ -1044,6 +1044,11 @@ gx_default_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size) + dev_param_req_t *request = (dev_param_req_t *)data; + return gx_default_get_param(pdev, request->Param, request->list); + } ++ case gxdso_current_output_device: ++ { ++ *(gx_device **)data = pdev; ++ return 0; ++ } + } + return_error(gs_error_undefined); + } +diff --git a/base/gxdevsop.h b/base/gxdevsop.h +index cd3b632..27e3e84 100644 +--- a/base/gxdevsop.h ++++ b/base/gxdevsop.h +@@ -327,6 +327,10 @@ enum { + gxdso_JPEG_passthrough_data, + gxdso_JPEG_passthrough_end, + gxdso_supports_iccpostrender, ++ /* Retrieve the last device in a device chain ++ (either forwarding or subclass devices). ++ */ ++ gxdso_current_output_device, + /* Add new gxdso_ keys above this. */ + gxdso_pattern__LAST + }; +diff --git a/psi/zdevice.c b/psi/zdevice.c +index 4beda04..03285dc 100644 +--- a/psi/zdevice.c ++++ b/psi/zdevice.c +@@ -57,6 +57,7 @@ zcopydevice2(i_ctx_t *i_ctx_p) + } + + /* - currentdevice */ ++/* Returns the current device in the graphics state */ + int + zcurrentdevice(i_ctx_t *i_ctx_p) + { +@@ -71,6 +72,34 @@ zcurrentdevice(i_ctx_t *i_ctx_p) + return 0; + } + ++/* - .currentoutputdevice */ ++/* Returns the *output* device - which will often ++ be the same as above, but not always: if a compositor ++ or other forwarding device, or subclassing device is ++ in force, that will be referenced by the graphics state ++ rather than the output device. ++ This is equivalent of currentdevice device, but returns ++ the *device* object, rather than the dictionary describing ++ the device and device state. ++ */ ++static int ++zcurrentoutputdevice(i_ctx_t *i_ctx_p) ++{ ++ os_ptr op = osp; ++ gx_device *odev = NULL, *dev = gs_currentdevice(igs); ++ gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory; ++ int code = dev_proc(dev, dev_spec_op)(dev, ++ gxdso_current_output_device, (void *)&odev, 0); ++ if (code < 0) ++ return code; ++ ++ push(1); ++ make_tav(op, t_device, ++ (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all, ++ pdevice, odev); ++ return 0; ++} ++ + /* .devicename */ + static int + zdevicename(i_ctx_t *i_ctx_p) +@@ -632,6 +661,7 @@ const op_def zdevice_op_defs[] = + { + {"1.copydevice2", zcopydevice2}, + {"0currentdevice", zcurrentdevice}, ++ {"0.currentoutputdevice", zcurrentoutputdevice}, + {"1.devicename", zdevicename}, + {"0.doneshowpage", zdoneshowpage}, + {"0flushpage", zflushpage}, +-- +2.17.2 + + +From 4d98293c72cc5b5fe456065a3252d39e9ab28e4d Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Mon, 19 Nov 2018 09:00:54 +0000 +Subject: [PATCH 4/4] Coverity ID 327264 - move pointer NULL check + +Due to recent changes in this code, the pointer was being dereferenced +before we checked it to see if it was NULL. Moe the check so that we +check for NULL before dereferencing. + +The 'pvalue' of the operand can be NULL, even if the object is a t_device +type, because invalidate_stack_devices traverses the operand stack +looking for devices, and sets their pvalue member to NULL in order to +invalidate them so that they cannot be used. +--- + psi/zdevice.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/psi/zdevice.c b/psi/zdevice.c +index 03285dc..63865f1 100644 +--- a/psi/zdevice.c ++++ b/psi/zdevice.c +@@ -500,6 +500,9 @@ zsetdevice(i_ctx_t *i_ctx_p) + return code; + check_write_type(*op, t_device); + ++ if (op->value.pdevice == 0) ++ return gs_note_error(gs_error_undefined); ++ + /* slightly icky special case: the new device may not have had + * it's procs initialised, at this point - but we need to check + * whether we're being asked to change the device here +@@ -519,9 +522,6 @@ zsetdevice(i_ctx_t *i_ctx_p) + } + dev->ShowpageCount = 0; + +- if (op->value.pdevice == 0) +- return gs_note_error(gs_error_undefined); +- + code = gs_setdevice_no_erase(igs, op->value.pdevice); + if (code < 0) + return code; +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-19475.patch b/SOURCES/ghostscript-cve-2018-19475.patch new file mode 100644 index 0000000..108ebf2 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19475.patch @@ -0,0 +1,29 @@ +From aeea342904978c9fe17d85f4906a0f6fcce2d315 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Mon, 12 Nov 2018 17:21:33 +0000 +Subject: [PATCH] Bug 700153: restore: always check available stack + +Previously, we were checking there was enough stack space available when the +restore operation required a device change, but since we have to use +Postscript to reset the userparams (ick!), we need the stack check even when +not changing the device. +--- + psi/zdevice2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/psi/zdevice2.c b/psi/zdevice2.c +index 159a0c0..e11b075 100644 +--- a/psi/zdevice2.c ++++ b/psi/zdevice2.c +@@ -277,7 +277,7 @@ restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate + samepagedevice = false; + } + +- if (LockSafetyParams && !samepagedevice) { ++ if (LockSafetyParams) { + const int required_ops = 512; + const int required_es = 32; + +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-19476.patch b/SOURCES/ghostscript-cve-2018-19476.patch new file mode 100644 index 0000000..e20e390 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19476.patch @@ -0,0 +1,666 @@ +From fac7eb144135f3ed8fbb0028ab1f33ce4dcc1985 Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Fri, 21 Sep 2018 13:02:56 +0100 +Subject: [PATCH 1/3] Check all uses of dict_find* to ensure 0 return properly + handled + +dict_find and friends have the surprising quirk of returning < 0 for +an error and > 0 for no error. But they can also return 0 which means +'not found' without it being an error. + +From bug 699801, if the code assumes the usual case where 0 is a success +then an attempt might be made to use the empty dictionary slot returned +by dict_find*, which can lead to seg faults, and certainly won't have +the expected result. +--- + psi/icontext.c | 4 ++-- + psi/zcid.c | 6 ++++-- + psi/zfapi.c | 33 ++++++++++++++++++--------------- + psi/zfcid0.c | 39 +++++++++++++++++++++++++++++---------- + psi/zfcid1.c | 14 ++++++++++---- + psi/zicc.c | 4 ++++ + psi/zpdf_r6.c | 31 +++++++++++++++++++++++-------- + psi/ztoken.c | 2 +- + 8 files changed, 91 insertions(+), 42 deletions(-) + +diff --git a/psi/icontext.c b/psi/icontext.c +index 4db78e0..1fbe486 100644 +--- a/psi/icontext.c ++++ b/psi/icontext.c +@@ -162,7 +162,7 @@ context_state_alloc(gs_context_state_t ** ppcst, + uint size; + ref *system_dict = &pcst->dict_stack.system_dict; + +- if (dict_find_string(system_dict, "userparams", &puserparams) >= 0) ++ if (dict_find_string(system_dict, "userparams", &puserparams) > 0) + size = dict_length(puserparams); + else + size = 300; +@@ -286,7 +286,7 @@ context_state_store(gs_context_state_t * pcst) + /* We need i_ctx_p for access to the d_stack. */ + i_ctx_t *i_ctx_p = pcst; + +- if (dict_find_string(systemdict, "userparams", &puserparams) < 0) ++ if (dict_find_string(systemdict, "userparams", &puserparams) <= 0) + return_error(gs_error_Fatal); + pcst->userparams = *puserparams; + } +diff --git a/psi/zcid.c b/psi/zcid.c +index e394877..5c98fc9 100644 +--- a/psi/zcid.c ++++ b/psi/zcid.c +@@ -72,11 +72,13 @@ TT_char_code_from_CID_no_subst(const gs_memory_t *mem, + } else + return false; /* Must not happen. */ + for (;n--; i++) { ++ int code; ++ + if (array_get(mem, DecodingArray, i, &char_code1) < 0 || + !r_has_type(&char_code1, t_integer)) + return false; /* Must not happen. */ +- if (dict_find(TT_cmap, &char_code1, &glyph_index) >= 0 && +- r_has_type(glyph_index, t_integer)) { ++ code = dict_find(TT_cmap, &char_code1, &glyph_index); ++ if (code > 0 && r_has_type(glyph_index, t_integer)) { + *c = glyph_index->value.intval; + found = true; + if (*c != 0) +diff --git a/psi/zfapi.c b/psi/zfapi.c +index 48e1d54..1b687b0 100644 +--- a/psi/zfapi.c ++++ b/psi/zfapi.c +@@ -1826,6 +1826,9 @@ FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap) + + if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0) + return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ + if (r_type(pref) != t_string) + return_error(gs_error_typecheck); + *xlatmap = (char *)pref->value.bytes; +@@ -1881,11 +1884,11 @@ ps_get_server_param(gs_fapi_server *I, const byte *subtype, + ref *FAPIconfig, *options, *server_options; + i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p; + +- if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) >= 0 ++ if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0 + && r_has_type(FAPIconfig, t_dictionary)) { +- if (dict_find_string(FAPIconfig, "ServerOptions", &options) >= 0 ++ if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0 + && r_has_type(options, t_dictionary)) { +- if (dict_find_string(options, (char *)subtype, &server_options) >= ++ if (dict_find_string(options, (char *)subtype, &server_options) > + 0 && r_has_type(server_options, t_string)) { + *server_param = (byte *) server_options->value.const_bytes; + *server_param_size = r_size(server_options); +@@ -2070,7 +2073,7 @@ zFAPIrebuildfont(i_ctx_t *i_ctx_p) + pdata = (font_data *) pfont->client_data; + I = pbfont->FAPI; + +- if (dict_find_string((op - 1), "SubfontId", &v) >= 0 ++ if (dict_find_string((op - 1), "SubfontId", &v) > 0 + && r_has_type(v, t_integer)) + subfont = v->value.intval; + else +@@ -2277,8 +2280,8 @@ ps_get_glyphname_or_cid(gs_text_enum_t *penum, + if (pbfont->FontType == ft_CID_TrueType && font_file_path) { + ref *pdr2, *fidr, *dummy; + pdr2 = pfont_dict(gs_rootfont(igs)); +- if (dict_find_string(pdr2, "FontInfo", &fidr) && +- dict_find_string(fidr, "GlyphNames2Unicode", &dummy)) ++ if (dict_find_string(pdr2, "FontInfo", &fidr) > 0 && ++ dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0) + { + unsigned char uc[4] = {0}; + unsigned int cc = 0; +@@ -2417,13 +2420,13 @@ ps_get_glyphname_or_cid(gs_text_enum_t *penum, + + fdict = pfont_dict(gs_rootfont(igs)); + code = dict_find_string(fdict, "CMap", &CMapDict); +- if (code >= 0 && r_has_type(CMapDict, t_dictionary)) { ++ if (code > 0 && r_has_type(CMapDict, t_dictionary)) { + code = dict_find_string(CMapDict, "WMode", &WMode); +- if (code >= 0 && r_has_type(WMode, t_integer)) { ++ if (code > 0 && r_has_type(WMode, t_integer)) { + wmode = WMode->value.intval; + } + code = dict_find_string(CMapDict, "CMapName", &CMapName); +- if (code >= 0 && r_has_type(CMapName, t_name)) { ++ if (code > 0 && r_has_type(CMapName, t_name)) { + name_string_ref(imemory, CMapName, &CMapNameStr); + cmapnm = (char *)CMapNameStr.value.bytes; + cmapnmlen = r_size(&CMapNameStr); +@@ -2432,10 +2435,10 @@ ps_get_glyphname_or_cid(gs_text_enum_t *penum, + /* We only have to lookup the char code if we're *not* using an identity ordering + with the exception of Identity-UTF16 which is a different beast altogether */ + if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen)) +- || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) >= 0 ++ || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0 + && r_has_type(CIDSystemInfo, t_dictionary) + && dict_find_string(CIDSystemInfo, "Ordering", +- &Ordering) >= 0 ++ &Ordering) > 0 + && r_has_type(Ordering, t_string) + && strncmp((const char *)Ordering->value.bytes, + "Identity", 8) != 0)) { +@@ -2463,7 +2466,7 @@ ps_get_glyphname_or_cid(gs_text_enum_t *penum, + ref cc32; + ref *gid; + make_int(&cc32, 32); +- if (dict_find(TT_cmap, &cc32, &gid) >= 0) ++ if (dict_find(TT_cmap, &cc32, &gid) > 0) + c = gid->value.intval; + } + cr->char_codes[0] = c; +@@ -2536,7 +2539,7 @@ ps_get_glyphname_or_cid(gs_text_enum_t *penum, + if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0 + || !r_has_type(CharStrings, t_dictionary)) + return_error(gs_error_invalidfont); +- if ((dict_find(CharStrings, &char_name, &glyph_index) < 0) ++ if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0) + || r_has_type(glyph_index, t_null)) { + #ifdef DEBUG + ref *pvalue; +@@ -2955,7 +2958,7 @@ zFAPIpassfont(i_ctx_t *i_ctx_p) + if (code < 0) + return code; + +- if (dict_find_string(op, "SubfontId", &v) >= 0 ++ if (dict_find_string(op, "SubfontId", &v) > 0 + && r_has_type(v, t_integer)) + subfont = v->value.intval; + else +@@ -2968,7 +2971,7 @@ zFAPIpassfont(i_ctx_t *i_ctx_p) + /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us + * to try to use a specific FAPI plugin, so find it, and try it.... + */ +- if (dict_find_string(op, "FAPIPlugInReq", &v) >= 0 && r_type(v) == t_name) { ++ if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) { + + name_string_ref(imemory, v, &reqstr); + +diff --git a/psi/zfcid0.c b/psi/zfcid0.c +index 2aba09a..ba00b21 100644 +--- a/psi/zfcid0.c ++++ b/psi/zfcid0.c +@@ -410,13 +410,25 @@ zbuildfont9(i_ctx_t *i_ctx_p) + * from a file, GlyphData will be an integer, and DataSource will be + * a (reusable) stream. + */ +- if (code < 0 || +- (code = cid_font_data_param(op, &common, &GlyphDirectory)) < 0 || +- (code = dict_find_string(op, "FDArray", &prfda)) < 0 || +- (code = dict_find_string(op, "CIDFontName", &pCIDFontName)) <= 0 || +- (code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes)) < 0 +- ) ++ if (code < 0) ++ return code; ++ code = cid_font_data_param(op, &common, &GlyphDirectory); ++ if (code < 0) ++ return code; ++ code = dict_find_string(op, "FDArray", &prfda); ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ code = dict_find_string(op, "CIDFontName", &pCIDFontName); ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes); ++ if (code < 0) + return code; ++ + /* + * Since build_gs_simple_font may resize the dictionary and cause + * pointers to become invalid, save CIDFontName +@@ -426,17 +438,24 @@ zbuildfont9(i_ctx_t *i_ctx_p) + /* Standard CIDFont, require GlyphData and CIDMapOffset. */ + ref *pGlyphData; + +- if ((code = dict_find_string(op, "GlyphData", &pGlyphData)) < 0 || +- (code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, +- max_uint, &CIDMapOffset)) < 0) ++ code = dict_find_string(op, "GlyphData", &pGlyphData); ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, max_uint, &CIDMapOffset); ++ if (code < 0) + return code; + GlyphData = *pGlyphData; + if (r_has_type(&GlyphData, t_integer)) { + ref *pds; + stream *ignore_s; + +- if ((code = dict_find_string(op, "DataSource", &pds)) < 0) ++ code = dict_find_string(op, "DataSource", &pds); ++ if (code < 0) + return code; ++ if (code == 0) ++ return_error(gs_error_undefined); + check_read_file(i_ctx_p, ignore_s, pds); + DataSource = *pds; + } else { +diff --git a/psi/zfcid1.c b/psi/zfcid1.c +index ef3ece0..e3643a0 100644 +--- a/psi/zfcid1.c ++++ b/psi/zfcid1.c +@@ -347,11 +347,17 @@ zbuildfont11(i_ctx_t *i_ctx_p) + ref rcidmap, ignore_gdir, file, *pfile, cfnstr, *pCIDFontName, CIDFontName, *t; + ulong loca_glyph_pos[2][2]; + int code = cid_font_data_param(op, &common, &ignore_gdir); ++ if (code < 0) ++ return code; + +- if (code < 0 || +- (code = dict_find_string(op, "CIDFontName", &pCIDFontName)) <= 0 || +- (code = dict_int_param(op, "MetricsCount", 0, 4, 0, &MetricsCount)) < 0 +- ) ++ code = dict_find_string(op, "CIDFontName", &pCIDFontName); ++ if (code <= 0) { ++ if (code == 0) ++ return_error(gs_error_undefined); ++ return code; ++ } ++ code = dict_int_param(op, "MetricsCount", 0, 4, 0, &MetricsCount); ++ if (code < 0) + return code; + /* + * Since build_gs_simple_font may resize the dictionary and cause +diff --git a/psi/zicc.c b/psi/zicc.c +index ebf25fe..53bdf34 100644 +--- a/psi/zicc.c ++++ b/psi/zicc.c +@@ -261,6 +261,8 @@ zset_outputintent(i_ctx_t * i_ctx_p) + code = dict_find_string(op, "N", &pnval); + if (code < 0) + return code; ++ if (code == 0) ++ return_error(gs_error_undefined); + ncomps = pnval->value.intval; + + /* verify the DataSource entry. Creat profile from stream */ +@@ -491,6 +493,8 @@ znumicc_components(i_ctx_t * i_ctx_p) + code = dict_find_string(op, "N", &pnval); + if (code < 0) + return code; ++ if (code == 0) ++ return_error(gs_error_undefined); + ncomps = pnval->value.intval; + /* verify the DataSource entry. Create profile from stream */ + if (dict_find_string(op, "DataSource", &pstrmval) <= 0) +diff --git a/psi/zpdf_r6.c b/psi/zpdf_r6.c +index bcd4907..992f316 100644 +--- a/psi/zpdf_r6.c ++++ b/psi/zpdf_r6.c +@@ -145,21 +145,36 @@ zcheck_r6_password(i_ctx_t * i_ctx_p) + return_error(gs_error_typecheck); + + code = dict_find_string(CryptDict, "O", &Oref); +- if (code < 0 || !r_has_type(Oref, t_string)) { ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ if (!r_has_type(Oref, t_string)) + return_error(gs_error_typecheck); +- } ++ + code = dict_find_string(CryptDict, "OE", &OEref); +- if (code < 0 || !r_has_type(OEref, t_string)) { ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ if (!r_has_type(OEref, t_string)) + return_error(gs_error_typecheck); +- } ++ + code = dict_find_string(CryptDict, "U", &Uref); +- if (code < 0 || !r_has_type(Uref, t_string)) { ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ if (!r_has_type(Uref, t_string)) + return_error(gs_error_typecheck); +- } ++ + code = dict_find_string(CryptDict, "UE", &UEref); +- if (code < 0 || !r_has_type(UEref, t_string)) { ++ if (code < 0) ++ return code; ++ if (code == 0) ++ return_error(gs_error_undefined); ++ if (!r_has_type(UEref, t_string)) + return_error(gs_error_typecheck); +- } + + pop(2); + op = osp; +diff --git a/psi/ztoken.c b/psi/ztoken.c +index 519cd09..9314d97 100644 +--- a/psi/ztoken.c ++++ b/psi/ztoken.c +@@ -356,7 +356,7 @@ ztoken_scanner_options(const ref *upref, int old_options) + int code = dict_find_string(upref, pnso->pname, &ppcproc); + + /* Update the options only if the parameter has changed. */ +- if (code >= 0) { ++ if (code > 0) { + if (r_has_type(ppcproc, t_null)) + options &= ~pnso->option; + else +-- +2.17.2 + + +From 434753adbe8be5534bfb9b7d91746023e8073d16 Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Wed, 14 Nov 2018 09:25:13 +0000 +Subject: [PATCH 2/3] Bug #700169 - unchecked type + +Bug #700169 "Type confusion in setcolorspace" + +In seticc() we extract "Name" from a dictionary, if it succeeds we then +use it as a string, without checking the type to see if it is in fact +a string. + +Add a check on the type, and add a couple to check that 'N' is an integer +in a few places too. +--- + psi/zicc.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/psi/zicc.c b/psi/zicc.c +index 53bdf34..dbd2562 100644 +--- a/psi/zicc.c ++++ b/psi/zicc.c +@@ -76,7 +76,7 @@ int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff) + want to have this buffer. */ + /* Check if we have the /Name entry. This is used to associate with + specs that have enumerated types to indicate sRGB sGray etc */ +- if (dict_find_string(ICCdict, "Name", &pnameval) > 0){ ++ if (dict_find_string(ICCdict, "Name", &pnameval) > 0 && r_has_type(pnameval, t_string)){ + uint size = r_size(pnameval); + char *str = (char *)gs_alloc_bytes(gs_gstate_memory(igs), size+1, "seticc"); + memcpy(str, (const char *)pnameval->value.bytes, size); +@@ -263,6 +263,8 @@ zset_outputintent(i_ctx_t * i_ctx_p) + return code; + if (code == 0) + return_error(gs_error_undefined); ++ if (r_type(pnval) != t_integer) ++ return gs_note_error(gs_error_typecheck); + ncomps = pnval->value.intval; + + /* verify the DataSource entry. Creat profile from stream */ +@@ -495,6 +497,8 @@ znumicc_components(i_ctx_t * i_ctx_p) + return code; + if (code == 0) + return_error(gs_error_undefined); ++ if (r_type(pnval) != t_integer) ++ return gs_note_error(gs_error_typecheck); + ncomps = pnval->value.intval; + /* verify the DataSource entry. Create profile from stream */ + if (dict_find_string(op, "DataSource", &pstrmval) <= 0) +-- +2.17.2 + + +From 9a1b3ac61761094713f44dedfce56013308a3b1d Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Wed, 14 Nov 2018 09:31:10 +0000 +Subject: [PATCH 3/3] PS interpreter - add some type checking + +These were 'probably' safe anyway, since they mostly treat the objects +as integers without checking, which at least can't result in a crash. + +Nevertheless, we ought to check. + +The return from comparedictkeys could be wrong if one of the keys had +a value which was not an array, it could incorrectly decide the two +were in fact the same. +--- + psi/zbfont.c | 15 +++++++++------ + psi/zcolor.c | 24 +++++++++++++++++++++++- + psi/zcrd.c | 4 +++- + psi/zfjpx.c | 2 ++ + psi/zfont.c | 3 +++ + psi/zfont0.c | 3 +++ + psi/zimage3.c | 2 ++ + psi/ztrans.c | 4 ++++ + 8 files changed, 49 insertions(+), 8 deletions(-) + +diff --git a/psi/zbfont.c b/psi/zbfont.c +index c1d0461..5b830a2 100644 +--- a/psi/zbfont.c ++++ b/psi/zbfont.c +@@ -666,6 +666,9 @@ sub_font_params(gs_memory_t *mem, const ref *op, gs_matrix *pmat, gs_matrix *pom + return_error(gs_error_invalidfont); + if (dict_find_string(op, "OrigFont", &porigfont) <= 0) + porigfont = NULL; ++ if (porigfont != NULL && !r_has_type(porigfont, t_dictionary)) ++ return_error(gs_error_typecheck); ++ + if (pomat!= NULL) { + if (porigfont == NULL || + dict_find_string(porigfont, "FontMatrix", &pmatrix) <= 0 || +@@ -676,8 +679,8 @@ sub_font_params(gs_memory_t *mem, const ref *op, gs_matrix *pmat, gs_matrix *pom + /* Use the FontInfo/OrigFontName key preferrentially (created by MS PSCRIPT driver) */ + if ((dict_find_string((porigfont != NULL ? porigfont : op), "FontInfo", &pfontinfo) > 0) && + r_has_type(pfontinfo, t_dictionary) && +- (dict_find_string(pfontinfo, "OrigFontName", &pfontname) > 0)) { +- if ((dict_find_string(pfontinfo, "OrigFontStyle", &pfontstyle) > 0) && ++ (dict_find_string(pfontinfo, "OrigFontName", &pfontname) > 0) && (r_has_type(pfontname, t_name) || r_has_type(pfontname, t_string))) { ++ if ((dict_find_string(pfontinfo, "OrigFontStyle", &pfontstyle) > 0) && (r_has_type(pfontname, t_name) || r_has_type(pfontname, t_string)) && + r_size(pfontstyle) > 0) { + const byte *tmpStr1 = pfontname->value.const_bytes; + const byte *tmpStr2 = pfontstyle->value.const_bytes; +@@ -775,11 +778,11 @@ build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype, + avm_space useglob = r_is_local(pencoding) ? avm_local : avm_global; + + ialloc_set_space(idmemory, useglob); +- ++ + count = r_size(pencoding); + if ((code = ialloc_ref_array(&penc, (r_type_attrs(pencoding) & a_readonly), count, "build_gs_font")) < 0) + return code; +- ++ + while (count--) { + ref r; + if (array_get(imemory, pencoding, count, &r) < 0){ +@@ -790,7 +793,7 @@ build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype, + ref_assign(&(penc.value.refs[count]), &r); + } + else { +- ++ + if ((code = obj_cvs(imemory, &r, (byte *)buf, 32, &size, (const byte **)(&bptr))) < 0) { + return(code); + } +@@ -799,7 +802,7 @@ build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype, + ref_assign(&(penc.value.refs[count]), &r); + } + } +- ++ + if ((code = dict_put_string(osp, "Encoding", &penc, NULL)) < 0) + return code; + ialloc_set_space(idmemory, curglob); +diff --git a/psi/zcolor.c b/psi/zcolor.c +index fe81e79..b69b8f5 100644 +--- a/psi/zcolor.c ++++ b/psi/zcolor.c +@@ -1877,7 +1877,12 @@ static int comparedictkey(i_ctx_t * i_ctx_p, ref *CIEdict1, ref *CIEdict2, char + if (r_type(tempref1) == t_null) + return 1; + +- return comparearrays(i_ctx_p, tempref1, tempref2); ++ code = comparearrays(i_ctx_p, tempref1, tempref2); ++ ++ if (code > 0) ++ return 1; ++ else ++ return 0; + } + + static int hasharray(i_ctx_t * i_ctx_p, ref *m1, gs_md5_state_t *md5) +@@ -5473,6 +5478,9 @@ static int seticcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIE + return code; + if (code == 0) + return gs_note_error(gs_error_undefined); ++ if (r_type(tempref) != t_integer) ++ return gs_note_error(gs_error_typecheck); ++ + components = tempref->value.intval; + if (components > count_of(range)/2) + return_error(gs_error_rangecheck); +@@ -5584,6 +5592,10 @@ static int iccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace) + /* Need to check all the various parts */ + code1 = dict_find_string(&ICCdict1, "N", &tempref1); + code2 = dict_find_string(&ICCdict2, "N", &tempref2); ++ ++ if (!r_has_type(tempref1, t_integer) || !r_has_type(tempref2, t_integer)) ++ return 0; ++ + if (code1 != code2) + return 0; + if (tempref1->value.intval != tempref2->value.intval) +@@ -5737,6 +5749,8 @@ static int iccalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESub + return code; + if (code == 0) + return gs_note_error(gs_error_undefined); ++ if (!r_has_type(tempref, t_integer)) ++ return_error(gs_error_typecheck); + + components = tempref->value.intval; + +@@ -5775,6 +5789,9 @@ static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n) + return code; + if (code == 0) + return gs_note_error(gs_error_undefined); ++ if (!r_has_type(tempref, t_integer)) ++ return gs_note_error(gs_error_typecheck); ++ + *n = tempref->value.intval; + return 0; + } +@@ -5791,6 +5808,9 @@ static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr) + return code; + if (code == 0) + return gs_note_error(gs_error_undefined); ++ if (!r_has_type(tempref, t_integer)) ++ return gs_note_error(gs_error_typecheck); ++ + components = tempref->value.intval; + code = dict_find_string(&ICCdict, "Range", &tempref); + if (code > 0 && !r_has_type(tempref, t_null)) { +@@ -5824,6 +5844,8 @@ static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr) + return code; + if (code == 0) + return gs_note_error(gs_error_undefined); ++ if (!r_has_type(tempref, t_integer)) ++ return gs_note_error(gs_error_typecheck); + components = tempref->value.intval; + code = dict_find_string(&ICCdict, "Range", &tempref); + if (code > 0 && !r_has_type(tempref, t_null)) { +diff --git a/psi/zcrd.c b/psi/zcrd.c +index 7993b15..d58160d 100644 +--- a/psi/zcrd.c ++++ b/psi/zcrd.c +@@ -231,8 +231,10 @@ zcrd1_params(os_ptr op, gs_cie_render * pcrd, + return code; + + if (dict_find_string(op, "RenderTable", &pRT) > 0) { +- const ref *prte = pRT->value.const_refs; ++ const ref *prte; + ++ check_read_type(*pRT, t_array); ++ prte = pRT->value.const_refs; + /* Finish unpacking and checking the RenderTable parameter. */ + check_type_only(prte[4], t_integer); + if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4)) +diff --git a/psi/zfjpx.c b/psi/zfjpx.c +index c622f48..db1fae2 100644 +--- a/psi/zfjpx.c ++++ b/psi/zfjpx.c +@@ -115,6 +115,8 @@ z_jpx_decode(i_ctx_t * i_ctx_p) + dict_find_string(csdict, "N", &nref) > 0) { + if_debug1m('w', imemory, "[w] JPX image has an external %"PRIpsint + " channel colorspace\n", nref->value.intval); ++ if (r_type(nref) != t_integer) ++ return gs_note_error(gs_error_typecheck); + switch (nref->value.intval) { + case 1: state.colorspace = gs_jpx_cs_gray; + break; +diff --git a/psi/zfont.c b/psi/zfont.c +index 9c51792..f6c5ae1 100644 +--- a/psi/zfont.c ++++ b/psi/zfont.c +@@ -596,6 +596,9 @@ zfont_info(gs_font *font, const gs_point *pscale, int members, + info->members |= FONT_INFO_FULL_NAME; + if ((members & FONT_INFO_EMBEDDING_RIGHTS) + && (dict_find_string(pfontinfo, "FSType", &pvalue) > 0)) { ++ if (r_type(pvalue) != t_integer) ++ return gs_note_error(gs_error_typecheck); ++ + info->EmbeddingRights = pvalue->value.intval; + info->members |= FONT_INFO_EMBEDDING_RIGHTS; + } +diff --git a/psi/zfont0.c b/psi/zfont0.c +index 4b01c20..a179d7b 100644 +--- a/psi/zfont0.c ++++ b/psi/zfont0.c +@@ -243,6 +243,9 @@ zbuildfont0(i_ctx_t *i_ctx_p) + array_get(pfont->memory, &fdepvector, i, &fdep); + /* The lookup can't fail, because of the pre-check above. */ + dict_find_string(&fdep, "FID", &pfid); ++ if (!r_has_type(pfid, t_fontID)) ++ return gs_note_error(gs_error_typecheck); ++ + data.FDepVector[i] = r_ptr(pfid, gs_font); + } + pfont->data = data; +diff --git a/psi/zimage3.c b/psi/zimage3.c +index 87a3dce..2beda9f 100644 +--- a/psi/zimage3.c ++++ b/psi/zimage3.c +@@ -53,6 +53,8 @@ zimage3(i_ctx_t *i_ctx_p) + dict_find_string(op, "MaskDict", &pMaskDict) <= 0 + ) + return_error(gs_error_rangecheck); ++ check_type(*pDataDict, t_dictionary); ++ check_type(*pMaskDict, t_dictionary); + if ((code = pixel_image_params(i_ctx_p, pDataDict, + (gs_pixel_image_t *)&image, &ip_data, + 12, false, gs_currentcolorspace(igs))) < 0 || +diff --git a/psi/ztrans.c b/psi/ztrans.c +index 64defda..0550a10 100644 +--- a/psi/ztrans.c ++++ b/psi/ztrans.c +@@ -417,6 +417,7 @@ zimage3x(i_ctx_t *i_ctx_p) + gs_image3x_t_init(&image, NULL); + if (dict_find_string(op, "DataDict", &pDataDict) <= 0) + return_error(gs_error_rangecheck); ++ check_type(*pDataDict, t_dictionary); + if ((code = pixel_image_params(i_ctx_p, pDataDict, + (gs_pixel_image_t *)&image, &ip_data, + 16, false, gs_currentcolorspace(igs))) < 0 || +@@ -453,6 +454,9 @@ image_params *pip_data, const char *dict_name, + + if (dict_find_string(op, dict_name, &pMaskDict) <= 0) + return 1; ++ if (!r_has_type(pMaskDict, t_dictionary)) ++ return gs_note_error(gs_error_typecheck); ++ + if ((mcode = code = data_image_params(mem, pMaskDict, &pixm->MaskDict, + &ip_mask, false, 1, 16, false, false)) < 0 || + (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0 || +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2018-19477.patch b/SOURCES/ghostscript-cve-2018-19477.patch new file mode 100644 index 0000000..a4dfb31 --- /dev/null +++ b/SOURCES/ghostscript-cve-2018-19477.patch @@ -0,0 +1,32 @@ +From 606a22e77e7f081781e99e44644cd0119f559e03 Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Wed, 14 Nov 2018 09:27:00 +0000 +Subject: [PATCH] Bug #700168 - add a type check + +Bug #700168 "Type confusion in JBIG2Decode" + +The code was assuming that .jbig2globalctx was a structure allocated +by the graphics library, without checking. + +Add a check to see that it is a structure and that its the correct +type of structure. +--- + psi/zfjbig2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/psi/zfjbig2.c b/psi/zfjbig2.c +index a3d13a2..07b470f 100644 +--- a/psi/zfjbig2.c ++++ b/psi/zfjbig2.c +@@ -72,6 +72,8 @@ z_jbig2decode(i_ctx_t * i_ctx_p) + if (r_has_type(op, t_dictionary)) { + check_dict_read(*op); + if ( dict_find_string(op, ".jbig2globalctx", &sop) > 0) { ++ if (!r_is_struct(sop) || !r_has_stype(sop, imemory, st_jbig2_global_data_t)) ++ return_error(gs_error_typecheck); + gref = r_ptr(sop, s_jbig2_global_data_t); + s_jbig2decode_set_global_data((stream_state*)&state, gref); + } +-- +2.17.2 + diff --git a/SOURCES/ghostscript-cve-2019-3835.patch b/SOURCES/ghostscript-cve-2019-3835.patch new file mode 100644 index 0000000..640bb43 --- /dev/null +++ b/SOURCES/ghostscript-cve-2019-3835.patch @@ -0,0 +1,615 @@ +From 779664d79f0dca77dbdd66b753679bfd12dcbbad Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Mon, 26 Nov 2018 18:01:25 +0000 +Subject: [PATCH 1/4] Have gs_cet.ps run from gs_init.ps + +Previously gs_cet.ps was run on the command line, to set up the interpreter +state so our output more closely matches the example output for the QL CET +tests. + +Allow a -dCETMODE command line switch, which will cause gs_init.ps to run the +file directly. + +This works better for gpdl as it means the changes are made in the intial +interpreter state, rather than after initialisation is complete. + +This also means adding a definition of the default procedure for black +generation and under color removal (rather it being defined in-line in +.setdefaultbgucr + +Also, add a check so gs_cet.ps only runs once - if we try to run it a second +time, we'll just skip over the file, flushing through to the end. +--- + Resource/Init/gs_cet.ps | 11 ++++++++++- + Resource/Init/gs_init.ps | 13 ++++++++++++- + 2 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/Resource/Init/gs_cet.ps b/Resource/Init/gs_cet.ps +index d3e1686..75534bb 100644 +--- a/Resource/Init/gs_cet.ps ++++ b/Resource/Init/gs_cet.ps +@@ -1,6 +1,11 @@ + %!PS + % Set defaults for Ghostscript to match Adobe CPSI behaviour for CET + ++systemdict /product get (PhotoPRINT SE 5.0v2) readonly eq ++{ ++ (%END GS_CET) .skipeof ++} if ++ + % do this in the server level so it is persistent across jobs + //true 0 startjob not { + (*** Warning: CET startup is not in server default) = flush +@@ -25,7 +30,9 @@ currentglobal //true setglobal + + /UNROLLFORMS true def + +-{ } bind dup ++(%.defaultbgrucrproc) cvn { } bind def ++ ++(%.defaultbgrucrproc) cvn load dup + setblackgeneration + setundercolorremoval + 0 array cvx readonly dup dup dup setcolortransfer +@@ -109,3 +116,5 @@ userdict /.smoothness currentsmoothness put + % end of slightly nasty hack to give consistent cluster results + + //false 0 startjob pop % re-enter encapsulated mode ++ ++%END GS_CET +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index a2503f1..9a1f2b2 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -1534,10 +1534,18 @@ setpacking + % any-part-of-pixel rule. + 0.5 .setfilladjust + } bind def ++ + % Set the default screen and BG/UCR. ++% We define the proc here, rather than inline in .setdefaultbgucr ++% for the benefit of gs_cet.ps so jobs that do anything that causes ++% .setdefaultbgucr to be called will still get the redefined proc ++% in gs_cet.ps ++(%.defaultbgrucrproc) cvn { pop 0 } def ++ + /.setdefaultbgucr { + systemdict /setblackgeneration known { +- { pop 0 } dup setblackgeneration setundercolorremoval ++ (%.defaultbgrucrproc) cvn load dup ++ setblackgeneration setundercolorremoval + } if + } bind def + /.useloresscreen { % - .useloresscreen +@@ -2506,4 +2514,7 @@ WRITESYSTEMDICT { + % be 'true' in some cases. + userdict /AGM_preserve_spots //false put + ++systemdict /CETMODE .knownget ++{ { (gs_cet.ps) runlibfile } if } if ++ + % The interpreter will run the initial procedure (start). +-- +2.20.1 + + +From e8acf6d1aa1fc92f453175509bfdad6f2b12dc73 Mon Sep 17 00:00:00 2001 +From: Nancy Durgin +Date: Thu, 14 Feb 2019 10:09:00 -0800 +Subject: [PATCH 2/4] Undef /odef in gs_init.ps + +Made a new temporary utility function in gs_cet.ps (.odef) to use instead +of /odef. This makes it fine to undef odef with all the other operators in +gs_init.ps + +This punts the bigger question of what to do with .makeoperator, but it +doesn't make the situation any worse than it already was. +--- + Resource/Init/gs_cet.ps | 10 ++++++++-- + Resource/Init/gs_init.ps | 1 + + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/Resource/Init/gs_cet.ps b/Resource/Init/gs_cet.ps +index 75534bb..dbc5c4e 100644 +--- a/Resource/Init/gs_cet.ps ++++ b/Resource/Init/gs_cet.ps +@@ -1,6 +1,10 @@ + %!PS + % Set defaults for Ghostscript to match Adobe CPSI behaviour for CET + ++/.odef { % odef - ++ 1 index exch .makeoperator def ++} bind def ++ + systemdict /product get (PhotoPRINT SE 5.0v2) readonly eq + { + (%END GS_CET) .skipeof +@@ -93,8 +97,8 @@ userdict /.smoothness currentsmoothness put + } { + /setsmoothness .systemvar /typecheck signalerror + } ifelse +-} bind odef +-/currentsmoothness { userdict /.smoothness get } bind odef % for 09-55.PS, 09-57.PS . ++} bind //.odef exec ++/currentsmoothness { userdict /.smoothness get } bind //.odef exec % for 09-55.PS, 09-57.PS . + + % slightly nasty hack to give consistent cluster results + /ofnfa systemdict /filenameforall get def +@@ -113,6 +117,8 @@ userdict /.smoothness currentsmoothness put + } ifelse + ofnfa + } bind def ++ ++currentdict /.odef undef + % end of slightly nasty hack to give consistent cluster results + + //false 0 startjob pop % re-enter encapsulated mode +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 9a1f2b2..e5678b9 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2253,6 +2253,7 @@ SAFER { .setsafeglobal } if + /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice + /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack /.applypolicies ++ /odef + + % Used by a free user in the Library of Congress. Apparently this is used to + % draw a partial page, which is then filled in by the results of a barcode +-- +2.20.1 + + +From 205591753126802da850ada6511a0ff8411aa287 Mon Sep 17 00:00:00 2001 +From: Ray Johnston +Date: Thu, 14 Feb 2019 10:20:03 -0800 +Subject: [PATCH 3/4] Fix bug 700585: Restrict superexec and remove it from + internals and gs_cet.ps + +Also while changing things, restructure the CETMODE so that it will +work with -dSAFER. The gs_cet.ps is now run when we are still at save +level 0 with systemdict writeable. Allows us to undefine .makeoperator +and .setCPSImode internal operators after CETMODE is handled. + +Change previous uses of superexec to using .forceput (with the usual +.bind executeonly to hide it). +--- + Resource/Init/gs_cet.ps | 39 ++++++++++++++------------------------- + Resource/Init/gs_dps1.ps | 2 +- + Resource/Init/gs_fonts.ps | 8 ++++---- + Resource/Init/gs_init.ps | 38 +++++++++++++++++++++++++++----------- + Resource/Init/gs_ttf.ps | 6 +++--- + Resource/Init/gs_type1.ps | 6 +++--- + 6 files changed, 52 insertions(+), 47 deletions(-) + +diff --git a/Resource/Init/gs_cet.ps b/Resource/Init/gs_cet.ps +index dbc5c4e..58da404 100644 +--- a/Resource/Init/gs_cet.ps ++++ b/Resource/Init/gs_cet.ps +@@ -1,37 +1,28 @@ +-%!PS + % Set defaults for Ghostscript to match Adobe CPSI behaviour for CET + +-/.odef { % odef - +- 1 index exch .makeoperator def +-} bind def +- ++% skip if we've already run this -- based on fake "product" + systemdict /product get (PhotoPRINT SE 5.0v2) readonly eq + { + (%END GS_CET) .skipeof + } if + +-% do this in the server level so it is persistent across jobs +-//true 0 startjob not { +- (*** Warning: CET startup is not in server default) = flush +-} if ++% Note: this must be run at save level 0 and when systemdict is writeable ++currentglobal //true setglobal ++systemdict dup dup dup ++/version (3017.102) readonly .forceput % match CPSI 3017.102 ++/product (PhotoPRINT SE 5.0v2) readonly .forceput % match CPSI 3017.102 ++/revision 0 put % match CPSI 3017.103 Tek shows revision 5 ++/serialnumber dup {233640} readonly .makeoperator .forceput % match CPSI 3017.102 Tek shows serialnumber 1401788461 ++ ++systemdict /.odef { % odef - ++ 1 index exch //.makeoperator def ++} .bind .forceput % this will be undefined at the end + + 300 .sethiresscreen % needed for language switch build since it + % processes gs_init.ps BEFORE setting the resolution + + 0 array 0 setdash % CET 09-08 wants local setdash + +-currentglobal //true setglobal +- +-{ +- systemdict dup dup dup +- /version (3017.102) readonly put % match CPSI 3017.102 +- /product (PhotoPRINT SE 5.0v2) readonly put % match CPSI 3017.102 +- /revision 0 put % match CPSI 3017.103 Tek shows revision 5 +- /serialnumber dup {233640} readonly .makeoperator put % match CPSI 3017.102 Tek shows serialnumber 1401788461 +- systemdict /deviceinfo undef % for CET 20-23-1 +-% /UNROLLFORMS true put % CET files do unreasonable things inside forms +-} 1183615869 internaldict /superexec get exec +- + /UNROLLFORMS true def + + (%.defaultbgrucrproc) cvn { } bind def +@@ -118,9 +109,7 @@ userdict /.smoothness currentsmoothness put + ofnfa + } bind def + +-currentdict /.odef undef +-% end of slightly nasty hack to give consistent cluster results +- +-//false 0 startjob pop % re-enter encapsulated mode ++systemdict /.odef .undef + ++% end of slightly nasty hack to give consistent cluster results + %END GS_CET +diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps +index b75ea14..01475ac 100644 +--- a/Resource/Init/gs_dps1.ps ++++ b/Resource/Init/gs_dps1.ps +@@ -85,7 +85,7 @@ level2dict begin + % definition, copy it into the local directory. + //systemdict /SharedFontDirectory .knownget + { 1 index .knownget +- { //.FontDirectory 2 index 3 -1 roll { put } systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse } % readonly ++ { //.FontDirectory 2 index 3 -1 roll .forceput } % readonly + if + } + if +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 01eca35..ab062e1 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -512,11 +512,11 @@ buildfontdict 3 /.buildfont3 cvx put + % the font in LocalFontDirectory. + .currentglobal + { //systemdict /LocalFontDirectory .knownget +- { 2 index 2 index { .growput } systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse } % readonly ++ { 2 index 2 index .forceput } % readonly + if + } + if +- dup //.FontDirectory 4 -2 roll { .growput } systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse % readonly ++ dup //.FontDirectory 4 -2 roll .forceput % readonly + % If the font originated as a resource, register it. + currentfile .currentresourcefile eq { dup .registerfont } if + readonly +@@ -1178,13 +1178,13 @@ currentdict /.putgstringcopy .forceundef + //.FontDirectory 1 index known not { + 2 dict dup /FontName 3 index put + dup /FontType 1 put +- //.FontDirectory 3 1 roll { put } systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse % readonly ++ //.FontDirectory 3 1 roll //.forceput exec % readonly + } { + pop + } ifelse + } forall + } forall +- } ++ } executeonly % hide .forceput + FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined + + % Install initial fonts from Fontmap. +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index e5678b9..a054222 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2184,9 +2184,6 @@ SAFER { .setsafeglobal } if + /.endtransparencygroup % transparency-example.ps + /.setdotlength % Bug687720.ps + /.sort /.setdebug /.mementolistnewblocks /getenv +- +- /.makeoperator /.setCPSImode % gs_cet.ps, this won't work on cluster with -dSAFER +- + /unread + ] + {systemdict exch .forceundef} forall +@@ -2266,7 +2263,6 @@ SAFER { .setsafeglobal } if + + % Used by our own test suite files + %/.fileposition %image-qa.ps +- %/.makeoperator /.setCPSImode % gs_cet.ps + + % Either our code uses these in ways which mean they can't be undefined, or they are used directly by + % test files/utilities, or engineers expressed a desire to keep them visible. +@@ -2471,6 +2467,16 @@ end + /vmreclaim where + { pop NOGC not { 2 .vmreclaim 0 vmreclaim } if + } if ++ ++% Do this before systemdict is locked (see below for additional CETMODE setup using gs_cet.ps) ++systemdict /CETMODE .knownget { ++ { ++ (gs_cet.ps) runlibfile ++ } if ++} if ++systemdict /.makeoperator .undef % must be after gs_cet.ps ++systemdict /.setCPSImode .undef % must be after gs_cet.ps ++ + DELAYBIND not { + systemdict /.bindnow .undef % We only need this for DELAYBIND + systemdict /.forcecopynew .undef % remove temptation +@@ -2479,16 +2485,29 @@ DELAYBIND not { + systemdict /.forceundef .undef % ditto + } if + +-% Move superexec to internaldict if superexec is defined. +-systemdict /superexec .knownget { +- 1183615869 internaldict /superexec 3 -1 roll put +- systemdict /superexec .undef ++% Move superexec to internaldict if superexec is defined. (Level 2 or later) ++systemdict /superexec known { ++ % restrict superexec to single known use by PScript5.dll ++ % We could do this only for SAFER mode, but internaldict and superexec are ++ % not very well documented, and we don't want them to be used. ++ 1183615869 internaldict /superexec { ++ 2 index /Private eq % first check for typical use in PScript5.dll ++ 1 index length 1 eq and % expected usage is: dict /Private {put} superexec ++ 1 index 0 get systemdict /put get eq and ++ { ++ //superexec exec % the only usage we allow ++ } { ++ /superexec load /invalidaccess signalerror ++ } ifelse ++ } bind cvx executeonly put ++ systemdict /superexec .undef % get rid of the dangerous (unrestricted) operator + } if + + %% Can't remove this one until the last minute :-) + DELAYBIND not { + systemdict /.undef .undef + } if ++ + WRITESYSTEMDICT { + SAFER { + (\n *** WARNING - you have selected SAFER, indicating you want Ghostscript\n) print +@@ -2515,7 +2534,4 @@ WRITESYSTEMDICT { + % be 'true' in some cases. + userdict /AGM_preserve_spots //false put + +-systemdict /CETMODE .knownget +-{ { (gs_cet.ps) runlibfile } if } if +- + % The interpreter will run the initial procedure (start). +diff --git a/Resource/Init/gs_ttf.ps b/Resource/Init/gs_ttf.ps +index 05943c5..996d1e2 100644 +--- a/Resource/Init/gs_ttf.ps ++++ b/Resource/Init/gs_ttf.ps +@@ -1421,7 +1421,7 @@ mark + TTFDEBUG { (\n1 setting alias: ) print dup ==only + ( to be the same as ) print 2 index //== exec } if + +- 7 index 2 index 3 -1 roll exch //.growput systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse ++ 7 index 2 index 3 -1 roll exch .forceput + } forall + pop pop pop + } +@@ -1439,7 +1439,7 @@ mark + exch pop + TTFDEBUG { (\n2 setting alias: ) print 1 index ==only + ( to use glyph index: ) print dup //== exec } if +- 5 index 3 1 roll //.growput systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse ++ 5 index 3 1 roll .forceput + //false + } + { +@@ -1456,7 +1456,7 @@ mark + { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer) + TTFDEBUG { (\3 nsetting alias: ) print 1 index ==only + ( to be index: ) print dup //== exec } if +- exch pop 5 index 3 1 roll //.growput systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse ++ exch pop 5 index 3 1 roll .forceput + } + { + pop pop +@@ -1486,7 +1486,7 @@ mark + } ifelse + ] + TTFDEBUG { (Encoding: ) print dup === flush } if +-} bind def ++} .bind executeonly odef % hides .forceput + + % to be removed 9.09...... + currentdict /postalias undef +diff --git a/Resource/Init/gs_type1.ps b/Resource/Init/gs_type1.ps +index 2935d9c..1f38dd7 100644 +--- a/Resource/Init/gs_type1.ps ++++ b/Resource/Init/gs_type1.ps +@@ -116,7 +116,7 @@ + { % scratch(string) RAGL(dict) AGL(dict) CharStrings(dict) cstring gname aglname + CFFDEBUG { (\nsetting alias: ) print dup ==only + ( to be the same as glyph: ) print 1 index //== exec } if +- 3 index exch 3 index //.growput systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse ++ 3 index exch 3 index .forceput + % scratch(string) RAGL(dict) AGL(dict) CharStrings(dict) cstring gname + } + {pop} ifelse +@@ -135,7 +135,7 @@ + 3 1 roll pop pop + } if + pop +- dup /.AGLprocessed~GS //true //.growput systemdict /superexec known {//superexec}{1183615869 internaldict /superexec get exec} ifelse ++ dup /.AGLprocessed~GS //true .forceput + } if + + %% We need to excute the C .buildfont1 in a stopped context so that, if there +@@ -148,7 +148,7 @@ + {//.buildfont1} stopped + 4 3 roll .setglobal + {//.buildfont1 $error /errorname get signalerror} if +- } bind def ++ } .bind executeonly def % hide .forceput + + % If the diskfont feature isn't included, define a dummy .loadfontdict. + /.loadfontdict where +-- +2.20.1 + + +From d683d1e6450d74619e6277efeebfc222d9a5cb91 Mon Sep 17 00:00:00 2001 +From: Ray Johnston +Date: Sun, 24 Feb 2019 22:01:04 -0800 +Subject: [PATCH 4/4] Bug 700585: Obliterate "superexec". We don't need it, nor + do any known apps. + +We were under the impression that the Windows driver 'PScript5.dll' used +superexec, but after testing with our extensive suite of PostScript file, +and analysis of the PScript5 "Adobe CoolType ProcSet, it does not appear +that this operator is needed anymore. Get rid of superexec and all of the +references to it, since it is a potential security hole. +--- + Resource/Init/gs_init.ps | 18 ------------------ + psi/icontext.c | 1 - + psi/icstate.h | 1 - + psi/zcontrol.c | 30 ------------------------------ + psi/zdict.c | 6 ++---- + psi/zgeneric.c | 3 +-- + 6 files changed, 3 insertions(+), 56 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index a054222..ca20f12 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2485,24 +2485,6 @@ DELAYBIND not { + systemdict /.forceundef .undef % ditto + } if + +-% Move superexec to internaldict if superexec is defined. (Level 2 or later) +-systemdict /superexec known { +- % restrict superexec to single known use by PScript5.dll +- % We could do this only for SAFER mode, but internaldict and superexec are +- % not very well documented, and we don't want them to be used. +- 1183615869 internaldict /superexec { +- 2 index /Private eq % first check for typical use in PScript5.dll +- 1 index length 1 eq and % expected usage is: dict /Private {put} superexec +- 1 index 0 get systemdict /put get eq and +- { +- //superexec exec % the only usage we allow +- } { +- /superexec load /invalidaccess signalerror +- } ifelse +- } bind cvx executeonly put +- systemdict /superexec .undef % get rid of the dangerous (unrestricted) operator +-} if +- + %% Can't remove this one until the last minute :-) + DELAYBIND not { + systemdict /.undef .undef +diff --git a/psi/icontext.c b/psi/icontext.c +index 1fbe486..7462ea3 100644 +--- a/psi/icontext.c ++++ b/psi/icontext.c +@@ -151,7 +151,6 @@ context_state_alloc(gs_context_state_t ** ppcst, + pcst->rand_state = rand_state_initial; + pcst->usertime_total = 0; + pcst->keep_usertime = false; +- pcst->in_superexec = 0; + pcst->plugin_list = 0; + make_t(&pcst->error_object, t__invalid); + { /* +diff --git a/psi/icstate.h b/psi/icstate.h +index 4c6a14d..1009d85 100644 +--- a/psi/icstate.h ++++ b/psi/icstate.h +@@ -54,7 +54,6 @@ struct gs_context_state_s { + long usertime_total; /* total accumulated usertime, */ + /* not counting current time if running */ + bool keep_usertime; /* true if context ever executed usertime */ +- int in_superexec; /* # of levels of superexec */ + /* View clipping is handled in the graphics state. */ + ref error_object; /* t__invalid or error object from operator */ + ref userparams; /* t_dictionary */ +diff --git a/psi/zcontrol.c b/psi/zcontrol.c +index 0362cf4..dc813e8 100644 +--- a/psi/zcontrol.c ++++ b/psi/zcontrol.c +@@ -158,34 +158,6 @@ zexecn(i_ctx_t *i_ctx_p) + return o_push_estack; + } + +-/* superexec - */ +-static int end_superexec(i_ctx_t *); +-static int +-zsuperexec(i_ctx_t *i_ctx_p) +-{ +- os_ptr op = osp; +- es_ptr ep; +- +- check_op(1); +- if (!r_has_attr(op, a_executable)) +- return 0; /* literal object just gets pushed back */ +- check_estack(2); +- ep = esp += 3; +- make_mark_estack(ep - 2, es_other, end_superexec); /* error case */ +- make_op_estack(ep - 1, end_superexec); /* normal case */ +- ref_assign(ep, op); +- esfile_check_cache(); +- pop(1); +- i_ctx_p->in_superexec++; +- return o_push_estack; +-} +-static int +-end_superexec(i_ctx_t *i_ctx_p) +-{ +- i_ctx_p->in_superexec--; +- return 0; +-} +- + /* .runandhide */ + /* before executing , is been removed from */ + /* the operand stack and placed on the execstack with attributes */ +@@ -971,8 +943,6 @@ const op_def zcontrol3_op_defs[] = { + {"0%loop_continue", loop_continue}, + {"0%repeat_continue", repeat_continue}, + {"0%stopped_push", stopped_push}, +- {"1superexec", zsuperexec}, +- {"0%end_superexec", end_superexec}, + {"2.runandhide", zrunandhide}, + {"0%end_runandhide", end_runandhide}, + op_def_end(0) +diff --git a/psi/zdict.c b/psi/zdict.c +index b0deaaa..e2e525d 100644 +--- a/psi/zdict.c ++++ b/psi/zdict.c +@@ -212,8 +212,7 @@ zundef(i_ctx_t *i_ctx_p) + int code; + + check_type(*op1, t_dictionary); +- if (i_ctx_p->in_superexec == 0) +- check_dict_write(*op1); ++ check_dict_write(*op1); + code = idict_undef(op1, op); + if (code < 0 && code != gs_error_undefined) /* ignore undefined error */ + return code; +@@ -504,8 +503,7 @@ zsetmaxlength(i_ctx_t *i_ctx_p) + int code; + + check_type(*op1, t_dictionary); +- if (i_ctx_p->in_superexec == 0) +- check_dict_write(*op1); ++ check_dict_write(*op1); + check_type(*op, t_integer); + if (op->value.intval < 0) + return_error(gs_error_rangecheck); +diff --git a/psi/zgeneric.c b/psi/zgeneric.c +index 8048e28..d4edddb 100644 +--- a/psi/zgeneric.c ++++ b/psi/zgeneric.c +@@ -204,8 +204,7 @@ zput(i_ctx_t *i_ctx_p) + + switch (r_type(op2)) { + case t_dictionary: +- if (i_ctx_p->in_superexec == 0) +- check_dict_write(*op2); ++ check_dict_write(*op2); + { + int code = idict_put(op2, op1, op); + +-- +2.20.1 + diff --git a/SOURCES/ghostscript-cve-2019-3838.patch b/SOURCES/ghostscript-cve-2019-3838.patch new file mode 100644 index 0000000..0ba1e87 --- /dev/null +++ b/SOURCES/ghostscript-cve-2019-3838.patch @@ -0,0 +1,56 @@ +From ed9fcd95bb01f0768bf273b2526732e381202319 Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Wed, 20 Feb 2019 09:54:28 +0000 +Subject: [PATCH 1/2] Bug 700576: Make a transient proc executeonly (in + DefineResource). + +This prevents access to .forceput + +Solution originally suggested by cbuissar@redhat.com. +--- + Resource/Init/gs_res.ps | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps +index d9b3459..b646329 100644 +--- a/Resource/Init/gs_res.ps ++++ b/Resource/Init/gs_res.ps +@@ -425,7 +425,7 @@ status { + % so we have to use .forcedef here. + /.Instances 1 index .forcedef % Category dict is read-only + } executeonly if +- } ++ } executeonly + { .LocalInstances dup //.emptydict eq + { pop 3 dict localinstancedict Category 2 index put + } +-- +2.20.1 + + +From a82601e8f95a2f2147f3b3b9e44ec2b8f3a6be8b Mon Sep 17 00:00:00 2001 +From: Chris Liddell +Date: Fri, 22 Feb 2019 12:28:23 +0000 +Subject: [PATCH 2/2] Bug 700576(redux): an extra transient proc needs + executeonly'ed. + +--- + Resource/Init/gs_res.ps | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps +index b646329..8c1f29f 100644 +--- a/Resource/Init/gs_res.ps ++++ b/Resource/Init/gs_res.ps +@@ -437,7 +437,7 @@ status { + % Now make the resource value read-only. + 0 2 copy get { readonly } .internalstopped pop + dup 4 1 roll put exch pop exch pop +- } ++ } executeonly + { /defineresource cvx /typecheck signaloperror + } + ifelse +-- +2.20.1 + diff --git a/SOURCES/ghostscript-cve-2019-3839.patch b/SOURCES/ghostscript-cve-2019-3839.patch new file mode 100644 index 0000000..3c02934 --- /dev/null +++ b/SOURCES/ghostscript-cve-2019-3839.patch @@ -0,0 +1,866 @@ +From 95aa78beae9489d5c9f898fe2032aa23f860867d Mon Sep 17 00:00:00 2001 +From: Ray Johnston +Date: Fri, 21 Sep 2018 11:16:18 -0700 +Subject: [PATCH 1/6] Catch errors in setpagesize, .setpagesize and + setpagedevice and cleanup + +Bug 699794 showed that attempt to change page size in SAFER mode when the +nulldevice was the currentdevice would leave 'false' on the stack. Run +.setdevice in stopped and clean up, and also clean up .setpagesize +--- + Resource/Init/gs_lev2.ps | 9 ++++++++- + Resource/Init/gs_setpd.ps | 9 +++++++-- + Resource/Init/gs_statd.ps | 22 ++++++++++++++++++---- + 3 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index b69303d..ab0c32e 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -616,7 +616,14 @@ currentuserparams /WaitTimeout known + .dicttomark setpagedevice + /WaitTimeout exch mark /JobTimeout 5 2 roll .dicttomark setsystemparams + } bind def +-/.setpagesize { 2 array astore /PageSize .dict1 setpagedevice } bind def ++/.setpagesize ++ { 2 copy 2 array astore /PageSize .dict1 { setpagedevice } stopped { ++ pop % the setpagedevice dict ++ /setpagesize $error /errorname get signalerror ++ } { ++ pop pop % success -- pop the arguments ++ } ifelse ++ } bind def + /setduplexmode { /Duplex .dict1 setpagedevice } bind def + /setmargins + { exch 2 array astore /Margins .dict1 setpagedevice +diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps +index 46e5810..7875d1f 100644 +--- a/Resource/Init/gs_setpd.ps ++++ b/Resource/Init/gs_setpd.ps +@@ -932,10 +932,15 @@ SETPDDEBUG { (Recovering.) = pstack flush } if + % Stack: mark ... + SETPDDEBUG { (Installing.) = pstack flush } if + +- pop ++ pop + % .setdevice clears the current page device! + .currentpagedevice pop exch +- .setdevice pop ++ { .setdevice } stopped { ++ cleartomark exch pop ++ /setpagedevice $error /errorname get ++ signalerror ++ } if ++ pop + .setpagedevice + + % Implement UseCIEColor directly if this is a LL3 system. +diff --git a/Resource/Init/gs_statd.ps b/Resource/Init/gs_statd.ps +index 64c6463..34b759c 100644 +--- a/Resource/Init/gs_statd.ps ++++ b/Resource/Init/gs_statd.ps +@@ -39,7 +39,13 @@ statusdict begin + % These procedures are also accessed as data structures during initialization, + % so the page dimensions must be the first two elements of the procedure. + +-/.setpagesize { /statusdict .systemvar begin .setpagesize end } bind def ++/.setpagesize { ++ /statusdict .systemvar begin ++ { .setpagesize } stopped { ++ /setpagesize $error /errorname get signalerror ++ } if ++ end ++} bind def + + % Page sizes defined by Adobe documentation + % Note: these executable arrays should all begin with two +@@ -261,9 +267,17 @@ readonly def + % The Adobe documentation only defines setpagetype + % (a Level 1 operator) as accepting the values 0 and 1, + % so we do too. +- {/letter /note} 1 index get +- //systemdict /userdict get exch get cvx exec +- /pagetype exch def ++ dup type /integertype ne { ++ /setpage /typecheck signalerror ++ } { ++ dup 0 ne 1 index 1 ne or { ++ /setpage /rangecheck signalerror ++ } { ++ {/letter /note} 1 index get ++ //systemdict /userdict get exch get cvx exec ++ } ifelse ++ /pagetype exch def ++ } ifelse + end + } bind def + +-- +2.20.1 + + +From c29ec2fff76e45bbf9cd767ff541556c5d064be4 Mon Sep 17 00:00:00 2001 +From: Ray Johnston +Date: Fri, 21 Sep 2018 12:00:50 -0700 +Subject: [PATCH 2/6] Add parameter checking in setresolution + +Found in sequence for bug 699794 +--- + Resource/Init/gs_lev2.ps | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index ab0c32e..0f0d573 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -637,7 +637,14 @@ currentuserparams /WaitTimeout known + .dicttomark setpagedevice + } bind def + /setresolution +- { dup 2 array astore /HWResolution .dict1 setpagedevice ++ { count 1 lt { /setresolution /stackunderflow signalerror } if ++ dup type dup /integertype eq exch /realtype eq or not ++ { ++ /setresolution /typecheck signalerror ++ } if ++ dup 2 array astore /HWResolution .dict1 { setpagedevice } stopped { ++ pop /setresolution $error /errorname get signalerror ++ } if + } bind def + %END PAGEDEVICE + +-- +2.20.1 + + +From fe4c47d8e25d6366ecbb5ff487348148b908a89e Mon Sep 17 00:00:00 2001 +From: Nancy Durgin +Date: Tue, 13 Nov 2018 14:23:41 -0800 +Subject: [PATCH 3/6] Undefine some level2-related operators + +These are only a partial set. Undefine them in both the level2dict and +systemdict. They are undef'd in gs_init.ps because they are used outside +the scope of just gs_lev2.ps + + /.execform1 + /.getdevparams + /.setuserparams2 + /.startjob + /.checkFilePermitparams + /.checksetparams + /.copyparam + /.setpagesize + +Rename .dict1 to .pair2dict and use immediate reference. + +Undef these at end of gs_lev2.ps (should never make it into systemdict): + /.pair2dict + /.checkprocesscomment +--- + Resource/Init/gs_init.ps | 18 ++++++++++++++++++ + Resource/Init/gs_lev2.ps | 34 +++++++++++++++++++++------------- + 2 files changed, 39 insertions(+), 13 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 48bb96d..e915f11 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2271,6 +2271,24 @@ SAFER { .setsafeglobal } if + ] + {systemdict exch .forceundef} forall + ++ % level 2 operators, undefine from both systemdict and level2dict ++ [ ++ /.execform1 ++ /.getdevparams ++ /.setuserparams2 ++ /.startjob ++ /.checkFilePermitparams ++ /.checksetparams ++ /.copyparam ++ /.setpagesize ++ ++% Couldn't figure out how to do these yet ++% /.checkparamtype ++% /.startnewjob ++ ] ++ dup {level2dict exch .forceundef} forall ++ {systemdict exch .forceundef} forall ++ + //systemdict /UndefinePostScriptOperators .forceundef + } .bind executeonly def % must be bound and hidden for .forceundef + +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index 0f0d573..e6f0645 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -64,7 +64,7 @@ level2dict begin + pop + } ifelse pop pop + } forall pop pop +-} .bind def % not odef, shouldn't reset stacks ++} .bind odef + + % currentuser/systemparams creates and returns a dictionary in the + % current VM. The easiest way to make this work is to copy any composite +@@ -101,7 +101,7 @@ level2dict begin + 1 index length string exch .setglobal + copy exch not { readonly } if + } if +-} .bind def ++} .bind odef + + % Some user parameters are managed entirely at the PostScript level. + % We take care of that here. +@@ -345,13 +345,13 @@ end + } ifelse + } .bind def + /ProcessComment //null .definepsuserparam +-psuserparams /ProcessComment {.checkprocesscomment} put ++psuserparams /ProcessComment {//.checkprocesscomment exec} put + (%ProcessComment) cvn { + /ProcessComment getuserparam + dup //null eq { pop pop pop } { exec } ifelse + } bind def + /ProcessDSCComment //null .definepsuserparam +-psuserparams /ProcessDSCComment {.checkprocesscomment} put ++psuserparams /ProcessDSCComment {//.checkprocesscomment exec} put + /.loadingfont //false def + (%ProcessDSCComment) cvn { + /ProcessDSCComment getuserparam +@@ -556,7 +556,8 @@ end % serverdict + % Note that statusdict must be allocated in local VM. + % We don't bother with many of these yet. + +-/.dict1 { exch mark 3 1 roll .dicttomark } bind def ++% convenience function to make a dictionary from an object and a key ++/.pair2dict { exch mark 3 1 roll .dicttomark } bind def + + currentglobal //false setglobal 25 dict exch setglobal begin + currentsystemparams +@@ -569,11 +570,11 @@ systemdict /buildtime dup load put + /checkpassword { .checkpassword 0 gt } bind def + dup /DoStartPage known + { /dostartpage { /DoStartPage getsystemparam } bind def +- /setdostartpage { /DoStartPage .dict1 setsystemparams } bind def ++ /setdostartpage { /DoStartPage //.pair2dict exec setsystemparams } bind def + } if + dup /StartupMode known + { /dosysstart { /StartupMode getsystemparam 0 ne } bind def +- /setdosysstart { { 1 } { 0 } ifelse /StartupMode .dict1 setsystemparams } bind def ++ /setdosysstart { { 1 } { 0 } ifelse /StartupMode //.pair2dict exec setsystemparams } bind def + } if + %****** Setting jobname is supposed to set userparams.JobName, too. + /jobname { /JobName getuserparam } bind def +@@ -581,7 +582,7 @@ dup /StartupMode known + /ramsize { /RamSize getsystemparam } bind def + /realformat 1 index /RealFormat get def + dup /PrinterName known +- { /setprintername { /PrinterName .dict1 setsystemparams } bind def ++ { /setprintername { /PrinterName //.pair2dict exec setsystemparams } bind def + } if + /printername + { currentsystemparams /PrinterName .knownget not { () } if exch copy +@@ -617,18 +618,18 @@ currentuserparams /WaitTimeout known + /WaitTimeout exch mark /JobTimeout 5 2 roll .dicttomark setsystemparams + } bind def + /.setpagesize +- { 2 copy 2 array astore /PageSize .dict1 { setpagedevice } stopped { ++ { 2 copy 2 array astore /PageSize //.pair2dict exec { setpagedevice } stopped { + pop % the setpagedevice dict + /setpagesize $error /errorname get signalerror + } { + pop pop % success -- pop the arguments + } ifelse + } bind def +-/setduplexmode { /Duplex .dict1 setpagedevice } bind def ++/setduplexmode { /Duplex //.pair2dict exec setpagedevice } bind def + /setmargins +- { exch 2 array astore /Margins .dict1 setpagedevice ++ { exch 2 array astore /Margins //.pair2dict exec setpagedevice + } bind def +-/setpagemargin { 0 2 array astore /PageOffset .dict1 setpagedevice } bind def ++/setpagemargin { 0 2 array astore /PageOffset //.pair2dict exec setpagedevice } bind def + /setpageparams + { mark /PageSize 6 -2 roll + 4 index 1 and ORIENT1 { 1 } { 0 } ifelse ne { exch } if 2 array astore +@@ -642,7 +643,7 @@ currentuserparams /WaitTimeout known + { + /setresolution /typecheck signalerror + } if +- dup 2 array astore /HWResolution .dict1 { setpagedevice } stopped { ++ dup 2 array astore /HWResolution //.pair2dict exec { setpagedevice } stopped { + pop /setresolution $error /errorname get signalerror + } if + } bind def +@@ -1254,3 +1255,10 @@ def + %END TN 5044 psuedo-ops + + end % level2dict ++ ++% undefine things defined in this file and not referenced elsewhere ++[ ++ /.checkprocesscomment ++ /.pair2dict ++] ++{level2dict exch .forceundef} forall +-- +2.20.1 + + +From 932f4106a00e99e4ee32dcc02e57d3636f383ea1 Mon Sep 17 00:00:00 2001 +From: Nancy Durgin +Date: Wed, 28 Nov 2018 10:09:01 -0800 +Subject: [PATCH 4/6] Undef internal functions from level2dict + +--- + Resource/Init/gs_lev2.ps | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index e6f0645..7638f2a 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -117,7 +117,7 @@ counttomark 2 idiv { + } repeat pop + /.definepsuserparam { % .definepsuserparam - + psuserparams 3 copy pop +- type cvlit /.checkparamtype cvx 2 packedarray cvx put ++ type cvlit //.checkparamtype /exec load 3 packedarray cvx put + userparams 3 1 roll put + } .bind def + end +@@ -211,7 +211,7 @@ end + } forall + } if + /setsystemparams //pssystemparams mark exch { +- type cvlit /.checkparamtype cvx 2 packedarray cvx ++ type cvlit //.checkparamtype /exec load 3 packedarray cvx + } forall .dicttomark .checksetparams + % Set the C-level system params. If this succeeds, we know that + % the password check succeeded. +@@ -1260,5 +1260,7 @@ end % level2dict + [ + /.checkprocesscomment + /.pair2dict ++ /.setcolorrendering1 ++ /.checkparamtype + ] + {level2dict exch .forceundef} forall +-- +2.20.1 + + +From e7ff64cf9b756278f19c87d295ee0fd95c955c05 Mon Sep 17 00:00:00 2001 +From: Nancy Durgin +Date: Wed, 23 Jan 2019 12:00:30 -0800 +Subject: [PATCH 5/6] Fixed bug caused by the way .checksetparams was undef'd + +Previously, had undef'd it by making it an operator. +Now just use an immediate reference and undef it in the gs_lev2.ps file. + +This fixes bug introduced in commit fe4c47d8e25d6366ecbb5ff487348148b908a89e. + +Undef'ing .checksetparams by making it an operator doesn't work right because +errors report .checksetparams as the offending function instead of +the operator that uses it (setsystemparams in this case). + +This caused an error in file /tests_private/ps/ps3cet/27-09.PS on page 3, +where it reports the offending function of some error-handling tests. +Reporting function should be 'setsystemparams', not '.checksetparams' on +this page. +--- + Resource/Init/gs_init.ps | 1 - + Resource/Init/gs_lev2.ps | 7 ++++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index e915f11..a2503f1 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2278,7 +2278,6 @@ SAFER { .setsafeglobal } if + /.setuserparams2 + /.startjob + /.checkFilePermitparams +- /.checksetparams + /.copyparam + /.setpagesize + +diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps +index 7638f2a..de1cc94 100644 +--- a/Resource/Init/gs_lev2.ps ++++ b/Resource/Init/gs_lev2.ps +@@ -64,7 +64,7 @@ level2dict begin + pop + } ifelse pop pop + } forall pop pop +-} .bind odef ++} .bind def + + % currentuser/systemparams creates and returns a dictionary in the + % current VM. The easiest way to make this work is to copy any composite +@@ -129,7 +129,7 @@ end + /.setuserparams2 { + % Check that we will be able to set the PostScript-level + % user parameters. +- /setuserparams /psuserparams .systemvar .checksetparams ++ /setuserparams /psuserparams .systemvar //.checksetparams exec + % Set the C-level user params. If this succeeds, we know that + % the password check succeeded. + dup .setuserparams +@@ -212,7 +212,7 @@ end + } if + /setsystemparams //pssystemparams mark exch { + type cvlit //.checkparamtype /exec load 3 packedarray cvx +- } forall .dicttomark .checksetparams ++ } forall .dicttomark //.checksetparams exec + % Set the C-level system params. If this succeeds, we know that + % the password check succeeded. + dup .setsystemparams +@@ -1262,5 +1262,6 @@ end % level2dict + /.pair2dict + /.setcolorrendering1 + /.checkparamtype ++ /.checksetparams + ] + {level2dict exch .forceundef} forall +-- +2.20.1 + + +From 4ec9ca74bed49f2a82acb4bf430eae0d8b3b75c9 Mon Sep 17 00:00:00 2001 +From: Ray Johnston +Date: Thu, 31 Jan 2019 11:31:30 -0800 +Subject: [PATCH 6/6] Hide pdfdict and GS_PDF_ProcSet (internal stuff for the + PDF interp). + +We now keep GS_PDF_ProcSet in pdfdict, and immediately bind pdfdict +where needed so we can undef it after the last PDF interp file has +run (pdf_sec.ps). +--- + Resource/Init/pdf_base.ps | 11 ++++---- + Resource/Init/pdf_draw.ps | 59 +++++++++++++++++++-------------------- + Resource/Init/pdf_font.ps | 9 +++--- + Resource/Init/pdf_main.ps | 25 +++++++++-------- + Resource/Init/pdf_ops.ps | 11 ++++---- + Resource/Init/pdf_sec.ps | 4 ++- + 6 files changed, 60 insertions(+), 59 deletions(-) + +diff --git a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps +index c62ac0e..d3c3a5f 100644 +--- a/Resource/Init/pdf_base.ps ++++ b/Resource/Init/pdf_base.ps +@@ -23,7 +23,6 @@ + + /.setlanguagelevel where { pop 2 .setlanguagelevel } if + .currentglobal //true .setglobal +-/pdfdict where { pop } { /pdfdict 100 dict def } ifelse + pdfdict begin + + % Define the name interpretation dictionary for reading values. +@@ -130,11 +129,11 @@ currentdict /num-chars-dict .undef + + /.pdfexectoken { % .pdfexectoken ? + PDFDEBUG { +- pdfdict /PDFSTEPcount known not { pdfdict /PDFSTEPcount 1 .forceput } executeonly if ++ //pdfdict /PDFSTEPcount known not { //pdfdict /PDFSTEPcount 1 .forceput } executeonly if + PDFSTEP { +- pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput ++ //pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput + PDFSTEPcount 1 gt { +- pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput ++ //pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput + } executeonly + { + dup ==only +@@ -142,10 +141,10 @@ currentdict /num-chars-dict .undef + ( ? ) print flush 1 //false .outputpage + (%stdin) (r) file 255 string readline { + token { +- exch pop pdfdict /PDFSTEPcount 3 -1 roll .forceput ++ exch pop //pdfdict /PDFSTEPcount 3 -1 roll .forceput + } executeonly + { +- pdfdict /PDFSTEPcount 1 .forceput ++ //pdfdict /PDFSTEPcount 1 .forceput + } executeonly ifelse % token + } { + pop /PDFSTEP //false def % EOF on stdin +diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps +index d743ae1..1add3f7 100644 +--- a/Resource/Init/pdf_draw.ps ++++ b/Resource/Init/pdf_draw.ps +@@ -18,8 +18,7 @@ + + /.setlanguagelevel where { pop 2 .setlanguagelevel } if + .currentglobal //true .setglobal +-/pdfdict where { pop } { /pdfdict 100 dict def } ifelse +-GS_PDF_ProcSet begin ++/GS_PDF_ProcSet load begin + pdfdict begin + + % For simplicity, we use a single interpretation dictionary for all +@@ -113,7 +112,7 @@ pdfdict begin + + /resolvefunction { % resolvefunction + .resolvefn +- PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Function: ) print dup === flush } if } if ++ PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Function: ) print dup === flush } if } if + } bind executeonly def + + /resolvefnproc { % resolvefnproc +@@ -1073,7 +1072,7 @@ currentdict end readonly def + %% finished running the PaintProc. + + /.actual_pdfpaintproc { % .pdfpaintproc - +- PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Begin PaintProc) print dup === flush } if } if ++ PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Begin PaintProc) print dup === flush } if } if + PDFfile fileposition 3 1 roll + q + 1 index /PaintType oget 1 eq { +@@ -1108,21 +1107,21 @@ currentdict end readonly def + Q + }{ + (\n **** Error: File has unbalanced q/Q operators \(too many Q's\)\n Output may be incorrect.\n) +- pdfdict /.Qqwarning_issued .knownget ++ //pdfdict /.Qqwarning_issued .knownget + { + { + pop + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse +@@ -1131,21 +1130,21 @@ currentdict end readonly def + } loop + { + (\n **** Error: File has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n) +- pdfdict /.Qqwarning_issued .knownget ++ //pdfdict /.Qqwarning_issued .knownget + { + { + pop + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse +@@ -1156,7 +1155,7 @@ currentdict end readonly def + /pdfemptycount exch def + + Q +- PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if ++ PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if + PDFfile exch setfileposition + } bind executeonly odef + +@@ -1227,7 +1226,7 @@ currentdict end readonly def + ] cvx put + dup /BBox 2 copy knownoget { normrect FixPatternBBox put } { pop pop } ifelse + dup /.pattern_uses_transparency 1 index patternusestransparency put +- PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Pattern: ) print dup === flush } if } if ++ PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Pattern: ) print dup === flush } if } if + } bind executeonly def + + /ignore_color_op ( **** Error: Ignoring a color operation in a cached context.\n Output may be incorrect.\n) readonly def +@@ -2348,16 +2347,16 @@ currentdict /last-ditch-bpc-csp undef + } bind executeonly def + + /IncrementAppearanceNumber { +- pdfdict /AppearanceNumber .knownget { +- 1 add pdfdict /AppearanceNumber 3 -1 roll .forceput ++ //pdfdict /AppearanceNumber .knownget { ++ 1 add //pdfdict /AppearanceNumber 3 -1 roll .forceput + } executeonly + { +- pdfdict /AppearanceNumber 0 .forceput ++ //pdfdict /AppearanceNumber 0 .forceput + } executeonly ifelse + }bind executeonly odef + + /MakeAppearanceName { +- pdfdict /AppearanceNumber get ++ //pdfdict /AppearanceNumber get + 10 string cvs + dup length 10 add string dup 0 (\{FormName) putinterval + dup 3 -1 roll +@@ -2378,17 +2377,17 @@ currentdict /last-ditch-bpc-csp undef + gsave initclip + MakeNewAppearanceName + .pdfFormName +- pdfdict /.PreservePDFForm known {pdfdict /.PreservePDFForm get} {//false}ifelse exch +- pdfdict /.PreservePDFForm true .forceput ++ //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get} {//false}ifelse exch ++ //pdfdict /.PreservePDFForm true .forceput + DoForm +- pdfdict /.PreservePDFForm 3 -1 roll .forceput ++ //pdfdict /.PreservePDFForm 3 -1 roll .forceput + grestore + } bind executeonly odef + + /DoForm { + %% save the current value, if its true we will set it to false later, in order + %% to prevent us preserving Forms which are used *from* an annotation /Appearance. +- pdfdict /.PreservePDFForm known {pdfdict /.PreservePDFForm get} {//false}ifelse exch ++ //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get} {//false}ifelse exch + + %% We may alter the Default* colour spaces, if the Resources + %% ColorSpace entry contains one of them. But we don't want that +@@ -2503,13 +2502,13 @@ currentdict /last-ditch-bpc-csp undef + pdfemptycount countdictstack 3 -1 roll + /pdfemptycount count 4 sub store + +- pdfdict /.PreservePDFForm known {pdfdict /.PreservePDFForm get}{//false} ifelse ++ //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get}{//false} ifelse + { + %% We must *not* preserve any subsidiary forms (curently at least) as PDF + %% form preservation doesn't really work. This is used just for Annotation + %% Appearances currently, and if they should happen to use a form, we do not + %% want to preserve it. +- pdfdict /.PreservePDFForm false .forceput ++ //pdfdict /.PreservePDFForm false .forceput + /q cvx /execform cvx 5 -2 roll + } executeonly + { +@@ -2542,7 +2541,7 @@ currentdict /last-ditch-bpc-csp undef + saved_DCMYK /DefaultCMYK exch /ColorSpace defineresource pop + end + } if +- pdfdict /.PreservePDFForm 3 -1 roll .forceput ++ //pdfdict /.PreservePDFForm 3 -1 roll .forceput + } bind executeonly odef + + /_dops_save 1 array def +@@ -2701,13 +2700,13 @@ drawopdict begin + % Start by getting the object number for a Form XObject + dup Page /XObject obj_get dup 0 eq not { + % Now get the recording dictionary and see if that object number has been seen +- pdfdict /Recursive_XObject_D get 1 index known { ++ //pdfdict /Recursive_XObject_D get 1 index known { + ( **** Error: Recursive XObject detected, ignoring ") print 1 index 256 string cvs print (", object number ) print 256 string cvs print (\n) print + ( Output may be incorrect.\n) pdfformaterror + //false + }{ + % We haven't seen it yet, so record it. +- pdfdict /Recursive_XObject_D get 1 index null put ++ //pdfdict /Recursive_XObject_D get 1 index null put + 3 1 roll + //true + }ifelse +@@ -2745,7 +2744,7 @@ drawopdict begin + ( Output may be incorrect.\n) pdfformaterror + } ifelse + PDFfile exch setfileposition +- pdfdict /Recursive_XObject_D get exch undef ++ //pdfdict /Recursive_XObject_D get exch undef + }{ + % Otherwise ignore it and tidy up the stacks + pop pop +diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps +index 46408f9..275b659 100644 +--- a/Resource/Init/pdf_font.ps ++++ b/Resource/Init/pdf_font.ps +@@ -37,8 +37,7 @@ + + /.setlanguagelevel where { pop 2 .setlanguagelevel } if + .currentglobal //true .setglobal +-/pdfdict where { pop } { /pdfdict 100 dict def } ifelse +-GS_PDF_ProcSet begin ++/GS_PDF_ProcSet load begin % from userdict at this point + pdfdict begin + + % We cache the PostScript font in an additional element of the +@@ -1219,11 +1218,11 @@ currentdict /eexec_pdf_param_dict .undef + .pdfruncontext + countdictstack BuildCharDictDepth sub + { +- pdfdict /.Qqwarning_issued .knownget {not}{//true} ifelse ++ //pdfdict /.Qqwarning_issued .knownget {not}{//true} ifelse + { + (\n **** Warning: Type 3 glyph has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n) + pdfformatwarning +- pdfdict /.Qqwarning_issued //true .forceput ++ //pdfdict /.Qqwarning_issued //true .forceput + } executeonly if + Q + } repeat +@@ -2334,7 +2333,7 @@ currentdict /bndef undef + dup //null eq + {pop} + { +- pdfdict /InputPDFFileName .knownget {.CRCHashFilenameAndObject} if ++ //pdfdict /InputPDFFileName .knownget {.CRCHashFilenameAndObject} if + exch dup /.OrigUniqueIDXUID .knownget not + { + dup /XUID .knownget not +diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps +index dd1480b..e44288e 100644 +--- a/Resource/Init/pdf_main.ps ++++ b/Resource/Init/pdf_main.ps +@@ -18,8 +18,9 @@ + + /.setlanguagelevel where { pop 2 .setlanguagelevel } if + .currentglobal //true .setglobal +-/pdfdict where { pop } { /pdfdict 100 dict def } ifelse + pdfdict begin ++/GS_PDF_ProcSet dup load def % keep in pdfdict to hide it ++userdict /GS_PDF_ProcSet undef + + % Patch in an obsolete variable used by some third-party software. + /#? //false def +@@ -304,8 +305,8 @@ currentdict /runpdfstring .undef + /Page //null def + /DSCPageCount 0 def + /PDFSave //null def +- GS_PDF_ProcSet begin +- pdfdict begin ++ //pdfdict /GS_PDF_ProcSet get begin ++ //pdfdict begin + pdfopen begin + /CumulativePageCount currentpagedevice /PageCount get def + } bind executeonly def +@@ -624,7 +625,7 @@ currentdict /runpdfstring .undef + %% copied to a temporary file) and store it in pdfdict. We will use this for + %% hashing fonts to detect if fonts with the same name are from different files. + %% +- dup currentglobal exch true setglobal .getfilename exch setglobal /InputPDFFileName exch pdfdict 3 1 roll .forceput ++ dup currentglobal exch true setglobal .getfilename exch setglobal /InputPDFFileName exch //pdfdict 3 1 roll .forceput + + //runpdfbegin exec + //pdf_collection_files exec +@@ -1390,7 +1391,7 @@ currentdict /xref-char-dict undef + } bind executeonly def + + /pdfopenfile { % pdfopenfile +- pdfdict readonly pop % can't do it any earlier than this ++ //pdfdict readonly pop % can't do it any earlier than this + 32 dict begin + /LocalResources 0 dict def + /DefaultQstate //null def % establish binding +@@ -2684,21 +2685,21 @@ currentdict /PDF2PS_matrix_key undef + StreamRunAborted not { + (\n **** Error: File has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n) + +- pdfdict /.Qqwarning_issued .knownget ++ //pdfdict /.Qqwarning_issued .knownget + { + { + pop + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse +@@ -2710,8 +2711,8 @@ currentdict /PDF2PS_matrix_key undef + Repaired % pass Repaired state around the restore + RepairedAnError + PDFSave restore +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //false .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //false .forceput + .setglobal + /RepairedAnError exch def + /Repaired exch def +diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps +index aa09641..c2e7461 100644 +--- a/Resource/Init/pdf_ops.ps ++++ b/Resource/Init/pdf_ops.ps +@@ -24,6 +24,7 @@ + systemdict /pdfmark known not + { userdict /pdfmark { cleartomark } bind executeonly put } if + ++systemdict /pdfdict where { pop } { /pdfdict 100 dict put } ifelse + userdict /GS_PDF_ProcSet 256 dict dup begin + + % ---------------- Abbreviations ---------------- % +@@ -174,21 +175,21 @@ currentdict /gput_always_allow .undef + { + (\n **** Error: File has unbalanced q/Q operators \(too many Q's\)\n Output may be incorrect.\n) + +- pdfdict /.Qqwarning_issued .knownget ++ //pdfdict /.Qqwarning_issued .knownget + { + { + pop + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse + } + { +- currentglobal pdfdict gcheck .setglobal +- pdfdict /.Qqwarning_issued //true .forceput ++ currentglobal //pdfdict gcheck .setglobal ++ //pdfdict /.Qqwarning_issued //true .forceput + .setglobal + pdfformaterror + } executeonly ifelse +diff --git a/Resource/Init/pdf_sec.ps b/Resource/Init/pdf_sec.ps +index 143efb7..a8e3d2e 100644 +--- a/Resource/Init/pdf_sec.ps ++++ b/Resource/Init/pdf_sec.ps +@@ -39,7 +39,6 @@ + + /.setlanguagelevel where { pop 2 .setlanguagelevel } if + .currentglobal //true .setglobal +-/pdfdict where { pop } { /pdfdict 100 dict def } ifelse + pdfdict begin + + % Older ghostscript versions do not have .pdftoken, so we use 'token' instead. +@@ -748,4 +747,7 @@ currentdict /PDFScanRules_null undef + } bind executeonly def + + end % pdfdict ++ ++systemdict /pdfdict .forceundef % hide pdfdict ++ + .setglobal +-- +2.20.1 + diff --git a/SOURCES/ghostscript-cve-2019-6116-downstream.patch b/SOURCES/ghostscript-cve-2019-6116-downstream.patch new file mode 100644 index 0000000..0b5f15f --- /dev/null +++ b/SOURCES/ghostscript-cve-2019-6116-downstream.patch @@ -0,0 +1,48 @@ +diff --git a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps +index 00c14d5..2a6f4f3 100644 +--- a/Resource/Init/gs_dps.ps ++++ b/Resource/Init/gs_dps.ps +@@ -117,7 +117,7 @@ + .dicttomark readonly /localdicts exch put + % localdicts is now defined in userdict. + % Copy the definitions into systemdict. +- localdicts { .forcedef } forall ++ localdicts { .forcedef } executeonly forall + % Set the user parameters. + userparams readonly .setuserparams + % Establish the initial gstate(s). +diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps +index 4807f81..01eca35 100644 +--- a/Resource/Init/gs_fonts.ps ++++ b/Resource/Init/gs_fonts.ps +@@ -1136,7 +1136,7 @@ $error /SubstituteFont { } put + % Stack: fontdict + } executeonly + if pop % Stack: origfontname fontdirectory path +- } ++ } executeonly + if pop pop % Stack: origfontname + + % The font definitely did not load correctly. +diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps +index f1d1728..46408f9 100644 +--- a/Resource/Init/pdf_font.ps ++++ b/Resource/Init/pdf_font.ps +@@ -678,7 +678,7 @@ currentdict end readonly def + currentglobal 2 index dup gcheck setglobal + /FontInfo 5 dict dup 5 1 roll .forceput + setglobal +- } if ++ } executeonly if + dup /GlyphNames2Unicode .knownget not { + //true % No existing G2U, make one + } { +@@ -692,7 +692,7 @@ currentdict end readonly def + currentglobal exch dup gcheck setglobal + dup /GlyphNames2Unicode 100 dict dup 4 1 roll .forceput + 3 2 roll setglobal +- } if % font-res font-dict encoding|null font-info g2u ++ } executeonly if % font-res font-dict encoding|null font-info g2u + exch pop exch % font-res font-dict g2u encoding|null + userdict /.lastToUnicode get % font-res font-dict g2u Encoding|null CMap + .convert_ToUnicode-into-g2u % font-res font-dict diff --git a/SOURCES/ghostscript-cve-2019-6116.patch b/SOURCES/ghostscript-cve-2019-6116.patch new file mode 100644 index 0000000..9535366 --- /dev/null +++ b/SOURCES/ghostscript-cve-2019-6116.patch @@ -0,0 +1,1178 @@ +From 30cd347f37bfb293ffdc407397d1023628400b81 Mon Sep 17 00:00:00 2001 +From: Ken Sharp +Date: Mon, 15 Oct 2018 13:35:15 +0100 +Subject: [PATCH 1/6] font parsing - prevent SEGV in .cffparse + +Bug #699961 "currentcolortransfer procs crash .parsecff" + +zparsecff checked the operand for being an array (and not a packed +array) but the returned procedures from the default currentcolortransfer +are arrays, not packed arrays. This led to the code trying to +dereference a NULL pointer. + +Add a specific check for the 'refs' pointer being NULL before we try +to use it. + +Additionally, make the StartData procedure in the CFF Font Resource +executeonly to prevent pulling the hidden .parsecff operator out and +using it. Finally, extend this to other resource types. +--- + Resource/Init/gs_cff.ps | 4 +-- + Resource/Init/gs_cidcm.ps | 6 ++-- + Resource/Init/gs_ciddc.ps | 4 +-- + Resource/Init/gs_cmap.ps | 2 +- + Resource/Init/gs_res.ps | 60 +++++++++++++++++++-------------------- + psi/zfont2.c | 4 +++ + 6 files changed, 42 insertions(+), 38 deletions(-) + +diff --git a/Resource/Init/gs_cff.ps b/Resource/Init/gs_cff.ps +index 20c35a5..b60e374 100644 +--- a/Resource/Init/gs_cff.ps ++++ b/Resource/Init/gs_cff.ps +@@ -199,7 +199,7 @@ def + % ordinary CFF font. + /StartData { % StartData - + currentfile exch subfilefilter //false //false ReadData pop +-} bind def ++} bind executeonly def + /ReadData { % ReadData + % Initialize. + +@@ -234,7 +234,7 @@ def + end % FontSetInit ProcSet + /FontSet defineresource + +-} bind def ++} bind executeonly def + + % ---------------- Resource category definition ---------------- % + +diff --git a/Resource/Init/gs_cidcm.ps b/Resource/Init/gs_cidcm.ps +index 0201ea8..60b0fdb 100644 +--- a/Resource/Init/gs_cidcm.ps ++++ b/Resource/Init/gs_cidcm.ps +@@ -327,7 +327,7 @@ currentdict end def + //FindResource exec + } ifelse + } ifelse +-} bind def ++} bind executeonly def + + /ResourceStatus { % ResourceStatus true + % ResourceStatus false +@@ -359,7 +359,7 @@ currentdict end def + //false + } ifelse + } ifelse +-} bind def ++} bind executeonly def + + /ResourceForAll { %