[ Perl tips index ]
[ Subscribe to Perl tips ]
Opening files is a common operation in any programming language, and opening files in Perl is particularly easy. This is a good thing -- beginning programmers can learn the language more easily, and experienced programmers can get on with their job with less fuss and effort.
open function is extremely feature-rich, and it has the
longest description of any function in Perl's perlfunc
However, when programming in a security-sensitive context, the ease in which Perl allows us to open files can be a hindrance, rather than a help. When a process is running with elevated privileges, we usually wish to be specific about how files are opened, and we need to be particularly careful to avoid opening files the wrong way.
If the mode (reading, writing, appending) is not supplied to
the two-argument version of
open, then the file is opened
for reading. Here's an example:
open(my $fh,$filename) or die "Cannot read from $filename - $!";
Because we haven't told Perl how we wish to open the file, it is
opened for reading by default. But what happens if our
starts with a
>? Then our file isn't opened for reading at all,
instead we open the file for writing instead, clobbering its contents
if it already exists. This may just be an inconvenience, or it
could be a disaster, especially if our
$filename looks something
An even more serious problem arises when our
the pipe (
|) character. When this appears at the start or end
of the filename, Perl will execute a command instead of opening
a file. That could be used to spawn a shell, send out spam, or
do all manner of undesirable things.
The solution to these problems is simple. Always specify the
file operation when opening a file. In the above example, we can
explicitly open the file for reading by putting a
the start of the filename:
open(my $fh,"<$filename") or die "Cannot read from $filename - $!";
Many readers will feel safe and secure in the knowledge that they've
been doing this for years. However, that doesn't shield us from
open's magical features.
An often-forgotten feature of Perl's two-argument
open is that it
can be used to duplicate streams, as well as opening regular files.
Put very simply,
open can be used to gain access to other file handles
that are already open. These can include files, sockets, and the
special file handles
The syntax for duplicating a stream is rarely seen, but it should not be overlooked:
open(my $fh,"<&=0") or die "Cannot dup STDIN - $!";
<&=N syntax (where
N is a number) returns
another file handle corresponding to the file descriptor number
N. In Perl you can find the file descriptor number of a file handle
fileno function, but the standard file handles
STDERR are always assigned the special
numbers 0, 1 and 2 respectively. The equivalent construct can be
used to duplicate a file handle for writing:
open(my $fh,">&=1") or die "Cannot dup STDOUT - $!";
The risk of duplicating file-descriptors is that it may allow a clever attacker to unexpectedly read or write to another file handle that's already been opened by the process. These may include system files, configuration files, or even network sockets.
Perl has another shortcut for duplicating the file handles
STDOUT, and that's the special filename
open(my $fh,">-") or die "Cannot dup STDOUT - $!"; open(my $fh,"<-") or die "Cannot dup STDIN - $!";
Perl has a three-argument version of
open, which is much more strict
when it comes to processing its arguments. Using the 3-argument
open, the mode with which to open the file is passed as a
Using our previous example of opening a file for reading, our code would now look like:
open(my $fh,"<",$filename) or die "Cannot read from $filename - $!"
When using three-argument
open, the filename is treated literally.
This means that if it contains leading or trailing spaces, or any
other strange characters, Perl will try to open a file with exactly
open means you won't have any surprises when
you try to open a file, and as such it's highly recommended that
you make use of three-argument
open when working in a security
Using the three-argument version of
open isn't itself sufficient to
ensure your code is secure. You should always check input from unsafe
sources (typically anything outside of your program's control) before
passing it to
open. Taint, covered last week, is invaluable in this
Even so, your programs may be subject to race conditions. For example, in old-style locking code some programs do the following: if a lock file already exists, the program exits. If it does not, the lock file is created and the program runs on. If the test for existence and the file creation occur in two steps then there is a chance that the lock file will be created by another invocation between those two steps and two copies of the program will run together.
These issues and some methods to combat there will be covered further in the next installment.
[ Perl tips index ]
[ Subscribe to Perl tips ]
This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.
If you have any questions please don't hesitate to contact us:
|Phone:||03 9354 6001 (Australia)|
|International:||+61 3 9354 6001|
Copyright Perl Training Australia. Contact us at firstname.lastname@example.org