[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Potentially insecure Perl scripts

Ian Jackson <ijackson@chiark.greenend.org.uk> writes:

> Apparently this has been klnown about for EIGHTEEN YEARS
>   https://rt.perl.org/Public/Bug/Display.html?id=2783
> and no-one has fixed it or even documented it.

It's been documented for pretty close to eighteen years too.  See

       The null filehandle "<>" is special: it can be used to emulate the
       behavior of sed and awk, and any other Unix filter program that
       takes a list of filenames, doing the same to each line of input
       from all of them.  Input from "<>" comes either from standard
       input, or from each file listed on the command line.  Here's how it
       works: the first time "<>" is evaluated, the @ARGV array is
       checked, and if it is empty, $ARGV[0] is set to "-", which when
       opened gives you standard input.  The @ARGV array is then processed
       as a list of filenames.  The loop

           while (<>) {
               ...                     # code for each line

       is equivalent to the following Perl-like pseudo code:

           unshift(@ARGV, '-') unless @ARGV;
           while ($ARGV = shift) {
               open(ARGV, $ARGV);
               while (<ARGV>) {
                   ...         # code for each line

       except that it isn't so cumbersome to say, and will actually work.
       It really does shift the @ARGV array and put the current filename
       into the $ARGV variable.  It also uses filehandle ARGV internally.
       "<>" is just a synonym for "<ARGV>", which is magical.  (The pseudo
       code above doesn't work because it treats "<ARGV>" as non-magical.)

       Since the null filehandle uses the two argument form of "open" in
       perlfunc it interprets special characters, so if you have a script
       like this:

           while (<>) {

       and call it with "perl dangerous.pl 'rm -rfv *|'", it actually
       opens a pipe, executes the "rm" command and reads "rm"'s output
       from that pipe.  If you want all items in @ARGV to be interpreted
       as file names, you can use the module "ARGV::readonly" from CPAN,
       or use the double bracket:

           while (<<>>) {

> I think this is a serious bug in Perl which should be fixed in a
> security update.

There is absolutely no way.  So much stuff in Perl depends on this.  You
will break all kinds of scripts.  It's been a feature of the language for
basically forever.

There have been extensive discussions of this on perl5-porters, and
there's some general consensus that it was a bad idea originally, but
changing this destroys backwards compatibility.  You just can't; it's like
removing strcpy from libc.  The best you could do would be to add a
pragmata to turn it off, and *maybe*, *someday*, enable that pragmata by
default with a sufficiently new version in "use".

Russ Allbery (rra@debian.org)               <http://www.eyrie.org/~eagle/>

Reply to: