develooper Front page | perl.perl5.porters | Postings from July 2008

Taint bug (was: Creative and *routine* use of so-called "magic" ARGV (was [perl #2783] Security of ARGV using 2-argument open))

From:
Tom Christiansen
Date:
July 29, 2008 12:40
Subject:
Taint bug (was: Creative and *routine* use of so-called "magic" ARGV (was [perl #2783] Security of ARGV using 2-argument open))
Message ID:
16441.1217360399@chthon
In-Reply-To: Message from Mark Mielke <mark@mark.mielke.cc> 
   of "Tue, 29 Jul 2008 01:08:21 EDT." <488EA5C5.9050500@mark.mielke.cc> 

>  Tom Christiansen wrote:

>> [ how to support magical @ARGV better than today ]
>> If you feed an @ARGV or <STDIN> like this:

>>     /etc
>>     -
>>     /etc/passwd 
>>     /tmp/.X11-unix/X0 
>>     foo.gz 
>>     http://somewhere.com/path/to/foofile.gz 
>>     /etc/motd 
>>     /dev/tty 
>>     /tmp/fifo 
>>     ~/.exrc

> Very cool. Obviously, I wouldn't use it in a place where @ARGV
> can be passed in via a web page form.

"Obvious", you say.  And obvious I suppose it is--to me and thee.

But I'm increasingly susiciousness that we two may *not* be common case-
examples for adjudging obviousness.  That anyone would ever supply commands
with untested data coming from a potentially hostile entity isn't obvious.

Well, to me.  

What instead seems obvious is people without competence in security 
have been inappropriately tasked (or have tasked themselves) to create 
code beyond their ability.

If you don't understand fundamental matters of security but are
writing security-related code, at least one tacit problem exists, 
and probably more.

Perl arose in a culture where the security exploits most of us were worried
about were those involving trusted code run by untrusted users.  Setuid
programs (and to a lesser extent, setgid ones) that could be subverted to
misbehave were real concerns.  They were they were executing at a privilege
level distinct (and higher) than people running them.

Perl's dataflow-tracing that's engaged in taint mode was a real innovation
here.  The simple maxim that data taken from outside the program couldn't
be used to affect the state of anything outside your program,
*transitively*, was and is a great boon.  Per its design philosphy, Perl
keeps track of things even if you forget to.  Combined with indirect
execution and automatic memory management, Perl *can* make for a much safer
place to write secure code in than C does.

That "*can*" is a big one.  Just because it can, doesn't mean it does.

I once ran a code-review for company that did online Perl training.  As part
of their course, they'd let the remote type arbitrary Perl code into their
text input widgets, than blindly eval it.  They'd never heard of taintmode,
Safe compartments, per-user chrooting to sandboxes via loopback read-only
mounts, nor anything else that they should have been expert in.

Incredible, you may say, but perfectly and terrifyingly true.

More than once upon showing users the rename/relink/pathedit
script, I've had to address loud cries security-cries.  You'll
remember that this program, at its most basic level, is no more
than this:

    $op = shift;
    for (@ARGV) {
	$was = $_;
	eval $op;
	die  if @_;
	next if $was eq $_;
	rename($was, $_) || die "can't rename $was to $_: $!";
    } 

Why were they screaming?  Because of the eval.  They say, but now
people can say

    % rename 'system("/bin/rm -rf / &")' *.c

or some similar mayhem.

I then ask them how likely it is that they are ever going
to type 

    % /bin/rm -rf / 

into their own shells, and of course they say, "Never, that would
be really stupid."

But as you see, there's a misconnect here, because it's no different.
Why would a user ever want to hurt himself?

If you are the author of the code that you're running, you can trust 
yourself not to intentionally harm yourself.  You don't need a sandbox
to protect you.

If you are not that code's author, merely its executor, then you 
do not trust that code, and so you do.

If you write code that's run by untrustworthy agents, 
use and understand taint mode.

If you run code that was written by untrustworthy agents, 
use and understand Safe compartments--at least.

To my mind, it's a bug that while(<>) in taint mode doesn't
realize that a raw @ARGV from the command line is unsafe.

    % perl  -ne 'print ; exit' /etc/passwd
    root:*:0:0:Charlie &:/root:/bin/csh

    % perl -Tne 'print ; exit' /etc/passwd
    root:*:0:0:Charlie &:/root:/bin/csh

Since it knows that that's tainted data:

    % perl -MDevel::Peek -E '$s = shift; say Dump($s)' /etc/passwd    
    SV = PV(0x3c029038) at 0x3c0398c0
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x3c022560 "/etc/passwd"\0
      CUR = 11
      LEN = 12

    % perl -MDevel::Peek -TE '$s = shift; say Dump($s)' /etc/passwd
    SV = PVMG(0x3c035b80) at 0x3c03a8ac
      REFCNT = 1
      FLAGS = (GMG,SMG,pPOK)
      IV = 0
      NV = 0
      PV = 0x3c022210 "/etc/passwd"\0
      CUR = 11
      LEN = 12
      MAGIC = 0x3c03c460
	MG_VIRTUAL = &PL_vtbl_taint
	MG_TYPE = PERL_MAGIC_taint(t)
	MG_LEN = 1

And knows better than to let you use it in external commands:

    % perl -MDevel::Peek -TE '$ENV{PATH} = "/bin:/usr/bin"; $s = shift; print Dump($s); system("head", -1, $s)' /etc/passwd
    SV = PVMG(0x3c035b80) at 0x3c03a938
      REFCNT = 1
      FLAGS = (GMG,SMG,pPOK)
      IV = 0
      NV = 0
      PV = 0x3c022210 "/etc/passwd"\0
      CUR = 11
      LEN = 12
      MAGIC = 0x3c03c460
	MG_VIRTUAL = &PL_vtbl_taint
	MG_TYPE = PERL_MAGIC_taint(t)
	MG_LEN = 1
    Insecure dependency in system while running with -T switch at -e line 1.
    Exit 19

--tom



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