mikfire has asked for the wisdom of the Perl Monks concerning the following question:

This problem was originally in my user info, but I am confused enough now I will ask it correctly. Please believe me when I say I am certain I am correctly detainting all the data. I have read perlsec til my eyes bled. I can reproduce this on perl 5.5.3 running on both Solaris and FreeBSD as well as perl 5.6.0 running on Solaris.

I was working on some code that looked an awful lot like

my $file = $self->{Filename}; # This is detainted early on my $new_ext = ".new"; # This cannot be tainted my $new = $self->{Filename} . $new_ext; # Not tainted open NEW, "> $new" or die "Couldn't open $new : $!";
and the open line blew up with a taint violation.

I was unable to eyeball the situation and find my mistake so I added the is_tainted function from perlsec and rewrote the code to look like

my $file = $self->{Filename}; # This is detainted early on my $new_ext = ".new"; # This cannot be tainted my $new = $self->{Filename} . $new_ext; # Not tainted if ( is_tainted( $new ) ) { printf STDERR "%s is tainted by %s\n", $new, is_tainted( $file ) ? $file : $new_ext; } open NEW, "> $new" or die "Couldn't open $new : $!";
and this told me that $new_ext was tainted. My understanding of the taint rules says this is impossible - data hard coded in the program cannot be tainted.

Faced with nonsensical errors, I will quickly resort to nsensical solutions and reworked the code to look like

my $file = $self->{Filename}; # This is detainted early on my $new_ext = ".new"; # This cannot be tainted my $new = $file . $new_ext; # Not tainted if ( is_tainted( $new ) ) { printf STDERR "%s is tainted by %s\n", $new, is_tainted( $file ) ? $file : $new_ext; } open NEW, "> $new" or die "Couldn't open $new : $!";
and the taint violation went away. According to perlsec, the only way to detaint data is to send it through a regex and reference sub-expressions ( ie, $1, $2 ... ). I have not done that. I did a simple assignment, which is supposed to preserve the taint.

However, in studying the code I realized my original test was not quite correct - I was testing $file for taintedness when $new used $self->{Filename}. A quick examination of the source showed the $self->{Filename} is being detainted. Since being nonsensical had fixed the problem, I tried something equally nonsensical.

my $file = $self->{Filename}; # This is detainted early on my $new_ext = ".new"; # This cannot be tainted my $new = $file . $new_ext; # Not tainted if ( is_tainted( $self ) ) { printf STDERR "\$self ( %s ) is\n", ref( $self ); } open NEW, "> $new" or die "Couldn't open $new : $!";
and it told me the object was tainted. How can an object be tainted and, having been tainted, how do I detaint it? If I try to send it through a regex, the reference will be stringified and it will never refernce again. I still am uncertain how it got tainted in the first place.

I have hacked into the wee hours of the morning and was able to generate more data, but I still am unable to make sense of it.

The object getting tainted is being embedded in another object something like this

$self = { NAME => $name, HEAD => $TREE->HEAD, RCSDIR => $TREE->RCSDIR, ETCDIR => $TREE->ETCDIR, LOGOBJ => $logfile, FILE => $file, SEC => $param{sec}, LIB => $param{lib}, VFILE => $TREE }; # This is the object of interest
A few more debug statements told me the $TREE is not tainted but $self->{VFILE} is. I am still confused - if the data is not tainted, how can an assignment taint it? Oh, further investigation shows everything stored in the hash ref is tainted, but none of the originating data is. This is, I intuit, the clue.

Any suggestions? Any pointers to documentation outside of perlsec to help me understand? Advanced debugging tricks to make perl confess its taint? A well-applied two-by-four to my head?

mikfire

Replies are listed 'Best First'.
Re: I am so tainted
by Anonymous Monk on Jul 07, 2000 at 22:23 UTC
    I had similar problems. Then I tried the Untaint.pm module from CPAN, which also used the Taint.pm module. These worked well and I had no problems.
RE: I am so tainted
by mikfire (Deacon) on Jul 09, 2000 at 23:48 UTC
    In answer to the anonymous monk's post, I have looked at both the Taint and Untaint module. The Taint module implements the code from perlsec and puts some pretty wrappers around it. The Untaint module is an interesting mirror image of the code I have written called Detaint. I am doing things, it seems, pretty much according to Hoyle.

    I have isolated the issue. Consider the code

    #!/usr/bin/perl -T sub is_tainted { return ! eval { join('',@_), kill 0; 1; }; } #--- # This should taint things for me #--- my $taint = shift @ARGV; my $clean = "clean"; my $expected = { clean => $clean, taint => $taint, }; my $wrong = { taint => $taint, clean => $clean, }; printf "\$expected %s tainted\n", is_tainted( $expected ) ? "is" : "is +n't"; printf "\$expected->clean %s tainted\n", is_tainted( $expected->{clean} ) ? "is" : "isn't"; printf "\$expected->taint %s tainted\n", is_tainted( $expected->{taint} ) ? "is" : "isn't"; print "----------\n"; printf "\$wrong %s tainted\n", is_tainted( $wrong ) ? "is" : "isn't"; printf "\$wrong->clean %s tainted\n", is_tainted( $wrong->{clean} ) ? "is" : "isn't"; printf "\$wrong->taint %s tainted\n", is_tainted( $wrong->{taint} ) ? "is" : "isn't";
    If the first element in the hash ref is tainted, everything else is as well. If the first element is clean, it isn't. This is very wrong. Do I have enough for a bug report?

    Mik Firestone ( perlus bigotus maximus )

(chromatic) Re: I am so tainted
by chromatic (Archbishop) on Jul 11, 2000 at 07:46 UTC
    I'm not sure I understand the question completely, but if you're *positive* something like $self->{Filename} is okay, try: my $file = ($self->{Filename} =~ /^(.*)$/; Presumably, one could untaint an object with similar code:
    foreach (keys %$self) { $self->{$_} = ($self->{$_} =~ /^(.*)$/); }
    The standard disclaimer this time states that doing it that way really isn't all that secure (a hash slice would be better) and that this technique will only work on blessed hashes (other objects will go BOOM).