Blame SOURCES/ghostscript-cve-2018-17961.patch

5e8686
From b0222e5e39712999f22084996a6b85a120b9389e Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Thu, 20 Sep 2018 16:35:28 +0100
5e8686
Subject: [PATCH 1/6] Bug 699795: add operand checking to
5e8686
 .setnativefontmapbuilt
5e8686
5e8686
.setnativefontmapbuilt .forceputs a value into systemdict - it is intended
5e8686
to be a boolean, but in this case was being called with a compound object
5e8686
(a dictionary). Such an object, in local VM, being forced into systemdict
5e8686
would then confuse the garbager, since it could be restored away with the
5e8686
reference remaining.
5e8686
5e8686
This adds operand checking, so .setnativefontmapbuilt will simply ignore
5e8686
anything other than a boolean value, and also removes the definition of
5e8686
.setnativefontmapbuilt after use, since it is only used in two, closely
5e8686
related places.
5e8686
---
5e8686
 Resource/Init/gs_fonts.ps | 11 ++++++++---
5e8686
 1 file changed, 8 insertions(+), 3 deletions(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
5e8686
index 38f0f6c..45b6613 100644
5e8686
--- a/Resource/Init/gs_fonts.ps
5e8686
+++ b/Resource/Init/gs_fonts.ps
5e8686
@@ -372,9 +372,13 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
5e8686
 % of strings: what the system thinks is the ps name,
5e8686
 % and the access path.
5e8686
 /.setnativefontmapbuilt { % set whether we've been run
5e8686
-  systemdict exch /.nativefontmapbuilt exch .forceput
5e8686
+  dup type /booleantype eq {
5e8686
+      systemdict exch /.nativefontmapbuilt exch .forceput
5e8686
+  }
5e8686
+  {pop}
5e8686
+  ifelse
5e8686
 } .bind executeonly def
5e8686
-systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt
5e8686
+systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec
5e8686
 /.buildnativefontmap {   % - .buildnativefontmap <bool>
5e8686
   systemdict /.nativefontmapbuilt .knownget not
5e8686
   { //false} if
5e8686
@@ -415,9 +419,10 @@ systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt
5e8686
       } forall
5e8686
     } if
5e8686
     % record that we've been run
5e8686
-    //true .setnativefontmapbuilt
5e8686
+    //true //.setnativefontmapbuilt exec
5e8686
   } ifelse
5e8686
 } bind def
5e8686
+currentdict /.setnativefontmapbuilt .forceundef
5e8686
 
5e8686
 % Create the dictionary that registers the .buildfont procedure
5e8686
 % (called by definefont) for each FontType.
5e8686
-- 
5e8686
2.17.2
5e8686
5e8686
5e8686
From a54c9e61e7d02bbc620bcba9b1c208462a876afb Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Sat, 29 Sep 2018 15:34:55 +0100
5e8686
Subject: [PATCH 2/6] Bug 699816: Improve hiding of security critical custom
5e8686
 operators
5e8686
5e8686
Make procedures that use .forceput/.forcedef/.forceundef into operators.
5e8686
5e8686
The result of this is that errors get reported against the "top" operator,
5e8686
rather than the "called" operator within the procedure.
5e8686
5e8686
For example:
5e8686
/myproc
5e8686
{
5e8686
  myop
5e8686
} bind def
5e8686
5e8686
If 'myop' throws an error, the error handler will be passed the 'myop'
5e8686
operator. Promoting 'myproc' to a operator means the error handler will be
5e8686
passed 'myproc'.
5e8686
---
5e8686
 Resource/Init/gs_diskn.ps |  2 +-
5e8686
 Resource/Init/gs_dps.ps   |  2 +-
5e8686
 Resource/Init/gs_fntem.ps |  2 +-
5e8686
 Resource/Init/gs_fonts.ps | 10 +++++-----
5e8686
 Resource/Init/gs_lev2.ps  | 13 +++++++++----
5e8686
 Resource/Init/gs_pdfwr.ps |  2 +-
5e8686
 Resource/Init/gs_setpd.ps | 25 +++++++++++++++++--------
5e8686
 Resource/Init/gs_typ32.ps | 14 +++++++++-----
5e8686
 Resource/Init/gs_type1.ps |  2 +-
5e8686
 Resource/Init/pdf_base.ps |  2 +-
5e8686
 Resource/Init/pdf_draw.ps | 10 +++++-----
5e8686
 Resource/Init/pdf_font.ps |  8 ++++----
5e8686
 Resource/Init/pdf_main.ps |  4 ++--
5e8686
 Resource/Init/pdf_ops.ps  |  8 ++++----
5e8686
 14 files changed, 61 insertions(+), 43 deletions(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_diskn.ps b/Resource/Init/gs_diskn.ps
5e8686
index 5540715..26ec0b5 100644
5e8686
--- a/Resource/Init/gs_diskn.ps
5e8686
+++ b/Resource/Init/gs_diskn.ps
5e8686
@@ -53,7 +53,7 @@ systemdict begin
5e8686
     exch .setglobal
5e8686
   }
5e8686
   if
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef % must be bound and hidden for .forceput
5e8686
 
5e8686
 % Modify .putdevparams to force regeneration of .searchabledevs list
5e8686
 /.putdevparams {
5e8686
diff --git a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps
5e8686
index cad7056..daf7b0f 100644
5e8686
--- a/Resource/Init/gs_dps.ps
5e8686
+++ b/Resource/Init/gs_dps.ps
5e8686
@@ -70,7 +70,7 @@
5e8686
                 % Save a copy of the initial gstate.
5e8686
   //systemdict /savedinitialgstate gstate readonly .forceput
5e8686
   .setglobal
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef % must be bound and hidden for .forceput
5e8686
 
5e8686
 % Initialize local dictionaries and gstate when creating a new context.
5e8686
 % Note that until this completes, we are in the anomalous situation of
5e8686
diff --git a/Resource/Init/gs_fntem.ps b/Resource/Init/gs_fntem.ps
5e8686
index 3ceee18..c1f7651 100644
5e8686
--- a/Resource/Init/gs_fntem.ps
5e8686
+++ b/Resource/Init/gs_fntem.ps
5e8686
@@ -408,7 +408,7 @@ currentdict end def
5e8686
     exit
5e8686
   } loop
5e8686
   exch setglobal
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef % must be bound and hidden for .forceput
5e8686
 
5e8686
 currentdict end /ProcSet defineresource pop
5e8686
 
5e8686
diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
5e8686
index 45b6613..89c3ab7 100644
5e8686
--- a/Resource/Init/gs_fonts.ps
5e8686
+++ b/Resource/Init/gs_fonts.ps
5e8686
@@ -377,8 +377,8 @@ FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
5e8686
   }
5e8686
   {pop}
5e8686
   ifelse
5e8686
-} .bind executeonly def
5e8686
-systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec
5e8686
+} .bind executeonly odef
5e8686
+systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt
5e8686
 /.buildnativefontmap {   % - .buildnativefontmap <bool>
5e8686
   systemdict /.nativefontmapbuilt .knownget not
5e8686
   { //false} if
5e8686
@@ -419,7 +419,7 @@ systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec
5e8686
       } forall
5e8686
     } if
5e8686
     % record that we've been run
5e8686
-    //true //.setnativefontmapbuilt exec
5e8686
+    //true .setnativefontmapbuilt
5e8686
   } ifelse
5e8686
 } bind def
5e8686
 currentdict /.setnativefontmapbuilt .forceundef
5e8686
@@ -1103,7 +1103,7 @@ $error /SubstituteFont { } put
5e8686
 
5e8686
                 % Check to make sure the font was actually loaded.
5e8686
         dup 3 index .fontknownget
5e8686
-         { dup /PathLoad 4 index //.putgstringcopy exec
5e8686
+         { dup /PathLoad 4 index .putgstringcopy
5e8686
            4 1 roll pop pop pop //true exit
5e8686
          } if
5e8686
 
5e8686
@@ -1115,7 +1115,7 @@ $error /SubstituteFont { } put
5e8686
          {            % Stack: origfontname fontdirectory path filefontname
5e8686
            2 index 1 index .fontknownget
5e8686
             {   % Yes.  Stack: origfontname fontdirectory path filefontname fontdict
5e8686
-              dup 4 -1 roll /PathLoad exch //.putgstringcopy exec
5e8686
+              dup 4 -1 roll /PathLoad exch .putgstringcopy
5e8686
                       % Stack: origfontname fontdirectory filefontname fontdict
5e8686
               3 -1 roll pop
5e8686
                       % Stack: origfontname filefontname fontdict
5e8686
diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps
5e8686
index eee0b9f..a8ed892 100644
5e8686
--- a/Resource/Init/gs_lev2.ps
5e8686
+++ b/Resource/Init/gs_lev2.ps
5e8686
@@ -163,10 +163,11 @@ end
5e8686
         % Set them again to the new values.  From here on, we are safe,
5e8686
         % since a context switch will consult userparams.
5e8686
   .setuserparams
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef % must be bound and hidden for .forceput
5e8686
 
5e8686
 /setuserparams {		% <dict> setuserparams -
5e8686
-    .setuserparams2
5e8686
+    {.setuserparams2} stopped
5e8686
+    {/setuserparams load $error /errorname get signalerror} if
5e8686
 } .bind odef
5e8686
 % Initialize user parameters managed here.
5e8686
 /JobName () .definepsuserparam
5e8686
@@ -415,7 +416,9 @@ psuserparams /ProcessDSCComment {.checkprocesscomment} put
5e8686
 
5e8686
 % VMReclaim and VMThreshold are user parameters.
5e8686
 /setvmthreshold {		% <int> setvmthreshold -
5e8686
-  mark /VMThreshold 2 .argindex .dicttomark .setuserparams2 pop
5e8686
+  mark /VMThreshold 2 .argindex .dicttomark {.setuserparams2} stopped
5e8686
+  {pop /setvmthreshold load $error /errorname get signalerror}
5e8686
+  {pop} ifelse
5e8686
 } odef
5e8686
 /vmreclaim {			% <int> vmreclaim -
5e8686
   dup 0 gt {
5e8686
@@ -427,7 +430,9 @@ psuserparams /ProcessDSCComment {.checkprocesscomment} put
5e8686
     ifelse
5e8686
   } {
5e8686
     % VMReclaim userparam controls enable/disable GC
5e8686
-    mark /VMReclaim 2 index .dicttomark .setuserparams2 pop
5e8686
+    mark /VMReclaim 2 index .dicttomark {.setuserparams2} stopped
5e8686
+    {pop /vmreclaim load $error /errorname get signalerror}
5e8686
+    {pop} ifelse
5e8686
   } ifelse
5e8686
 } odef
5e8686
 -1 setvmthreshold
5e8686
diff --git a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps
5e8686
index fb1c419..58e75d3 100644
5e8686
--- a/Resource/Init/gs_pdfwr.ps
5e8686
+++ b/Resource/Init/gs_pdfwr.ps
5e8686
@@ -660,7 +660,7 @@ currentdict /.pdfmarkparams .undef
5e8686
   {
5e8686
     pop
5e8686
   } ifelse
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef % must be bound and hidden for .forceput
5e8686
 
5e8686
 % Use the DSC processing hook to pass DSC comments to the driver.
5e8686
 % We use a pseudo-parameter named DSC whose value is an array:
5e8686
diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps
5e8686
index 8fa7c51..afb4ffa 100644
5e8686
--- a/Resource/Init/gs_setpd.ps
5e8686
+++ b/Resource/Init/gs_setpd.ps
5e8686
@@ -608,6 +608,20 @@ NOMEDIAATTRS {
5e8686
 % in the <failed> dictionary with the policy value,
5e8686
 % and we replace the key in the <merged> dictionary with its prior value
5e8686
 % (or remove it if it had no prior value).
5e8686
+
5e8686
+% Making this an operator means we can properly hide
5e8686
+% the contents - specifically .forceput
5e8686
+/1Policy
5e8686
+{
5e8686
+  % Roll back the failed request to its previous status.
5e8686
+  SETPDDEBUG { (Rolling back.) = pstack flush } if
5e8686
+  3 index 2 index 3 -1 roll .forceput
5e8686
+  4 index 1 index .knownget
5e8686
+   { 4 index 3 1 roll .forceput }
5e8686
+   { 3 index exch .undef }
5e8686
+  ifelse
5e8686
+} bind executeonly odef
5e8686
+
5e8686
 /.policyprocs mark
5e8686
 % These procedures are called with the following on the stack:
5e8686
 %   <orig> <merged> <failed> <Policies> <key> <policy>
5e8686
@@ -631,14 +645,7 @@ NOMEDIAATTRS {
5e8686
         /setpagedevice .systemvar /configurationerror signalerror
5e8686
       } ifelse
5e8686
   } bind
5e8686
-  1 {		% Roll back the failed request to its previous status.
5e8686
-SETPDDEBUG { (Rolling back.) = pstack flush } if
5e8686
-        3 index 2 index 3 -1 roll .forceput
5e8686
-        4 index 1 index .knownget
5e8686
-         { 4 index 3 1 roll .forceput }
5e8686
-         { 3 index exch .undef }
5e8686
-        ifelse
5e8686
-  } .bind executeonly % must be bound and hidden for .forceput
5e8686
+  1 /1Policy load
5e8686
   7 {		% For PageSize only, just impose the request.
5e8686
         1 index /PageSize eq
5e8686
          { pop pop 1 index /PageSize 7 put }
5e8686
@@ -646,6 +653,8 @@ SETPDDEBUG { (Rolling back.) = pstack flush } if
5e8686
         ifelse
5e8686
   } bind
5e8686
 .dicttomark readonly def
5e8686
+currentdict /1Policy undef
5e8686
+
5e8686
 /.applypolicies		% <orig> <merged> <failed> .applypolicies
5e8686
                         %   <orig> <merged'> <failed'>
5e8686
  { 1 index /Policies get 1 index
5e8686
diff --git a/Resource/Init/gs_typ32.ps b/Resource/Init/gs_typ32.ps
5e8686
index b6600b0..9150f71 100644
5e8686
--- a/Resource/Init/gs_typ32.ps
5e8686
+++ b/Resource/Init/gs_typ32.ps
5e8686
@@ -79,15 +79,19 @@ systemdict /.removeglyphs .undef
5e8686
 .dicttomark /ProcSet defineresource pop
5e8686
 
5e8686
 /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse
5e8686
-.cidfonttypes begin
5e8686
-
5e8686
-4	% CIDFontType 4 = FontType 32
5e8686
-{ dup /FontType 32 .forceput
5e8686
+/CIDFontType4
5e8686
+{
5e8686
+  dup /FontType 32 .forceput
5e8686
   dup /CharStrings 20 dict .forceput
5e8686
   1 index exch .buildfont32 exch pop
5e8686
-} .bind executeonly def % must be bound and hidden for .forceput
5e8686
+} .bind executeonly odef
5e8686
+.cidfonttypes begin
5e8686
+
5e8686
+
5e8686
+4 /CIDFontType4 load def % CIDFontType 4 = FontType 32
5e8686
 
5e8686
 end		% .cidfonttypes
5e8686
+currentdict /CIDFontType4 .forceundef
5e8686
 
5e8686
 % Define the BuildGlyph procedure.
5e8686
 % Since Type 32 fonts are indexed by CID, there is no BuildChar procedure.
5e8686
diff --git a/Resource/Init/gs_type1.ps b/Resource/Init/gs_type1.ps
5e8686
index efdae48..2935d9c 100644
5e8686
--- a/Resource/Init/gs_type1.ps
5e8686
+++ b/Resource/Init/gs_type1.ps
5e8686
@@ -283,7 +283,7 @@ currentdict /closesourcedict .undef
5e8686
   } if
5e8686
   2 copy /WeightVector exch .forceput
5e8686
   .setweightvector
5e8686
-} .bind executeonly def
5e8686
+} .bind executeonly odef
5e8686
 end
5e8686
 
5e8686
 % Register the font types for definefont.
5e8686
diff --git a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps
5e8686
index a82a2a3..7ccd4cd 100644
5e8686
--- a/Resource/Init/pdf_base.ps
5e8686
+++ b/Resource/Init/pdf_base.ps
5e8686
@@ -218,7 +218,7 @@ currentdict /num-chars-dict .undef
5e8686
       } ifelse
5e8686
     } ifelse
5e8686
   } ifelse
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 /PDFScanRules_true << /PDFScanRules //true >> def
5e8686
 /PDFScanRules_null << /PDFScanRules //null >> def
5e8686
 /.pdfrun {			% <file> <opdict> .pdfrun -
5e8686
diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps
5e8686
index d1b6ac9..c239daf 100644
5e8686
--- a/Resource/Init/pdf_draw.ps
5e8686
+++ b/Resource/Init/pdf_draw.ps
5e8686
@@ -1158,7 +1158,7 @@ currentdict end readonly def
5e8686
   Q
5e8686
   PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if
5e8686
   PDFfile exch setfileposition
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /.pdfpaintproc {
5e8686
     %% Get the /m from pdfopdict (must be present)
5e8686
@@ -1189,7 +1189,7 @@ currentdict end readonly def
5e8686
     {
5e8686
       switch_to_text_marking_ops
5e8686
     } if
5e8686
-}bind executeonly def
5e8686
+}bind executeonly odef
5e8686
 
5e8686
 /resolvepattern {	% <patternstreamdict> resolvepattern <patterndict>
5e8686
                 % Don't do the resolvestream now: just capture the data
5e8686
@@ -2353,7 +2353,7 @@ currentdict /last-ditch-bpc-csp undef
5e8686
   }{
5e8686
     pdfdict /AppearanceNumber 0 .forceput
5e8686
   } ifelse
5e8686
-}bind executeonly def
5e8686
+}bind executeonly odef
5e8686
 
5e8686
 /MakeAppearanceName {
5e8686
   pdfdict /AppearanceNumber get
5e8686
@@ -2382,7 +2382,7 @@ currentdict /last-ditch-bpc-csp undef
5e8686
   DoForm
5e8686
   pdfdict /.PreservePDFForm 3 -1 roll .forceput
5e8686
   grestore
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /DoForm {
5e8686
   %% save the current value, if its true we will set it to false later, in order
5e8686
@@ -2541,7 +2541,7 @@ currentdict /last-ditch-bpc-csp undef
5e8686
     end
5e8686
   } if
5e8686
   pdfdict /.PreservePDFForm 3 -1 roll .forceput
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /_dops_save 1 array def
5e8686
 
5e8686
diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps
5e8686
index feaf0d0..535b14a 100644
5e8686
--- a/Resource/Init/pdf_font.ps
5e8686
+++ b/Resource/Init/pdf_font.ps
5e8686
@@ -718,7 +718,7 @@ currentdict end readonly def
5e8686
   {pop pop pop}
5e8686
   ifelse
5e8686
 
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 currentdict /.DoToUnicode? .forceundef
5e8686
 
5e8686
@@ -1241,7 +1241,7 @@ currentdict /eexec_pdf_param_dict .undef
5e8686
     } bdef
5e8686
     dup currentdict Encoding .processToUnicode
5e8686
     currentdict end .completefont exch pop
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 /.adjustcharwidth {	% <wx> <wy> .adjustcharwidth <wx'> <wy'>
5e8686
   % Enforce the metrics, in glyph space, to the values found in the PDF Font object
5e8686
   % - force wy == 0 (assumed, and not stored in the PDF font)
5e8686
@@ -2026,7 +2026,7 @@ currentdict /CMap_read_dict undef
5e8686
     } if
5e8686
     /findresource cvx /undefined signalerror
5e8686
   } loop
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /buildCIDType0 {	% <CIDFontType0-font-resource> buildCIDType0 <font>
5e8686
   dup /BaseFont get findCIDFont exch pop
5e8686
@@ -2211,7 +2211,7 @@ currentdict /CMap_read_dict undef
5e8686
   /Type0 //buildType0
5e8686
   /Type1 //buildType1
5e8686
   /MMType1 //buildType1
5e8686
-  /Type3 //buildType3
5e8686
+  /Type3 /buildType3 load
5e8686
   /TrueType //buildTrueType
5e8686
   /CIDFontType0 //buildCIDType0
5e8686
   /CIDFontType2 //buildCIDType2
5e8686
diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps
5e8686
index 09f8735..c823e69 100644
5e8686
--- a/Resource/Init/pdf_main.ps
5e8686
+++ b/Resource/Init/pdf_main.ps
5e8686
@@ -660,7 +660,7 @@ currentdict /runpdfstring .undef
5e8686
     } forall
5e8686
     pop
5e8686
   } ifelse
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 currentdict /pdf_collection_files .undef
5e8686
 
5e8686
@@ -2715,7 +2715,7 @@ currentdict /PDF2PS_matrix_key undef
5e8686
   .setglobal
5e8686
   /RepairedAnError exch def
5e8686
   /Repaired exch def
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 % Display the contents of a page (including annotations).
5e8686
 /showpagecontents {	% <pagedict> showpagecontents -
5e8686
diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps
5e8686
index c45fc51..8672d61 100644
5e8686
--- a/Resource/Init/pdf_ops.ps
5e8686
+++ b/Resource/Init/pdf_ops.ps
5e8686
@@ -193,7 +193,7 @@ currentdict /gput_always_allow .undef
5e8686
       pdfformaterror
5e8686
     } ifelse
5e8686
   } if
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 % Save PDF gstate
5e8686
 /qstate {       % - qstate <qstate>
5e8686
@@ -451,7 +451,7 @@ currentdict /gput_always_allow .undef
5e8686
   %% a gsave, so we haven't copied it to /self, if we don't do that here
5e8686
   %% then transparent annotations cause an invalid access error.
5e8686
   currentdict //nodict eq {/self dup load end 5 dict begin def} if
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 /AIS { .setalphaisshape } bind executeonly def
5e8686
 /BM {
5e8686
   /.setblendmode where {
5e8686
@@ -1077,7 +1077,7 @@ end readonly def
5e8686
     pdfopdict /v {inside_text_v} bind .forceput
5e8686
     pdfopdict /y {inside_text_y} bind .forceput
5e8686
     pdfopdict /re {inside_text_re} bind .forceput
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /switch_to_normal_marking_ops {
5e8686
     pdfopdict /m {normal_m} bind .forceput
5e8686
@@ -1086,7 +1086,7 @@ end readonly def
5e8686
     pdfopdict /v {normal_v} bind .forceput
5e8686
     pdfopdict /y {normal_y} bind .forceput
5e8686
     pdfopdict /re {normal_re} bind .forceput
5e8686
-} bind executeonly def
5e8686
+} bind executeonly odef
5e8686
 
5e8686
 /BT {
5e8686
   currentdict /TextSaveMatrix known {
5e8686
-- 
5e8686
2.17.2
5e8686
5e8686
5e8686
From 1778db6bc10a8d60dfe986b22d2300326733ddd6 Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Thu, 4 Oct 2018 10:42:13 +0100
5e8686
Subject: [PATCH 3/6] Bug 699832: add control over hiding error handlers.
5e8686
5e8686
With a previous commit changing error handling in SAFER so the handler gets
5e8686
passed a name object (rather than executable object), it is less critical to
5e8686
hide the error handlers.
5e8686
5e8686
This introduces a -dSAFERERRORS option to force only use of the default error
5e8686
handlers.
5e8686
5e8686
It also adds a .setsafererrors Postscript call, meaning a caller, without
5e8686
-dSAFERERRORS, can create their own default error handlers (in errordict, as
5e8686
normal), and then call .setsafererrors meaning their own handlers are always
5e8686
called.
5e8686
5e8686
With -dSAFERERRORS or after a call to .setsafererrors, .setsafererrors is
5e8686
removed.
5e8686
---
5e8686
 Resource/Init/gs_init.ps | 42 ++++++++++++++++++++++++----------
5e8686
 psi/interp.c             | 49 ++++++++++++++++++++++++----------------
5e8686
 2 files changed, 59 insertions(+), 32 deletions(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
5e8686
index b94f873..a627eec 100644
5e8686
--- a/Resource/Init/gs_init.ps
5e8686
+++ b/Resource/Init/gs_init.ps
5e8686
@@ -188,6 +188,16 @@ currentdict /DELAYSAFER known { /DELAYSAFER //true def /NOSAFER //true def } if
5e8686
   currentdict /PARANOIDSAFER known or	% PARANOIDSAFER is equivalent
5e8686
 }
5e8686
 ifelse def
5e8686
+
5e8686
+/SAFERERRORS
5e8686
+currentdict /NOSAFERERRORS known
5e8686
+{
5e8686
+  //false
5e8686
+}
5e8686
+{
5e8686
+  currentdict /SAFERERRORS known
5e8686
+} ifelse def
5e8686
+
5e8686
 currentdict /SHORTERRORS known   /SHORTERRORS exch def
5e8686
 currentdict /TTYPAUSE known   /TTYPAUSE exch def
5e8686
 currentdict /WRITESYSTEMDICT known   /WRITESYSTEMDICT exch def
5e8686
@@ -1137,12 +1147,23 @@ errordict begin
5e8686
  } bind def
5e8686
 end		% errordict
5e8686
 
5e8686
-% Put all the default handlers in gserrordict
5e8686
-gserrordict
5e8686
-errordict {2 index 3 1 roll put} forall
5e8686
-noaccess pop
5e8686
-% remove the non-standard errors from errordict
5e8686
+gserrordict /unknownerror errordict /unknownerror get put
5e8686
 errordict /unknownerror .undef
5e8686
+
5e8686
+/.SAFERERRORLIST ErrorNames def
5e8686
+/.setsafererrors
5e8686
+{
5e8686
+% Put all the requested handlers in gserrordict
5e8686
+  gserrordict
5e8686
+  //.SAFERERRORLIST
5e8686
+  {dup errordict exch get 2 index 3 1 roll put} forall
5e8686
+  noaccess pop
5e8686
+  systemdict /.setsafeerrors .forceundef
5e8686
+  systemdict /.SAFERERRORLIST .forceundef
5e8686
+} bind executeonly odef
5e8686
+
5e8686
+SAFERERRORS {.setsafererrors} if
5e8686
+
5e8686
 % Define a stable private copy of handleerror that we will always use under
5e8686
 % JOBSERVER mode.
5e8686
 /.GShandleerror errordict /handleerror get def
5e8686
@@ -1774,18 +1795,15 @@ currentdict /.runlibfile .undef
5e8686
 
5e8686
 % Bind all the operators defined as procedures.
5e8686
 /.bindoperators		% binds operators in currentdict
5e8686
- { % Temporarily disable the typecheck error.
5e8686
-   errordict /typecheck 2 copy get
5e8686
-   errordict /typecheck { pop } put	% pop the command
5e8686
+ {
5e8686
    currentdict
5e8686
     { dup type /operatortype eq
5e8686
-       { % This might be a real operator, so bind might cause a typecheck,
5e8686
-         % but we've made the error a no-op temporarily.
5e8686
-         .bind
5e8686
+       {
5e8686
+         % This might be a real operator, so bind might cause a typecheck
5e8686
+         {.bind} .internalstopped pop
5e8686
        }
5e8686
       if pop pop
5e8686
     } forall
5e8686
-   put
5e8686
  } def
5e8686
 DELAYBIND not { .bindoperators } if
5e8686
 
5e8686
diff --git a/psi/interp.c b/psi/interp.c
5e8686
index 1dec9b6..d60c733 100644
5e8686
--- a/psi/interp.c
5e8686
+++ b/psi/interp.c
5e8686
@@ -661,27 +661,18 @@ again:
5e8686
     if (gs_errorname(i_ctx_p, code, &error_name) < 0)
5e8686
         return code;            /* out-of-range error code! */
5e8686
 
5e8686
-    /*  If LockFilePermissions is true, we only refer to gserrordict, which
5e8686
-     *  is not accessible to Postcript jobs
5e8686
+    /*  We refer to gserrordict first, which is not accessible to Postcript jobs
5e8686
+     *  If we're running with SAFERERRORS all the handlers are copied to gserrordict
5e8686
+     *  so we'll always find the default one. If not SAFERERRORS, only gs specific
5e8686
+     *  errors are in gserrordict.
5e8686
      */
5e8686
-    if (i_ctx_p->LockFilePermissions) {
5e8686
-        if (((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
5e8686
-              dict_find(perrordict, &error_name, &epref) <= 0))
5e8686
-            )
5e8686
-            return code;            /* error name not in errordict??? */
5e8686
-    }
5e8686
-    else {
5e8686
-        /*
5e8686
-         * For greater Adobe compatibility, only the standard PostScript errors
5e8686
-         * are defined in errordict; the rest are in gserrordict.
5e8686
-         */
5e8686
-        if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
5e8686
-            (dict_find(perrordict, &error_name, &epref) <= 0 &&
5e8686
-             (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
5e8686
-              dict_find(perrordict, &error_name, &epref) <= 0))
5e8686
-            )
5e8686
-            return code;            /* error name not in errordict??? */
5e8686
-    }
5e8686
+    if (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 ||
5e8686
+        (dict_find(perrordict, &error_name, &epref) <= 0 &&
5e8686
+         (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
5e8686
+          dict_find(perrordict, &error_name, &epref) <= 0))
5e8686
+        )
5e8686
+        return code;            /* error name not in errordict??? */
5e8686
+
5e8686
     doref = *epref;
5e8686
     epref = &doref;
5e8686
     /* Push the error object on the operand stack if appropriate. */
5e8686
@@ -694,6 +685,24 @@ again:
5e8686
         }
5e8686
         *osp = *perror_object;
5e8686
         errorexec_find(i_ctx_p, osp);
5e8686
+        /* If using SAFER, hand a name object to the error handler, rather than the executable
5e8686
+         * object/operator itself.
5e8686
+         */
5e8686
+        if (i_ctx_p->LockFilePermissions) {
5e8686
+            code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr);
5e8686
+            if (code < 0) {
5e8686
+                const char *unknownstr = "--unknown--";
5e8686
+                rlen = strlen(unknownstr);
5e8686
+                memcpy(buf, unknownstr, rlen);
5e8686
+            }
5e8686
+            else {
5e8686
+                buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
5e8686
+                rlen += 4;
5e8686
+            }
5e8686
+            code = name_ref(imemory, buf, rlen, osp, 1);
5e8686
+            if (code < 0)
5e8686
+                make_null(osp);
5e8686
+        }
5e8686
     }
5e8686
     goto again;
5e8686
 }
5e8686
-- 
5e8686
2.17.2
5e8686
5e8686
5e8686
From a6807394bd94b708be24758287b606154daaaed9 Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Tue, 2 Oct 2018 16:02:58 +0100
5e8686
Subject: [PATCH 4/6] For hidden operators, pass a name object to error
5e8686
 handler.
5e8686
5e8686
In normal operation, Postscript error handlers are passed the object which
5e8686
triggered the error: this is invariably an operator object.
5e8686
5e8686
The issue arises when an error is triggered by an operator which is for internal
5e8686
use only, and that operator is then passed to the error handler, meaning it
5e8686
becomes visible to the error handler code.
5e8686
5e8686
By converting to a name object, the error message is still valid, but we no
5e8686
longer expose internal use only operators.
5e8686
5e8686
The change in gs_dps1.ps is related to the above: previously an error in
5e8686
scheck would throw an error against .gcheck, but as .gcheck is now a hidden
5e8686
operator, it resulted in a name object being passed to the error handler. As
5e8686
scheck is a 'real' operator, it's better to use the real operator, rather than
5e8686
the name of an internal, hidden one.
5e8686
---
5e8686
 Resource/Init/gs_dps1.ps |  2 +-
5e8686
 psi/interp.c             | 33 ++++++++++++++++++++++++---------
5e8686
 2 files changed, 25 insertions(+), 10 deletions(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps
5e8686
index 1182f53..ec5db61 100644
5e8686
--- a/Resource/Init/gs_dps1.ps
5e8686
+++ b/Resource/Init/gs_dps1.ps
5e8686
@@ -21,7 +21,7 @@ level2dict begin
5e8686
 % ------ Virtual memory ------ %
5e8686
 
5e8686
 /currentshared /.currentglobal load def
5e8686
-/scheck /.gcheck load def
5e8686
+/scheck {.gcheck} bind odef
5e8686
 %****** FOLLOWING IS WRONG ******
5e8686
 /shareddict currentdict /globaldict .knownget not { 20 dict } if def
5e8686
 
5e8686
diff --git a/psi/interp.c b/psi/interp.c
5e8686
index d60c733..6dc0dda 100644
5e8686
--- a/psi/interp.c
5e8686
+++ b/psi/interp.c
5e8686
@@ -677,6 +677,8 @@ again:
5e8686
     epref = &doref;
5e8686
     /* Push the error object on the operand stack if appropriate. */
5e8686
     if (!GS_ERROR_IS_INTERRUPT(code)) {
5e8686
+        byte buf[260], *bufptr;
5e8686
+        uint rlen;
5e8686
         /* Replace the error object if within an oparray or .errorexec. */
5e8686
         osp++;
5e8686
         if (osp >= ostop) {
5e8686
@@ -685,23 +687,36 @@ again:
5e8686
         }
5e8686
         *osp = *perror_object;
5e8686
         errorexec_find(i_ctx_p, osp);
5e8686
-        /* If using SAFER, hand a name object to the error handler, rather than the executable
5e8686
-         * object/operator itself.
5e8686
-         */
5e8686
-        if (i_ctx_p->LockFilePermissions) {
5e8686
+
5e8686
+        if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) {
5e8686
             code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr);
5e8686
             if (code < 0) {
5e8686
                 const char *unknownstr = "--unknown--";
5e8686
                 rlen = strlen(unknownstr);
5e8686
                 memcpy(buf, unknownstr, rlen);
5e8686
+                bufptr = buf;
5e8686
             }
5e8686
             else {
5e8686
-                buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
5e8686
-                rlen += 4;
5e8686
+                ref *tobj;
5e8686
+                bufptr[rlen] = '\0';
5e8686
+                /* Only pass a name object if the operator doesn't exist in systemdict
5e8686
+                 * i.e. it's an internal operator we have hidden
5e8686
+                 */
5e8686
+                code = dict_find_string(systemdict, (const char *)bufptr, &tobj);
5e8686
+                if (code < 0) {
5e8686
+                    buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-';
5e8686
+                    rlen += 4;
5e8686
+                    bufptr = buf;
5e8686
+                }
5e8686
+                else {
5e8686
+                    bufptr = NULL;
5e8686
+                }
5e8686
+            }
5e8686
+            if (bufptr) {
5e8686
+                code = name_ref(imemory, buf, rlen, osp, 1);
5e8686
+                if (code < 0)
5e8686
+                    make_null(osp);
5e8686
             }
5e8686
-            code = name_ref(imemory, buf, rlen, osp, 1);
5e8686
-            if (code < 0)
5e8686
-                make_null(osp);
5e8686
         }
5e8686
     }
5e8686
     goto again;
5e8686
-- 
5e8686
2.17.2
5e8686
5e8686
5e8686
From a5a9bf8c6a63aa4ac6874234fe8cd63e72077291 Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Wed, 10 Oct 2018 23:25:51 +0100
5e8686
Subject: [PATCH 5/6] Bug 699938: .loadfontloop must be an operator
5e8686
5e8686
In the fix for Bug 699816, I omitted to make .loadfontloop into an operator, to
5e8686
better hide .forceundef and .putgstringcopy.
5e8686
---
5e8686
 Resource/Init/gs_fonts.ps | 2 +-
5e8686
 1 file changed, 1 insertion(+), 1 deletion(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
5e8686
index 89c3ab7..72feff2 100644
5e8686
--- a/Resource/Init/gs_fonts.ps
5e8686
+++ b/Resource/Init/gs_fonts.ps
5e8686
@@ -1148,7 +1148,7 @@ $error /SubstituteFont { } put
5e8686
 
5e8686
     } loop              % end of loop
5e8686
 
5e8686
- } bind executeonly def % must be bound and hidden for .putgstringcopy
5e8686
+ } bind executeonly odef % must be bound and hidden for .putgstringcopy
5e8686
 
5e8686
 currentdict /.putgstringcopy .undef
5e8686
 
5e8686
-- 
5e8686
2.17.2
5e8686
5e8686
5e8686
From 2756f0efae1d3966989b15a6526c5d80848b5015 Mon Sep 17 00:00:00 2001
5e8686
From: Chris Liddell <chris.liddell@artifex.com>
5e8686
Date: Wed, 28 Nov 2018 17:12:08 +0000
5e8686
Subject: [PATCH 6/6] Bug 700290: Fix problems with DELAYBIND and font
5e8686
 substitution
5e8686
5e8686
Judicious use of immediate evaluation for .setnativefontmapbuilt and
5e8686
.putgstringcopy to avoid problems with DELAYBIND
5e8686
---
5e8686
 Resource/Init/gs_fonts.ps | 9 ++++-----
5e8686
 1 file changed, 4 insertions(+), 5 deletions(-)
5e8686
5e8686
diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
5e8686
index 72feff2..7a57366 100644
5e8686
--- a/Resource/Init/gs_fonts.ps
5e8686
+++ b/Resource/Init/gs_fonts.ps
5e8686
@@ -419,7 +419,7 @@ systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt
5e8686
       } forall
5e8686
     } if
5e8686
     % record that we've been run
5e8686
-    //true .setnativefontmapbuilt
5e8686
+    //true //.setnativefontmapbuilt
5e8686
   } ifelse
5e8686
 } bind def
5e8686
 currentdict /.setnativefontmapbuilt .forceundef
5e8686
@@ -1103,7 +1103,7 @@ $error /SubstituteFont { } put
5e8686
 
5e8686
                 % Check to make sure the font was actually loaded.
5e8686
         dup 3 index .fontknownget
5e8686
-         { dup /PathLoad 4 index .putgstringcopy
5e8686
+         { dup /PathLoad 4 index //.putgstringcopy
5e8686
            4 1 roll pop pop pop //true exit
5e8686
          } if
5e8686
 
5e8686
@@ -1115,7 +1115,7 @@ $error /SubstituteFont { } put
5e8686
          {            % Stack: origfontname fontdirectory path filefontname
5e8686
            2 index 1 index .fontknownget
5e8686
             {   % Yes.  Stack: origfontname fontdirectory path filefontname fontdict
5e8686
-              dup 4 -1 roll /PathLoad exch .putgstringcopy
5e8686
+              dup 4 -1 roll /PathLoad exch //.putgstringcopy
5e8686
                       % Stack: origfontname fontdirectory filefontname fontdict
5e8686
               3 -1 roll pop
5e8686
                       % Stack: origfontname filefontname fontdict
5e8686
@@ -1149,8 +1149,7 @@ $error /SubstituteFont { } put
5e8686
     } loop              % end of loop
5e8686
 
5e8686
  } bind executeonly odef % must be bound and hidden for .putgstringcopy
5e8686
-
5e8686
-currentdict /.putgstringcopy .undef
5e8686
+currentdict /.putgstringcopy .forceundef
5e8686
 
5e8686
 % Define a procedure to load all known fonts.
5e8686
 % This isn't likely to be very useful.
5e8686
-- 
5e8686
2.17.2
5e8686