Blob Blame History Raw
From 8d19fdf63f91f50466b08f23e2d93d37a4c5ea0b Mon Sep 17 00:00:00 2001
From: Ken Sharp <ken.sharp@artifex.com>
Date: Mon, 15 Oct 2018 11:28:28 +0100
Subject: [PATCH] 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.
---
 Resource/Init/gs_diskn.ps |   2 +-
 Resource/Init/gs_dps.ps   |   2 +-
 Resource/Init/gs_epsf.ps  |   2 +-
 Resource/Init/gs_fonts.ps |   4 +-
 Resource/Init/gs_init.ps  |   2 +-
 Resource/Init/gs_setpd.ps | 100 ++++++++++++++++++++------------------
 6 files changed, 58 insertions(+), 54 deletions(-)

diff --git a/Resource/Init/gs_diskn.ps b/Resource/Init/gs_diskn.ps
index 26ec0b5..fd694bc 100644
--- a/Resource/Init/gs_diskn.ps
+++ b/Resource/Init/gs_diskn.ps
@@ -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 --git a/Resource/Init/gs_dps.ps b/Resource/Init/gs_dps.ps
index daf7b0f..00c14d5 100644
--- a/Resource/Init/gs_dps.ps
+++ b/Resource/Init/gs_dps.ps
@@ -124,7 +124,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 --git a/Resource/Init/gs_epsf.ps b/Resource/Init/gs_epsf.ps
index e4037d9..2d0f677 100644
--- a/Resource/Init/gs_epsf.ps
+++ b/Resource/Init/gs_epsf.ps
@@ -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 --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps
index 7a57366..052a191 100644
--- a/Resource/Init/gs_fonts.ps
+++ b/Resource/Init/gs_fonts.ps
@@ -583,7 +583,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
@@ -1012,7 +1012,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 --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index 2114a2a..0b900e6 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -2244,7 +2244,7 @@ SAFER { .setsafeglobal } 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 --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps
index fab8b84..71eb622 100644
--- a/Resource/Init/gs_setpd.ps
+++ b/Resource/Init/gs_setpd.ps
@@ -609,6 +609,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
@@ -617,59 +634,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.
@@ -1012,7 +1016,7 @@ SETPDDEBUG { (Installing.) = pstack flush } if
     .postinstall
   } ifelse
   setglobal           % return to original VM allocation mode
-} 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.
-- 
2.17.2