Blob Blame History Raw
From: Ken Sharp <ken.sharp@artifex.com>
Date: Mon, 15 Oct 2018 10:28:28 +0000 (+0100)
Subject: Make .forceput unavailable from '.policyprocs' helper dictionary

Make .forceput unavailable from '.policyprocs' helper dictionary

Bug #69963 "1Policy is a dangerous operator, any callers should be odef"

Leaving the .policyprocs dictionary with a procedure which is a simple
wrapper for .forceput effectively leaves .forceput available.

It seems that the only reason to have .policyprocs is to minimise the
code in .applypolicies, so we can remove the dictionary and put the
code straight into .applypolicies, which we can then bind and make
executeonly, which hides the .forceput. Also, since we don't need
.applypolicies after startup, we can undefine that from systemdict too.

While we're here, review all the uses of .force* to make certain that
there are no other similar cases. This showed a few places where we
hadn't made a function executeonly, so do that too. Its probably not
required, since I'm reasonably sure its impossible to load those
functions as packed arrays (they are all defined as operators), but lets
have a belt and braces approach, the additional time cost is negligible.

https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=8d19fdf63f91f50466b08f23e2d93d37a4c5ea0b
---

diff -up ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_diskn.ps
--- ghostscript-9.07/Resource/Init/gs_diskn.ps.cve-2018-18284	2018-12-05 18:48:43.460994455 +0100
+++ ghostscript-9.07/Resource/Init/gs_diskn.ps	2018-12-05 18:49:15.314745554 +0100
@@ -61,7 +61,7 @@ systemdict begin
   % doesn't get run enough to justify the complication
   //.putdevparams
   //systemdict /.searchabledevs .forceundef
-} .bind odef % must be bound and hidden for .forceundef
+} .bind executeonly odef % must be bound and hidden for .forceundef
 
 % ------ extend filenameforall to handle wildcards in %dev% part of pattern -------%
 /filenameforall {
diff -up ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_dps.ps
--- ghostscript-9.07/Resource/Init/gs_dps.ps.cve-2018-18284	2018-12-05 18:48:43.460994455 +0100
+++ ghostscript-9.07/Resource/Init/gs_dps.ps	2018-12-05 18:48:43.471994369 +0100
@@ -125,7 +125,7 @@
   /savedinitialgstate .systemvar setgstate gsave
                 % Wrap up.
   end .setglobal
-} odef
+} bind executeonly odef
 
 % Check whether an object is a procedure.
 /.proccheck {			% <obj> .proccheck <bool>
diff -up ghostscript-9.07/Resource/Init/gs_epsf.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_epsf.ps
--- ghostscript-9.07/Resource/Init/gs_epsf.ps.cve-2018-18284	2013-02-14 08:58:16.000000000 +0100
+++ ghostscript-9.07/Resource/Init/gs_epsf.ps	2018-12-05 18:48:43.472994362 +0100
@@ -31,7 +31,7 @@
 /EPSBoundingBoxState 5 def
 /EPSBoundingBoxSetState {
   //systemdict /EPSBoundingBoxState 3 -1 roll .forceput
-} .bind odef % .forceput must be bound and hidden
+} .bind executeonly odef % .forceput must be bound and hidden
 
 % Parse 4 numbers for a bounding box
 /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false
diff -up ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_fonts.ps
--- ghostscript-9.07/Resource/Init/gs_fonts.ps.cve-2018-18284	2018-12-05 18:48:43.461994448 +0100
+++ ghostscript-9.07/Resource/Init/gs_fonts.ps	2018-12-05 18:48:43.472994362 +0100
@@ -572,7 +572,7 @@ buildfontdict 3 /.buildfont3 cvx put
 } bind def
 /.setloadingfont {
    //systemdict /.loadingfont 3 -1 roll .forceput
-} .bind odef % .forceput must be bound and hidden
+} .bind executeonly odef % .forceput must be bound and hidden
 /.loadfont
  {              % Some buggy fonts leave extra junk on the stack,
                 % so we have to make a closure that records the stack depth
@@ -985,7 +985,7 @@ $error /SubstituteFont { } put
     dup length string copy
     .forceput setglobal
   } ifelse
-} .bind odef % must be bound and hidden for .forceput
+} .bind executeonly odef % must be bound and hidden for .forceput
 
 % Attempt to load a font from a file.
 /.tryloadfont {         % <fontname> .tryloadfont <font> true
diff -up ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_init.ps
--- ghostscript-9.07/Resource/Init/gs_init.ps.cve-2018-18284	2018-12-05 18:48:43.454994502 +0100
+++ ghostscript-9.07/Resource/Init/gs_init.ps	2018-12-05 18:48:43.473994354 +0100
@@ -2200,7 +2200,7 @@ SAFER { .setsafe } if
 /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile
 /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams
 /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice
-/.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack
+/.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack /.applypolicies
 
 % Used by a free user in the Library of Congress. Apparently this is used to
 % draw a partial page, which is then filled in by the results of a barcode
diff -up ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-18284 ghostscript-9.07/Resource/Init/gs_setpd.ps
--- ghostscript-9.07/Resource/Init/gs_setpd.ps.cve-2018-18284	2018-12-05 18:48:43.462994440 +0100
+++ ghostscript-9.07/Resource/Init/gs_setpd.ps	2018-12-05 18:48:43.473994354 +0100
@@ -545,6 +545,23 @@ NOMEDIAATTRS {
 % and we replace the key in the <merged> dictionary with its prior value
 % (or remove it if it had no prior value).
 
+% These procedures are called with the following on the stack:
+%   <orig> <merged> <failed> <Policies> <key> <policy>
+% They are expected to consume the top 2 operands.
+% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
+% the same as 0, i.e., we signal an error.
+/0Policy {             % Set errorinfo and signal a configurationerror.
+  NOMEDIAATTRS {
+    % NOMEDIAATTRS means that the default policy is 7...
+    pop 2 index exch 7 put
+  } {
+    pop dup 4 index exch get 2 array astore
+    $error /errorinfo 3 -1 roll put
+    cleartomark
+    /setpagedevice .systemvar /configurationerror signalerror
+  } ifelse
+} bind executeonly odef
+
 % Making this an operator means we can properly hide
 % the contents - specifically .forceput
 /1Policy
@@ -553,59 +570,46 @@ NOMEDIAATTRS {
   SETPDDEBUG { (Rolling back.) = pstack flush } if
   3 index 2 index 3 -1 roll .forceput
   4 index 1 index .knownget
-   { 4 index 3 1 roll .forceput }
-   { 3 index exch .undef }
+  { 4 index 3 1 roll .forceput }
+  { 3 index exch .undef }
   ifelse
 } bind executeonly odef
 
-/.policyprocs mark
-% These procedures are called with the following on the stack:
-%   <orig> <merged> <failed> <Policies> <key> <policy>
-% They are expected to consume the top 2 operands.
-% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
-% the same as 0, i.e., we signal an error.
-%
-% M. Sweet, Easy Software Products:
-%
-% Define NOMEDIAATTRS to turn off the default (but unimplementable) media
-% selection policies for setpagedevice.  This is used by CUPS to support
-% the standard Adobe media attributes.
-  0 {		% Set errorinfo and signal a configurationerror.
-      NOMEDIAATTRS {
-        % NOMEDIAATTRS means that the default policy is 7...
-        pop 2 index exch 7 put
-      } {
-        pop dup 4 index exch get 2 array astore
-        $error /errorinfo 3 -1 roll put
-        cleartomark
-        /setpagedevice .systemvar /configurationerror signalerror
-      } ifelse
-  } bind
-  1 /1Policy load
-  7 {		% For PageSize only, just impose the request.
-        1 index /PageSize eq
-         { pop pop 1 index /PageSize 7 put }
-         { .policyprocs 0 get exec }
-        ifelse
-  } bind
-.dicttomark readonly def
-currentdict /1Policy undef
+/7Policy {             % For PageSize only, just impose the request.
+  1 index /PageSize eq
+  { pop pop 1 index /PageSize 7 put }
+  { .policyprocs 0 get exec }
+  ifelse
+} bind executeonly odef
 
 /.applypolicies		% <orig> <merged> <failed> .applypolicies
                         %   <orig> <merged'> <failed'>
- { 1 index /Policies get 1 index
-    { type /integertype eq
-       { pop		% already processed
-       }
-       { 2 copy .knownget not { 1 index /PolicyNotFound get } if
-                        % Stack: <orig> <merged> <failed> <Policies> <key>
-                        %   <policy>
-         .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
-       }
-      ifelse
-    }
-   forall pop
- } bind def
+{
+  1 index /Policies get 1 index
+  { type /integertype eq
+     {
+       pop             % already processed
+     }{
+       2 copy .knownget not { 1 index /PolicyNotFound get } if
+                      % Stack: <orig> <merged> <failed> <Policies> <key>
+                      %   <policy>
+        dup 1 eq {
+          1Policy
+        }{
+          dup 7 eq {
+            7Policy
+          }{
+            0Policy
+          } ifelse
+        } ifelse
+     } ifelse
+  }
+  forall pop
+} bind executeonly odef
+
+currentdict /0Policy undef
+currentdict /1Policy undef
+currentdict /7Policy undef
 
 % Prepare to present parameters to the device, by spreading them onto the
 % operand stack and removing any that shouldn't be presented.
@@ -907,7 +911,7 @@ SETPDDEBUG { (Installing.) = pstack flus
   } {
     .postinstall
   } ifelse
-} odef
+} bind executeonly odef
 
 % We break out the code after calling the Install procedure into a
 % separate procedure, since it is executed even if Install causes an error.