From 97f9052ce49e6844b06a49ff9e4b8fc1eaf6bd10 Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Wed, 9 Jan 2019 14:24:07 +0000 Subject: [PATCH 6/7] Undefine a bunch of gs_fonts.ps specific procs Also reorder and add some immediate evaluation, so it still works with the undefining. CVE: CVE-2019-6116 Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git] Signed-off-by: Ovidiu Panait --- Resource/Init/gs_dps1.ps | 3 +- Resource/Init/gs_fonts.ps | 275 +++++++++++++++++++++----------------- Resource/Init/gs_res.ps | 7 +- 3 files changed, 157 insertions(+), 128 deletions(-) diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps index b75ea14..8700c8c 100644 --- a/Resource/Init/gs_dps1.ps +++ b/Resource/Init/gs_dps1.ps @@ -67,7 +67,8 @@ level2dict begin /selectfont % selectfont - { - { 1 .argindex findfont + { + 1 .argindex findfont 1 index dup type /arraytype eq { makefont } { scalefont } ifelse setfont pop pop } stopped { /selectfont .systemvar $error /errorname get signalerror } if diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps index c13a2fc..0562235 100644 --- a/Resource/Init/gs_fonts.ps +++ b/Resource/Init/gs_fonts.ps @@ -100,7 +100,7 @@ userdict /.nativeFontmap .FontDirectory maxlength dict put { 2 index token not { (Fontmap entry for ) print 1 index =only ( ends prematurely! Giving up.) = flush - {.loadFontmap} 0 get 1 .quit + {//.loadFontmap exec} 0 get 1 .quit } if dup /; eq { pop 3 index 3 1 roll .growput exit } if pop @@ -202,6 +202,14 @@ NOFONTPATH { /FONTPATH () def } if { pop } { /FONTPATH (GS_FONTPATH) getenv not { () } if def } ifelse + +% The following are dummy definitions that, if we have a FONTPATH, will +% be replaced in the following section. +% They are here so immediately evaulation will work, and allow them to +% undefined at the bottom of the file. +/.scanfontbegin{} bind def +/.scanfontdir {} bind def + FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if /FONTPATH [ FONTPATH .pathlist ] def @@ -242,12 +250,12 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if /.scanfontbegin { % Construct the table of all file names already in Fontmap. currentglobal //true setglobal - .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength + //.scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength Fontmap { exch pop { dup type /stringtype eq - { .splitfilename pop .fonttempstring copy .lowerstring cvn - .scanfontdict exch //true put + { //.splitfilename exec pop //.fonttempstring copy //.lowerstring exec cvn + //.scanfontdict exch //true put } { pop } @@ -280,9 +288,9 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if /txt //true .dicttomark def /.scan1fontstring 8192 string def -% %%BeginFont: is not per Adobe documentation, but a few fonts have it. +% BeginFont: is not per Adobe documentation, but a few fonts have it. /.scanfontheaders [(%!PS-Adobe*) (%!FontType*) (%%BeginFont:*)] def -0 .scanfontheaders { length .max } forall 6 add % extra for PFB header +0 //.scanfontheaders { length .max } forall 6 add % extra for PFB header /.scan1fontfirst exch string def /.scanfontdir % .scanfontdir - { currentglobal exch //true setglobal @@ -291,10 +299,10 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if 0 0 0 4 -1 roll % found scanned files { % stack: exch 1 add exch % increment filecount - dup .splitfilename .fonttempstring copy .lowerstring + dup //.splitfilename exec //.fonttempstring copy //.lowerstring exec % stack: % - .scanfontskip exch known exch .scanfontdict exch known or + //.scanfontskip exch known exch //.scanfontdict exch known or { pop % stack: } @@ -309,7 +317,7 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if % On some platforms, the file operator will open directories, % but an error will occur if we try to read from one. % Handle this possibility here. - dup .scan1fontfirst { readstring } .internalstopped + dup //.scan1fontfirst { readstring } .internalstopped { pop pop () } { pop } ifelse @@ -322,7 +330,7 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if { dup length 6 sub 6 exch getinterval } if % Check for font file headers. - //false .scanfontheaders + //false //.scanfontheaders { 2 index exch .stringmatch or } forall exch pop @@ -335,7 +343,7 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if { exch copystring exch DEBUG { ( ) print dup =only flush } if 1 index .definenativefontmap - .splitfilename pop //true .scanfontdict 3 1 roll .growput + //.splitfilename exec pop //true //.scanfontdict 3 1 roll .growput % Increment fontcount. 3 -1 roll 1 add 3 1 roll } @@ -352,7 +360,7 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if } ifelse } - .scan1fontstring filenameforall + //.scan1fontstring filenameforall QUIET { pop pop pop } { ( ) print =only ( files, ) print =only ( scanned, ) print @@ -422,7 +430,6 @@ systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt //true .setnativefontmapbuilt } ifelse } bind def -currentdict /.setnativefontmapbuilt .forceundef % Create the dictionary that registers the .buildfont procedure % (called by definefont) for each FontType. @@ -526,7 +533,8 @@ buildfontdict 3 /.buildfont3 cvx put % We use this only for explicitly aliased fonts, not substituted fonts: % we think this matches the observed behavior of Adobe interpreters. /.aliasfont % .aliasfont - { .currentglobal 3 1 roll dup .gcheck .setglobal + { + currentglobal 3 1 roll dup gcheck setglobal % dup length 2 add dict % dup 3 -1 roll % @@ -541,7 +549,7 @@ buildfontdict 3 /.buildfont3 cvx put % whose FontName is a local non-string, if someone passed a % garbage value to findfont. In this case, just don't % call definefont at all. - 2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or + 2 index dup type /stringtype eq exch gcheck or 1 index gcheck not or { pop % 1 index dup type /stringtype eq { cvn } if % @@ -566,10 +574,11 @@ buildfontdict 3 /.buildfont3 cvx put % Don't bind in definefont, since Level 2 redefines it. /definefont .systemvar exec } - { /findfont cvx {.completefont} .errorexec pop exch pop + { + /findfont cvx {.completefont} //.errorexec exec pop exch pop } ifelse - exch .setglobal + exch setglobal } odef % so findfont will bind it % Define .loadfontfile for loading a font. If we recognize Type 1 and/or @@ -669,10 +678,19 @@ buildfontdict 3 /.buildfont3 cvx put [(Cn) 4] [(Cond) 4] [(Narrow) 4] [(Pkg) 4] [(Compr) 4] [(Serif) 8] [(Sans) -8] ] readonly def + +/.fontnamestring { % .fontnamestring + dup type dup /nametype eq { + pop .namestring + } { + /stringtype ne { pop () } if + } ifelse +} bind def + /.fontnameproperties { % .fontnameproperties % - .fontnamestring - .substituteproperties { + //.fontnamestring exec + //.substituteproperties { 2 copy 0 get search { pop pop pop dup length 1 sub 1 exch getinterval 3 -1 roll exch { dup 0 ge { or } { neg not and } ifelse @@ -710,13 +728,7 @@ buildfontdict 3 /.buildfont3 cvx put % .nametostring dup type /nametype eq { .namestring } if } bind def -/.fontnamestring { % .fontnamestring - dup type dup /nametype eq { - pop .namestring - } { - /stringtype ne { pop () } if - } ifelse -} bind def + /.substitutefontname { % .substitutefontname % % Look for properties and/or a face name in the font name. @@ -724,7 +736,7 @@ buildfontdict 3 /.buildfont3 cvx put % base font; otherwise, use the default font. % Note that the "substituted" font name may be the same as % the requested one; the caller must check this. - exch .fontnamestring { + exch //.fontnamestring exec { defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique /Helvetica-Narrow /Helvetica-Narrow-Oblique /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique @@ -734,12 +746,12 @@ buildfontdict 3 /.buildfont3 cvx put } 3 1 roll % Stack: facelist properties fontname % Look for a face name. - .substitutefaces { + //.substitutefaces { 2 copy 0 get search { pop pop pop % Stack: facelist properties fontname [(pattern) family properties] dup 2 get 4 -1 roll or 3 1 roll - 1 get .substitutefamilies exch get + 1 get //.substitutefamilies exch get 4 -1 roll pop 3 1 roll } { pop pop @@ -748,7 +760,7 @@ buildfontdict 3 /.buildfont3 cvx put 1 index length mod get exec } bind def /.substitutefont { % .substitutefont - dup 0 exch .fontnameproperties .substitutefontname + dup 0 exch //.fontnameproperties exec .substitutefontname % Only accept fonts known in the Fontmap. Fontmap 1 index known not { @@ -814,7 +826,7 @@ FAKEFONTS not { (%END FAKEFONTS) .skipeof } if counttomark 1 sub { .aliasfont } repeat end % mark exch pop exch pop -} odef +} bind odef /findfont { .findfont } bind def @@ -860,7 +872,7 @@ FAKEFONTS not { (%END FAKEFONTS) .skipeof } if } { dup .substitutefont 2 copy eq { pop defaultfontname } if - .checkalias + //.checkalias exec QUIET not { SHORTERRORS { (%%[) print 1 index =only @@ -886,8 +898,8 @@ $error /SubstituteFont { } put //null 0 1 FONTPATH length 1 sub { FONTPATH 1 index get //null ne { exch pop exit } if pop } for dup //null ne { - dup 0 eq { .scanfontbegin } if - FONTPATH 1 index get .scanfontdir + dup 0 eq { //.scanfontbegin exec} if + FONTPATH 1 index get //.scanfontdir exec FONTPATH exch //null put //true } { pop //false @@ -897,11 +909,10 @@ $error /SubstituteFont { } put % scanning of FONTPATH. /.dofindfont { % mark .dofindfont % mark ... .tryfindfont not { - % We didn't find the font. If we haven't scanned % all the directories in FONTPATH, scan the next one % now and look for the font again. - .scannextfontdir { + //.scannextfontdir exec { % Start over with an empty alias list. counttomark 1 sub { pop } repeat % mark .dofindfont @@ -927,6 +938,7 @@ $error /SubstituteFont { } put } if % Substitute for the font. Don't alias. % Same stack as at the beginning of .dofindfont. + $error /SubstituteFont get exec % % igorm: I guess the surrounding code assumes that .stdsubstfont @@ -935,72 +947,11 @@ $error /SubstituteFont { } put % used in .dofindfont and through .stdsubstfont % just to represent a simple iteration, % which accumulates the aliases after the mark. - .stdsubstfont + //.stdsubstfont exec } ifelse } ifelse } if } bind def -% Try to find a font using only the present contents of Fontmap. -/.tryfindfont { % .tryfindfont true - % .tryfindfont false - //.FontDirectory 1 index .fontknownget - { % Already loaded - exch pop //true - } - { - dup Fontmap exch .knownget - { //true //true } - { % Unknown font name. Look for a file with the - % same name as the requested font. - dup .tryloadfont - { exch pop //true //false } - { - % if we can't load by name check the native font map - dup .nativeFontmap exch .knownget - { //true //true } - { //false //false } ifelse - } ifelse - } ifelse - - { % Try each element of the Fontmap in turn. - pop - //false exch % (in case we exhaust the list) - % Stack: fontname false fontmaplist - { exch pop - dup type /nametype eq - { % Font alias - .checkalias .tryfindfont exit - } - { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and - { % Font with a procedural definition - exec % The procedure will load the font. - % Check to make sure this really happened. - //.FontDirectory 1 index .knownget - { exch pop //true exit } - if - } - { % Font file name - //true .loadfontloop { //true exit } if - } - ifelse - } - ifelse //false - } - forall - % Stack: font true -or- fontname false - { //true - } - { % None of the Fontmap entries worked. - % Try loading a file with the same name - % as the requested font. - .tryloadfont - } - ifelse - } - if - } - ifelse - } bind def % any user of .putgstringcopy must use bind and executeonly /.putgstringcopy % .putgstringcopy - @@ -1014,25 +965,6 @@ $error /SubstituteFont { } put } executeonly ifelse } .bind executeonly odef % must be bound and hidden for .forceput -% Attempt to load a font from a file. -/.tryloadfont { % .tryloadfont true - % .tryloadfont false - dup .nametostring - % Hack: check for the presence of the resource machinery. - /.genericrfn where { - pop - pop dup .fonttempstring /FontResourceDir getsystemparam .genericrfn - {//false .loadfontloop} .internalstopped {//false} if { - //true - } { - dup .nametostring - {//true .loadfontloop} .internalstopped {//false} if - } ifelse - } { - {//true .loadfontloop} .internalstopped {//false} if - } ifelse -} bind def - /.loadfontloop { % .loadfontloop % true % -or- @@ -1102,7 +1034,7 @@ $error /SubstituteFont { } put } if % Check to make sure the font was actually loaded. - dup 3 index .fontknownget + dup 3 index //.fontknownget exec { dup /PathLoad 4 index .putgstringcopy 4 1 roll pop pop pop //true exit } executeonly if @@ -1113,7 +1045,7 @@ $error /SubstituteFont { } put exch dup % Stack: origfontname fontdirectory path path (r) file .findfontname { % Stack: origfontname fontdirectory path filefontname - 2 index 1 index .fontknownget + 2 index 1 index //.fontknownget exec { % Yes. Stack: origfontname fontdirectory path filefontname fontdict dup 4 -1 roll /PathLoad exch .putgstringcopy % Stack: origfontname fontdirectory filefontname fontdict @@ -1136,7 +1068,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. @@ -1150,7 +1082,87 @@ $error /SubstituteFont { } put } bind executeonly odef % must be bound and hidden for .putgstringcopy -currentdict /.putgstringcopy .undef +% Attempt to load a font from a file. +/.tryloadfont { % .tryloadfont true + % .tryloadfont false + dup //.nametostring exec + % Hack: check for the presence of the resource machinery. + /.genericrfn where { + pop + pop dup //.fonttempstring /FontResourceDir getsystemparam .genericrfn + {//false .loadfontloop} .internalstopped {//false} if { + //true + } { + dup //.nametostring exec + {//true .loadfontloop} .internalstopped {//false} if + } ifelse + } { + {//true .loadfontloop} .internalstopped {//false} if + } ifelse +} bind def + +% Try to find a font using only the present contents of Fontmap. +/.tryfindfont { % .tryfindfont true + % .tryfindfont false + //.FontDirectory 1 index //.fontknownget exec + { % Already loaded + exch pop //true + } + { + dup Fontmap exch .knownget + { //true //true } + { % Unknown font name. Look for a file with the + % same name as the requested font. + dup //.tryloadfont exec + { exch pop //true //false } + { + % if we can't load by name check the native font map + dup .nativeFontmap exch .knownget + { //true //true } + { //false //false } ifelse + } ifelse + } ifelse + + { % Try each element of the Fontmap in turn. + pop + //false exch % (in case we exhaust the list) + % Stack: fontname false fontmaplist + { exch pop + dup type /nametype eq + { % Font alias + //.checkalias exec + .tryfindfont exit + } + { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and + { % Font with a procedural definition + exec % The procedure will load the font. + % Check to make sure this really happened. + //.FontDirectory 1 index .knownget + { exch pop //true exit } + if + } + { % Font file name + //true .loadfontloop { //true exit } if + } + ifelse + } + ifelse //false + } + forall + % Stack: font true -or- fontname false + { //true + } + { % None of the Fontmap entries worked. + % Try loading a file with the same name + % as the requested font. + //.tryloadfont exec + } + ifelse + } + if + } + ifelse + } bind def % Define a procedure to load all known fonts. % This isn't likely to be very useful. @@ -1192,9 +1204,9 @@ FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined /.loadinitialfonts { NOFONTMAP not { /FONTMAP where - { pop [ FONTMAP .pathlist ] + { pop [ FONTMAP //.pathlist exec] { dup VMDEBUG findlibfile - { exch pop .loadFontmap } + { exch pop //.loadFontmap exec } { /undefinedfilename signalerror } ifelse } @@ -1208,7 +1220,7 @@ FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined pop pop defaultfontmap_content { .definefontmap } forall } { - .loadFontmap + //.loadFontmap exec } ifelse } { pop pop @@ -1272,3 +1284,18 @@ FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined { .makemodifiedfont dup /FontName get exch definefont pop } bind def + +% Undef these, not needed outside this file +[ + % /.fonttempstring /.scannextfontdir - are also used in gs_res.ps, so are undefined there + % /.fontnameproperties - is used in pdf_font.ps + % /.scanfontheaders - used in gs_cff.ps, gs_ttf.ps + /.loadfontloop /.tryloadfont /.findfont /.pathlist /.loadFontmap /.lowerstring + /.splitfilename /.scanfontdict /.scanfontbegin + /.scanfontskip /.scan1fontstring + /.scan1fontfirst /.scanfontdir + /.setnativefontmapbuilt /.aliasfont + /.setloadingfont /.substitutefaces /.substituteproperties /.substitutefamilies + /.nametostring /.fontnamestring /.checkalias /.fontknownget /.stdsubstfont + /.putgstringcopy +] {systemdict exch .forceundef} forall diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps index 18d5452..b016113 100644 --- a/Resource/Init/gs_res.ps +++ b/Resource/Init/gs_res.ps @@ -961,7 +961,7 @@ userdict /.localcsdefaults //false put dup type /nametype eq { .namestring } if dup type /stringtype ne { //false exit } if % Check the resource directory. - dup .fonttempstring /FontResourceDir getsystemparam .genericrfn + dup //.fonttempstring /FontResourceDir getsystemparam .genericrfn status { pop pop pop pop //true exit } if @@ -969,7 +969,7 @@ userdict /.localcsdefaults //false put % as the font. findlibfile { closefile //true exit } if % Scan a FONTPATH directory and try again. - .scannextfontdir not { //false exit } if + //.scannextfontdir exec not { //false exit } if } loop } bind def @@ -1008,7 +1008,7 @@ currentdict /.fontstatusaux .undef } ifelse } bind executeonly /ResourceForAll { - { .scannextfontdir not { exit } if } loop + { //.scannextfontdir exec not { exit } if } loop /Generic /Category findresource /ResourceForAll get exec } bind executeonly /.ResourceFileStatus { @@ -1163,6 +1163,7 @@ end % level2dict [ /.default_resource_dir /.resource_dir_name + /.fonttempstring /.scannextfontdir % from gs_fonts.ps ] {systemdict exch .forceundef} forall -- 2.18.1