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
perlop(1):
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 (<>) {
print;
}
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 (<<>>) {
print;
}
> 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: