The double diamond, a more secure <>

We’ve had the three argument open since Perl 5.6. This allows us to separate the way we want to interact with the file from the filename. There’s a place where we don’t get to choose, but Perl 5.22 might introduce a new operator to handle that.

First, I’ll review the issue.

The old style of open allows me to conflate the file handle mode and the file name in one string:

open FILE, '> some_file';

That’s poor practice, even if it is habit. Now I can separate that information into three arguments.

open FILE, '>', 'some_file';

This is important when we use a variable for the filename argument.
With two-argument open we probably expect to open a file for writing
because that’s the implied mode:

open FILE, $filename;

What if, however, $filename isn’t just a filename? open gets a string and acts on what’s in that string. If it sees > at the beginning or a | at the end, it opens the file or the process in a particular way. Perl tries to be helpful when it can.

I discussed this in “Secure Programming Techniques” in Mastering Perl, but there’s another place that has this problem. The diamond operator, <>, automatically goes through the values in @ARGV and tries to open them. If those values have the special mode characters, Perl treats them as special. This is the same as <ARGV>, since that’s the implied filehandle.

Here’s a short Perl program that acts like cat:

#!/usr/bin/perl
# while.pl

print while( <> );

If I call this with the name of a regular file, the <> opens that file and prints its contents line by line. It can print its own source code:

$ perl while.pl while.pl
#!/usr/bin/perl

print while( <> );

However, if I create a filename with a pipe on the end, it uses the name for the program it should launch then redirects its output into ARGV. Here it happens with the date command:

$ perl while.pl 'date |'
Sat Oct  4 02:16:49 EDT 2014

Fantastic! If I had stopped to think about it, I might have come up with this trick, and now that I know about it, I can see how it might be useful to read the output of several commands easily. But, I hadn’t thought about it which means I hadn’t ever intended to support that feature, and that’s the problem. Insecurity stems from people doing things we don’t intend them to do by allowing loose programming constructs that are more flexible than our mandate.

I can try taint checking, which would recognize the values in @ARGV as dirty. Before I get that far, though, perl complains about the environment:

$ perl -T while.pl 'date |'
Insecure $ENV{PATH} while running with -T switch at while.pl line 3.

I can clean up the environment in the program. I tend to like completely erasing it and backtracking on particular keys that I later find I need. The PATH key is one I can do without, and in Mastering Perl I recommend using full paths to call external programs so you at least know where it was found. For now, I’ll just do without any environment variables:

#!/usr/bin/perl

%ENV = ();

print while( <> );

Now the diamond operator doesn’t treat the | as special:

$ perl -T while.pl 'date |'
Insecure dependency in piped open while running with -T switch at while.pl line 5.

A new operator might fix this. The double diamond, <<>>, the turns off this magic without the taint-checking:

while( <<>> ) { # no special shell characters there!
	... 
	}

This could be especially useful on the command line where I might write short programs and store them as aliases. Maybe we’ll get -N and -P switches that use while( <<>> ), too. If you want to read what p5p is writing about it, start at New feature proposal : <<>> to disable magic open of ARGV.