[ 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.
Perl's open function is extremely feature-rich, and it has the
longest description of any function in Perl's perlfunc
documentation.
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(FILE,$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 $filename
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
like >/etc/passwd.
An even more serious problem arises when our $filename contains
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 < at
the start of the filename:
open(FILE,"<$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
all of open's magical features.
open.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 STDIN, STDOUT, and STDERR.
The syntax for duplicating a stream is rarely seen, but it should not be overlooked:
open(FILE,"<&=0") or die "Cannot dup STDIN - $!";
The <&=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
using the fileno function, but the standard file handles
STDIN, STDOUT, and 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(FILE,">&=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
STDIN and STDOUT, and that's the special filename
minus (-):
open(FILE,">-") or die "Cannot dup STDOUT - $!";
open(FILE,"<-") or die "Cannot dup STDIN - $!";
openPerl 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
separate argument.
Using our previous example of opening a file for reading, our code would now look like:
open(FILE,"<",$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
that name.
Using three-argument 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
sensitive context.
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
area.
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 ]
| Location | Course | Course Date | Duration | Early Bird Date |
|---|---|---|---|---|
| Melbourne | Programming Perl | Tue 2 Sep 2008 | 4 days | Mon 4 Aug 2008 |
| Sydney | Programming Perl | Tue 7 Oct 2008 | 4 days | Mon 8 Sep 2008 |
| Canberra | Programming Perl | Mon 24 Nov 2008 | 4 days | Mon 27 Oct 2008 |
For future dates, please see our training calendar.
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:
| Email: | contact@perltraining.com.au |
| Phone: | 03 9354 6001 (Australia) |
| International: | +61 3 9354 6001 |
Copyright 2001-2008 Perl Training Australia. Contact us at contact@perltraining.com.au