From 5c49efe24dda0f2dbd2a09b9159e683cce99b6d8 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Fri, 11 Jan 2019 13:36:36 +0000
Subject: [PATCH 7/7] Remove .forcedef, and harden .force* ops more

Remove .forcedef and replace all uses with a direct call to .forceput instead.

Ensure every procedure (named and trasient) that calls .forceput is
executeonly.

CVE: CVE-2019-6116
Upstream-Status: Backport [git://git.ghostscript.com/ghostpdl.git]

Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
---
 Resource/Init/gs_dps1.ps  | 15 +++++++-----
 Resource/Init/gs_init.ps  | 28 ++++++++-------------
 Resource/Init/gs_lev2.ps  | 51 +++++++++++++++++++--------------------
 Resource/Init/gs_ll3.ps   |  5 ++--
 Resource/Init/gs_res.ps   | 29 +++++++++++-----------
 Resource/Init/gs_statd.ps |  4 +--
 6 files changed, 63 insertions(+), 69 deletions(-)

diff --git a/Resource/Init/gs_dps1.ps b/Resource/Init/gs_dps1.ps
index 8700c8c..3d2cf7a 100644
--- a/Resource/Init/gs_dps1.ps
+++ b/Resource/Init/gs_dps1.ps
@@ -33,14 +33,17 @@ systemdict begin
 
 /SharedFontDirectory .FontDirectory .gcheck
  { .currentglobal //false .setglobal
+   currentdict
    /LocalFontDirectory .FontDirectory dup maxlength dict copy
-   .forcedef	% LocalFontDirectory is local, systemdict is global
+   .forceput	% LocalFontDirectory is local, systemdict is global
    .setglobal .FontDirectory
- }
- { /LocalFontDirectory .FontDirectory
-   .forcedef	% LocalFontDirectory is local, systemdict is global
+ } executeonly
+ {
+   currentdict
+   /LocalFontDirectory .FontDirectory
+   .forceput	% LocalFontDirectory is local, systemdict is global
    50 dict
- }
+ }executeonly
 ifelse def
 
 end				% systemdict
@@ -55,7 +58,7 @@ level2dict begin
     { //SharedFontDirectory }
     { /LocalFontDirectory .systemvar }	% can't embed ref to local VM
    ifelse .forceput pop	% LocalFontDirectory is local, systemdict is global
- } .bind odef
+ } .bind executeonly odef
 % Don't just copy (load) the definition of .setglobal:
 % it gets redefined for LL3.
 /setshared { /.setglobal .systemvar exec } odef
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index d9a0829..45bebf4 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -54,7 +54,7 @@ systemdict exch
    dup /userdict
    currentdict dup 200 .setmaxlength		% userdict
    .forceput			% userdict is local, systemdict is global
- }
+ } executeonly
 if begin
 
 % Define dummy local/global operators if needed.
@@ -299,13 +299,6 @@ QUIET not { printgreeting flush } if
   1 index exch .makeoperator def
 } .bind def
 
-% Define a special version of def for storing local objects into global
-% dictionaries.  Like .forceput, this exists only during initialization.
-/.forcedef {		% <key> <value> .forcedef -
-  1 .argindex pop	% check # of args
-  currentdict 3 1 roll .forceput
-} .bind odef
-
 % Define procedures for accessing variables in systemdict and userdict
 % regardless of the contents of the dictionary stack.
 /.systemvar {		% <name> .systemvar <value>
@@ -347,7 +340,7 @@ DELAYBIND
        }
       ifelse
     } .bind def
-} if
+} executeonly if
 
 %**************** BACKWARD COMPATIBILITY ****************
 /hwsizedict mark /HWSize //null .dicttomark readonly def
@@ -655,7 +648,7 @@ currentdict /.typenames .undef
       /ifelse .systemvar
     ] cvx executeonly
   exch .setglobal
-} odef
+} executeonly odef
 systemdict /internaldict dup .makeinternaldict .makeoperator
 .forceput		% proc is local, systemdict is global
 
@@ -1093,7 +1086,7 @@ def
 
 % Define $error.  This must be in local VM.
 .currentglobal //false .setglobal
-/$error 40 dict .forcedef	% $error is local, systemdict is global
+currentdict /$error 40 dict .forceput	% $error is local, systemdict is global
                 % newerror, errorname, command, errorinfo,
                 % ostack, estack, dstack, recordstacks,
                 % binary, globalmode,
@@ -1112,8 +1105,8 @@ end
 % Define errordict similarly.  It has one entry per error name,
 %   plus handleerror.  However, some astonishingly badly written PostScript
 %   files require it to have at least one empty slot.
-/errordict ErrorNames length 3 add dict
-.forcedef		% errordict is local, systemdict is global
+currentdict /errordict ErrorNames length 3 add dict
+.forceput		% errordict is local, systemdict is global
 .setglobal		% back to global VM
 %  gserrordict contains all the default error handling methods, but unlike
 %  errordict it is noaccess after creation (also it is in global VM).
@@ -1273,8 +1266,9 @@ end
 (END PROCS) VMDEBUG
 
 % Define the font directory.
+currentdict
 /FontDirectory //false .setglobal 100 dict //true .setglobal
-.forcedef		% FontDirectory is local, systemdict is global
+.forceput		% FontDirectory is local, systemdict is global
 
 % Define the encoding dictionary.
 /EncodingDirectory 16 dict def	% enough for Level 2 + PDF standard encodings
@@ -2333,7 +2327,6 @@ SAFER { .setsafeglobal } if
   //systemdict /UndefinePostScriptOperators get exec
   //systemdict /UndefinePDFOperators get exec
   //systemdict /.forcecopynew .forceundef	% remove temptation
-  //systemdict /.forcedef .forceundef		% ditto
   //systemdict /.forceput .forceundef		% ditto
   //systemdict /.undef .forceundef		    % ditto
   //systemdict /.forceundef .forceundef		% ditto
@@ -2368,9 +2361,9 @@ SAFER { .setsafeglobal } if
         % (and, if implemented, context switching).
   .currentglobal //false .setglobal
      mark userparams { } forall .dicttomark readonly
-     /userparams exch .forcedef		% systemdict is read-only
+     currentdict exch /userparams exch .forceput		% systemdict is read-only
   .setglobal
-} if
+} executeonly if
 /.currentsystemparams where {
   pop
         % Remove real system params from pssystemparams.
@@ -2458,7 +2451,6 @@ end
 DELAYBIND not {
   systemdict /.bindnow .undef       % We only need this for DELAYBIND
   systemdict /.forcecopynew .undef	% remove temptation
-  systemdict /.forcedef .undef		% ditto
   systemdict /.forceput .undef		% ditto
   systemdict /.forceundef .undef	% ditto
 } if
diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps
index 0f0d573..9c0c3a6 100644
--- a/Resource/Init/gs_lev2.ps
+++ b/Resource/Init/gs_lev2.ps
@@ -304,31 +304,30 @@ end
     psuserparams exch /.checkFilePermitparams load put
   .setglobal
 
-pssystemparams begin
-  /CurDisplayList 0 .forcedef
-  /CurFormCache 0 .forcedef
-  /CurInputDevice () .forcedef
-  /CurOutlineCache 0 .forcedef
-  /CurOutputDevice () .forcedef
-  /CurPatternCache 0 .forcedef
-  /CurUPathCache 0 .forcedef
-  /CurScreenStorage 0 .forcedef
-  /CurSourceList 0 .forcedef
-  /DoPrintErrors //false .forcedef
-  /JobTimeout 0 .forcedef
-  /LicenseID (LN-001) .forcedef     % bogus
-  /MaxDisplayList 140000 .forcedef
-  /MaxFormCache 100000 .forcedef
-  /MaxImageBuffer 524288 .forcedef
-  /MaxOutlineCache 65000 .forcedef
-  /MaxPatternCache 100000 .forcedef
-  /MaxUPathCache 300000 .forcedef
-  /MaxScreenStorage 84000 .forcedef
-  /MaxSourceList 25000 .forcedef
-  /PrinterName product .forcedef
-  /RamSize 4194304 .forcedef
-  /WaitTimeout 40 .forcedef
-end
+pssystemparams
+dup /CurDisplayList 0 .forceput
+dup /CurFormCache 0 .forceput
+dup /CurInputDevice () .forceput
+dup /CurOutlineCache 0 .forceput
+dup /CurOutputDevice () .forceput
+dup /CurPatternCache 0 .forceput
+dup /CurUPathCache 0 .forceput
+dup /CurScreenStorage 0 .forceput
+dup /CurSourceList 0 .forceput
+dup /DoPrintErrors //false .forceput
+dup /JobTimeout 0 .forceput
+dup /LicenseID (LN-001) .forceput     % bogus
+dup /MaxDisplayList 140000 .forceput
+dup /MaxFormCache 100000 .forceput
+dup /MaxImageBuffer 524288 .forceput
+dup /MaxOutlineCache 65000 .forceput
+dup /MaxPatternCache 100000 .forceput
+dup /MaxUPathCache 300000 .forceput
+dup /MaxScreenStorage 84000 .forceput
+dup /MaxSourceList 25000 .forceput
+dup /PrinterName product .forceput
+dup /RamSize 4194304 .forceput
+    /WaitTimeout 40 .forceput
 
 % Define the procedures for handling comment scanning.  The names
 % %ProcessComment and %ProcessDSCComment are known to the interpreter.
@@ -710,7 +709,7 @@ pop		% currentsystemparams
 /statusdict currentdict def
 
 currentdict end
-/statusdict exch .forcedef	% statusdict is local, systemdict is global
+currentdict exch /statusdict exch .forceput	% statusdict is local, systemdict is global
 
 % The following compatibility operators are in systemdict.  They are
 % defined here, rather than in gs_init.ps, because they require the
diff --git a/Resource/Init/gs_ll3.ps b/Resource/Init/gs_ll3.ps
index c86721f..881af44 100644
--- a/Resource/Init/gs_ll3.ps
+++ b/Resource/Init/gs_ll3.ps
@@ -521,9 +521,8 @@ end
 % Define additional user and system parameters.
 /HalftoneMode 0 .definepsuserparam
 /MaxSuperScreen 1016 .definepsuserparam
-pssystemparams begin		% read-only, so use .forcedef
-  /MaxDisplayAndSourceList 160000 .forcedef
-end
+% read-only, so use .forceput
+pssystemparams  /MaxDisplayAndSourceList 160000 .forceput
 
 % Define the IdiomSet resource category.
 { /IdiomSet } {
diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps
index b016113..89c0ed6 100644
--- a/Resource/Init/gs_res.ps
+++ b/Resource/Init/gs_res.ps
@@ -41,10 +41,10 @@ level2dict begin
 % However, Ed Taft of Adobe says their interpreters don't implement this
 % either, so we aren't going to worry about it for a while.
 
-currentglobal //false setglobal systemdict begin
-  /localinstancedict 5 dict
-  .forcedef	% localinstancedict is local, systemdict is global
-end //true setglobal
+currentglobal //false setglobal
+  systemdict /localinstancedict 5 dict
+  .forceput	% localinstancedict is local, systemdict is global
+//true setglobal
 /.emptydict 0 dict readonly def
 setglobal
 
@@ -149,7 +149,7 @@ setglobal
           dup [ exch 0 -1 ] exch
           .Instances 4 2 roll put
                 % Make the Category dictionary read-only.  We will have to
-                % use .forceput / .forcedef later to replace the dummy,
+                % use .forceput / .forceput later to replace the dummy,
                 % empty .Instances dictionary with the real one later.
           readonly
         }{
@@ -304,7 +304,8 @@ systemdict begin
      dup () ne {
      .file_name_directory_separator concatstrings
     } if
-    2 index exch //false .file_name_combine not {
+    2 index exch //false
+    .file_name_combine not {
       (Error: .default_resource_dir returned ) print exch print ( that can't combine with ) print =
       /.default_resource_dir cvx /configurationerror signalerror
     } if
@@ -317,14 +318,14 @@ currentdict /pssystemparams known not {
 pssystemparams begin
   //.default_resource_dir exec
   /FontResourceDir (Font) //.resource_dir_name exec
-     readonly .forcedef	% pssys'params is r-o
+     readonly currentdict 3 1 roll .forceput	% pssys'params is r-o
   /GenericResourceDir () //.resource_dir_name exec
-     readonly .forcedef	% pssys'params is r-o
+     readonly currentdict 3 1 roll .forceput	% pssys'params is r-o
   pop % .default_resource_dir
   /GenericResourcePathSep
-        .file_name_separator readonly .forcedef		% pssys'params is r-o
-  (%diskFontResourceDir) cvn (/Resource/Font/) readonly .forcedef	% pssys'params is r-o
-  (%diskGenericResourceDir) cvn (/Resource/) readonly .forcedef	% pssys'params is r-o
+        .file_name_separator readonly currentdict 3 1 roll .forceput		% pssys'params is r-o
+  currentdict (%diskFontResourceDir) cvn (/Resource/Font/) readonly .forceput	% pssys'params is r-o
+  currentdict (%diskGenericResourceDir) cvn (/Resource/) readonly .forceput	% pssys'params is r-o
 end
 end
 
@@ -422,8 +423,8 @@ status {
                 .Instances dup //.emptydict eq {
                   pop 3 dict
                         % As noted above, Category dictionaries are read-only,
-                        % so we have to use .forcedef here.
-                  /.Instances 1 index .forcedef	% Category dict is read-only
+                        % so we have to use .forceput here.
+                  currentdict /.Instances 2 index .forceput	% Category dict is read-only
                 } executeonly if
               }
               { .LocalInstances dup //.emptydict eq
@@ -441,7 +442,7 @@ status {
            { /defineresource cvx /typecheck signaloperror
            }
         ifelse
-} .bind executeonly .makeoperator		% executeonly to prevent access to .forcedef
+} .bind executeonly .makeoperator		% executeonly to prevent access to .forceput
 /UndefineResource
         {  { dup 2 index .knownget
               { dup 1 get 1 ge
diff --git a/Resource/Init/gs_statd.ps b/Resource/Init/gs_statd.ps
index 20d4c96..b6a7659 100644
--- a/Resource/Init/gs_statd.ps
+++ b/Resource/Init/gs_statd.ps
@@ -21,10 +21,10 @@ systemdict begin
         % We make statusdict a little larger for Level 2 stuff.
         % Note that it must be allocated in local VM.
  .currentglobal //false .setglobal
- /statusdict 91 dict .forcedef		% statusdict is local, sys'dict global
+ currentdict /statusdict 91 dict .forceput		% statusdict is local, sys'dict global
         % To support the Level 2 job control features,
         % serverdict must also be in local VM.
- /serverdict 10 dict .forcedef		% serverdict is local, sys'dict global
+ currentdict /serverdict 10 dict .forceput		% serverdict is local, sys'dict global
  .setglobal
 end
 
-- 
2.18.1

