develooper Front page | perl.perl5.porters | Postings from October 2013

Re: [perl #119855] chdir, taint, and if

Thread Previous
From:
Dave Mitchell
Date:
October 18, 2013 14:14
Subject:
Re: [perl #119855] chdir, taint, and if
Message ID:
20131018141403.GM2278@iabyn.com
On Tue, Oct 01, 2013 at 11:23:54AM +0200, Eirik Berg Hanssen wrote:
> On Tue, Oct 1, 2013 at 9:55 AM, Dave Mitchell <davem@iabyn.com> wrote:
> > In perlsec, it says:
> >
> >     For efficiency reasons, Perl takes a conservative view of
> >     whether data is tainted.  If an expression contains tainted data,
> >     any subexpression may be considered tainted, even if the value
> >     of the subexpression is not itself affected by the tainted data.
> >
> > perhaps we should s/an expression/a statement/ ?
> >
> 
>   I was thinking along the same lines, but this is referring to something
> else: Whether the data (the subexpression evaluates to) is tainted or not,
> not whether the command that attempts "to do something insecure" involves
> tainted data.
> 
>   What lacks documentation is how this involvement is determined.  And ...
> it's not simple ... hang on ...
> 
> 
> my $x = $taintedvar==16 ? '.' : '..'; # $x is not tainted, thanks to an
> explicit exception
> chdir($x); # involves no tainted data: success!
> 
> chdir(my $y = $taintedvar==16 ? '.' : '..'); # involves no tainted data:
> success!
> 
> chdir((my $z = $taintedvar==16) ? '.' : '..'); # involves no tainted data:
> success!
> 
> chdir($taintedvar==16 ? '.' : '..'); # somehow involves tainted data
> (though none is passed to chdir): fails!
> 
> chdir( sub { return '.' if pop==16; '..' }->($taintedvar) ); # somehow does
> not involve tainted data: success!
> 
> 
>   (If you replace those chdir calls with calls to &mychdir (simply wrapping
> chdir), they all succeed.)
> 
>   Is this intentional?  I doubt it.  Is it buggy?  Not necessarily.  It may
> be intentionally avoiding the detailed tracking of taintedness within a
> statement.
> 
>   If so, perhaps an addition to the documentation could go like so:
> 
>   «Likewise for efficiency reasons, Perl may avoid tracking taintedness
> within a non-compound statement.  If a non-compound statement uses tainted
> data, any subexpression may be considered to be using tainted data, even if
> the operands seen by the subexpression are not themselves tainted.»
> 
>   Or hey, p5p could decide that these are in fact bugs.  They're certainly
> bizarre enough.

Having rummaged around in the source for bit and having reminded myself of
how it works, I've come up with the following greatly expanded explanatory
text, which I propose adding to perlsec. I think it covers all your
examples above.

---------------------------------------------------------------------

For efficiency reasons, Perl takes a conservative view of whether data is
tainted. In general terms, this means that an operation is regarded as
unsafe if I<any> tainted data has been encountered during the current
expression or statement, even if the actual relevant arguments are
untainted. For example in the following expression,

    $tainted && chdir($clean);

the argument to chdir() is not tainted, but chdir() checks whether I<any>
taint was encountered during the current expression (which it was, due to
$tainted), and so fails.

In the underlying mechanism, Perl keeps track of tainting in two ways: the
tainting of individual values, and the tainting of the current expression.
Whenever a tainted value is accessed, the current expression is marked as
tainted. Whenever a value is updated, it is marked as tainted if the
current expression is tainted. This the main way in which taint propagates.

When a potentially unsafe operation is performed, it's usually the taint
of the current expression that is checked, not the taint of the individual
arguments (although if any arguments were tainted, accessing them should
have tainted the expression anyway).

Perl resets the expression taint at suitable boundaries, such as at the
end of a statement or block. When Perl knows that it is safe to do so, it
may additionally reset it at other points. In particular, scalar and array
assignment taint their left-hand arguments based on on the taint of the
individual right-hand arguments rather than on the taint of the whole
expression, and the resulting expression is untainted. For example in the
following:

    @a = ($clean, $tainted, $clean) and chdir($clean);

$a[1] becomes tainted; $a[0], $a[2] are clean, and the chdir() succeeds.


-- 
The crew of the Enterprise encounter an alien life form which is
surprisingly neither humanoid nor made from pure energy.
    -- Things That Never Happen in "Star Trek" #22

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About