The taint mechanism tries to protect you from data supplied by a
potentially hostile user.  Such data can be trickily constructed to
cause your program to malfunction and provide said user with access to
which they are not entitled.  You can ask perl to do taint checking at
any time, but it automatically does it for setuid scripts.

Taint checking tracks the origin of all data used by your program.
Data from untrusted sources is considered tainted, and may not be used
as part of certain risky operations such as command lines, filenames,
etc.

The %ENV{} hash comes from shell environment variables, over which
presumably the user has some control, and thus, they are tainted.
Among the things in the hash is the search path for commands.  If the
user did something like "PATH=/home/eviluser/scripts:/bin:/usr/bin"
then invoked your program, and your program executed something like
"ls" without specifying a path, you might execute eviluser's
undesirable ls script instead of /bin/ls.  However, if taint checking
is turned on, this can't happen.

The way to work with the taint mechanism is to set the path explicitly
at the beginning of your program.  Do this with a string literal, to
avoid further taint issues, and only put known-secure directories into
the path.  For example, you could do:

    $ENV{"PATH"} = "/bin:/usr/bin";

Other data which is not tied to system functionality, e.g. text you
read from a file, can be de-tainted as follows:

    1. Ensure the data is safe, possibly by stripping out any
    constructs which are not known to be safe

    2. Use the following construct, which has the side effect of
    detainting:

        $untainted = ($tainted =~ /^(.*)$/);

    note that the pattern needs to match all of the data you want to
    keep.

Dennis Boone
MATRIX / Michigan State University

 > I just taint gettin' this taint thing. Please banish the darkness.

 > I've got a cgi program that makes a call to a homegrown package.  The
 > homegrown package (I made successfully!) among several things tried to
 > run this:

 > $host = `hostname`;

 > ....and of course it failed with this message in apache's error_log:

 > 1) Insecure $ENV{PATH} while running setuid at
 > /home/Louis/Perlib/LOUIS_utility.pm line 62.
 > 2) Compilation failed in require at /home/Louis/Cgi-bin/lz0006.pl line 35.
 > 3) BEGIN failed--compilation aborted at /home/Louis/Cgi-bin/lz0006.pl line
 > 35.

 > So I do some research into taintness in the "Cookbook" and find a
 > receipe to untaint (with the regular caveats about security). I take
 > the following code and insert it in my package to accomplish
 > identifying the hostname, and guess what. My cgi program works but I
 > still get the exact same message in the error_log above even after I
 > "cp /dev/null" the error_log file in case I was looking at an old
 > message. Here's the receipe code:

 > die "cannot fork:  $!" unless defined ($pid = open(SAFE, "|-"));
 > if ($pid == 0) {
 >      exec('hostname') or die "can't exec hostname: $!";
 > } else {
 >      $host = <SAFE>;
 >      close SAFE;
 > }

 > Perl baulks at the insecure env path in my package LOUIS_utility.pm
 > and the calling cgi program lz0006.pl fails to compile. And yet it
 > works!  If somebody simply tells me that this is impossible, I will
 > take a break and a deep breadth.

Reply via email to