in reply to Passing taint checked scalars

I could be way off base (usually am), but I thought the only way to untaint a variable was to use regex 'special' variables $1,$2, etc... Thus the following is what comes to mind:
$filename =~ m{([\w./]+)}smx ? $filename = $1 : croak "Bah!";
Ignorance is not bliss, educate me please.

Replies are listed 'Best First'.
Re^2: Passing taint checked scalars
by martin (Friar) on Feb 04, 2006 at 08:06 UTC
    Let's walk through the OP's code snippet then:

    $filename =~ m{([\w./]+)}smx is a pattern match with capturing parentheses in list context, evaluating to a list of the captured strings on success, otherwise an empty list. ($filename) = ... is the list assignment that gives our pattern match its context (note the parentheses) and stores the result of the match back in $filename. If the match fails, an empty list is assigned and that way $filename becomes undefined.

    Now this whole assignment is the left hand side of a low-precedence or operation. The right hand side only gets evaluated if the left hand side evaluates to boolean false. A list assignment evaluates to true if and only if the list of things ready to be assigned is not empty, which is the case here if the pattern match succeeded.

    The last part, croak "Bah!" will thus only be called if the pattern match failed. On success, $filename is untainted and stripped of all extra characters outside the match. The first element of the matching list is exactly what also could have been accessed as $1. There you are.

    By the way, although this was some way to perform a taint check, the regular expression used here is not very effective to avoid danger. A user-supplied filename like ../../../etc/passwd, for example, would pass the check with nobody the wiser.

      Assuming I'm wish to enforce canonical paths, I believe:

      ($filename) = $filename =~ m{\A (/ ([\w./]+) )}smx and $filename !~ m{\.{2}\/}smx or die 'Bad filename';

      Covers me. Correct? Is there a more elegant way to do this?