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