[tex-live] Status of restricted \write18 and epstopdf conversion

Alexander Cherepanov cherepan at mccme.ru
Sun Oct 18 00:57:37 CEST 2009


Hi Manuel!
On Thu, 15 Oct 2009 23:55:16 +0200, Manuel Pégourié-Gonnard <mpg at elzevir.fr> wrote:

> repstopdf, which has been specially crafted for
> this purpose: all options are checked to avoid injection, so the only
> external program called is ghostscript with -dSAFER, 

First of all, you talk about 
rsync://tug.org/tldevsrc/Master/texmf-dist/scripts/epstopdf/epstopdf.pl
(size: 17776, last changed: 2009/10/15 03:39:50), right?

As far as I can see, there are no checks for injections in --outfile= 
at all. Arbitrary command execution is possible:

  ./repstopdf --outfile='out.pdf" - -c quit; echo Hi! > out; true "' input.eps

This should be prohibited, I suppose?

The following should be prohibited as well:

  ./repstopdf --gscmd="gs
  " input.eps

  ./repstopdf --autorotate="None
  " input.eps

> and the output file
> name is subject to conditions more restrictive than openout_any=p (it
> was easier than to implement a true support of this variable). 

There is a couple of quirks on Windows. Relative paths on other 
drives (like "c:dir/file") are allowed. And alternate data streams 
on NTFS (like "file:ads") are allowed (didn't test it but should work; 
no big deal in a any case but to be on a safe side it's better to ban 
it). Both could be ruled out by checking for a colon.

And you can use backslash as a path separator on cygwin:

  ./repstopdf --outfile='dir\..\..\..\out.pdf' input.eps

(tested on cygwin1.5 only).

Approximate patch:

--- epstopdf.pl.orig    2009-10-15 03:39:50.000000000 +0400
+++ epstopdf.pl 2009-10-18 02:50:24.000000000 +0400
@@ -277,7 +277,7 @@
 # \label{val_autorotate}
 die "Invalid value for autorotate: '$::opt_autorotate' (use 'All', 'None' or 'PageByPage').\n"
     if ($::opt_autorotate and 
-        not $::opt_autorotate =~ /^(None|All|PageByPage)$/);
+        not $::opt_autorotate =~ /^(None|All|PageByPage)\z/);
 
 ### option BoundingBox types
 my $BBName = "%%BoundingBox:";
@@ -320,10 +320,20 @@
     my ($drive, $path, $basename) = splitpath($OutputFilename);
     $ok = 0 if $basename =~ /^\./;
   }
+  # disallow colon on Windows. It could be used either after a drive 
+  # (like "a:dir\file") or for an alternate data stream (like 
+  # "file:ads").
+  if ($^O eq "MSWin32" || $^O eq "cygwin") {
+    $ok = 0 if $OutputFilename =~ /:/;
+  }
+  # disallow quote
+  $ok = 0 if $OutputFilename =~ /"/;
+  # disallow newline (just to be on a safe side)
+  $ok = 0 if $OutputFilename =~ /\n/;
   # disallow absolute path
   $ok = 0 if file_name_is_absolute($OutputFilename);
   # disallow going to parent directory
-  my $ds = ($^O eq "MSWin32") ? qr([\\/]) : qr(/);
+  my $ds = ($^O eq "MSWin32" || $^O eq "cygwin") ? qr([\\/]) : qr(/);
   $ok = 0 if $OutputFilename =~ /^\.\.$ds|$ds\.\.$ds/;
   # we passed all tests
   die error "Output filename '$OutputFilename' not allowed in restricted mode." unless $ok;
@@ -335,8 +345,8 @@
   $GS = $::opt_gscmd;
   # validate GS \label{val_gscmd}
   if ($restricted) {
-    $GS =~ /^(gs|mgs|gswin32c|gs386|gsos2)$/
-      or $GS =~ /^gs[\-_]?(\d|\d[\.-_]?\d\d)c?$/
+    $GS =~ /^(gs|mgs|gswin32c|gs386|gsos2)\z/
+      or $GS =~ /^gs[\-_]?(\d|\d[\.-_]?\d\d)c?\z/
       or die error "Value of gscmd '$GS' not allowed in restricted mode.";
   }
 }

It should be tested more thoroughly (at least at cygwin1.7) but I want 
to get it out earlier.

Alexander Cherepanov




More information about the tex-live mailing list