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

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