You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Peter Ensch <pe...@ti.com> on 2003/07/09 17:24:23 UTC

untainting PATH in mod_perl

perlsec says that to untaint the PATH env one should
do: 
  $ENV{'PATH'} = '/bin:/usr/bin';
  delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

In plain CGI, I normally do this inside a BEGIN 
block; in mod_perl however, this doesn't work. A
print of $ENV{PATH} returns the original tainted
PATH.

In my script I'm doing something like
 foreach(`/bin/ls $path`) {
   <do something> 
 }

$path is already untainted but I'm still getting 
an 'Insecure $ENV{PATH}' error. What am I missing 
here?

Thanks,
P

-- 

^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
Peter Ensch,
pensch@ti.com           A-1140   (214) 480 2333
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

Re: untainting PATH in mod_perl

Posted by Peter Ensch <pe...@ti.com>.
On Tue, Jul 15, 2003 at 04:30:35PM +0300, Stas Bekman wrote:
> Peter B. Ensch wrote:
> 
> >>FWIW, I use the following code when I need to use ``|qx:
> >>
> >>local $ENV{PATH} = "/bin:/usr/bin";
> >>local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };
> >
> >But this code must be used in each scope where you intend to use 
> >backticks, a system call Etc. Is there no way to untaint your
> >PATH environment one time for the script or handler?
> 
> If you write code used by other people this is probably the only way to go. 
> This is because you want to control the setting. What if PATH gets 
> untainted at the server startup, but then some other module sets a new 
> tainted value to $ENV{PATH}? So it's a good habit to have it local to the 
> code that you run.
> 
> Besides helps to avoid forking external processes. If you can rewrite your 
> code:
> 
>  foreach(`/bin/ls $path`) {
>    <do something>
>  }
> 
> (which is probably not the real code), not to `` but to read the file in, 
> and process it, you eliminate the whole problem altogether. I realize that 
> this is not always possible.
> 
> How about abstracting untaint and `` into a single function:
> 
> sub backticks {
>   local $ENV{PATH} = "/bin:/usr/bin";
>   local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };
>   qx(@_);
> }
> 

Stas,

Thanks for your explanation and suggestion. I'm a lot clearer on this
issue now.

P.

-- 

^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
Peter Ensch,
pensch@ti.com           A-1140   (214) 480 2333
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

Re: untainting PATH in mod_perl

Posted by Stas Bekman <st...@stason.org>.
Peter B. Ensch wrote:

>>FWIW, I use the following code when I need to use ``|qx:
>>
>>local $ENV{PATH} = "/bin:/usr/bin";
>>local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };
> 
> But this code must be used in each scope where you intend to use 
> backticks, a system call Etc. Is there no way to untaint your
> PATH environment one time for the script or handler?

If you write code used by other people this is probably the only way to go. 
This is because you want to control the setting. What if PATH gets untainted 
at the server startup, but then some other module sets a new tainted value to 
$ENV{PATH}? So it's a good habit to have it local to the code that you run.

Besides helps to avoid forking external processes. If you can rewrite your code:

  foreach(`/bin/ls $path`) {
    <do something>
  }

(which is probably not the real code), not to `` but to read the file in, and 
process it, you eliminate the whole problem altogether. I realize that this is 
not always possible.

How about abstracting untaint and `` into a single function:

sub backticks {
   local $ENV{PATH} = "/bin:/usr/bin";
   local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };
   qx(@_);
}

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: untainting PATH in mod_perl

Posted by "Peter B. Ensch" <pe...@comcast.net>.
On Tue, Jul 15, 2003 at 12:19:14PM +0300, Stas Bekman wrote:
> Dominique Quatravaux wrote:
> >> Sorry, getting out of good ideas.. 
> >
> >
> >  Surprise, surprise: I found out that my code does not work under
> >mod_perl 1.23 either! And I found the real solution: one has to add
> >
> >  PerlSetupEnv Off
> >
> >to the Apache configuration file. Now the untainting mumbo-jumbo in
> ><perl> section works.
> >
> >  Warning: this has the consequence of breaking the part of the CGI
> >environment emulation that deals with environment (e.g. instead of
> >$ENV{"HTTP_USER_AGENT"}, you now have to check
> >Apache->request()->subprocess_env("HTTP_USER_AGENT")). Glancing at its
> >source code, I don't think CGI.pm will survive that...
> >
> >  BTW, I finally got around to reading mod_perl's source, and it
> >is now clear to me that the environment, when being copied from
> >->subprocess_env() into %ENV, gets tainted (around line 704 in
> >src/modules/perl/mod_perl.c). The whole %ENV gets tainted, not just
> >the HTTP_USER_AGENT and such from the CGI context, so PATH is tainted
> >as well. This explains our now common problem - and also guarantees
> >that there is no easy way out of it if you use CGI.pm yourself :-(.
> 
> You need to untaint the variables before you use them. Since they get reset 
> on every request, you need to untaint them inside your script/handler's run 
> time, not the BEGIN block...:
> http://perl.apache.org/docs/1.0/guide/porting.html#BEGIN_blocks
> 
> it should work just fine with mp1 and mp2.
> 
> Relying on 'PerlSetupEnv Off' is not a very good idea, since if you want to 
> release your code for others to use, they may not be able to turn it off, 
> since it'll break their CGI-legacy code as you have observed.
> 
> FWIW, I use the following code when I need to use ``|qx:
> 
> local $ENV{PATH} = "/bin:/usr/bin";
> local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };
> 
> 

But this code must be used in each scope where you intend to use 
backticks, a system call Etc. Is there no way to untaint your
PATH environment one time for the script or handler?

P

-- 
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
Peter B. Ensch (peterbe@comcast.net)   
                                       
Linux 2.4.20-4GB 5:47am Up 2 days 18:47
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

Re: untainting PATH in mod_perl

Posted by Stas Bekman <st...@stason.org>.
Dominique Quatravaux wrote:
>>  Sorry, getting out of good ideas.. 
> 
> 
>   Surprise, surprise: I found out that my code does not work under
> mod_perl 1.23 either! And I found the real solution: one has to add
> 
>   PerlSetupEnv Off
> 
> to the Apache configuration file. Now the untainting mumbo-jumbo in
> <perl> section works.
> 
>   Warning: this has the consequence of breaking the part of the CGI
> environment emulation that deals with environment (e.g. instead of
> $ENV{"HTTP_USER_AGENT"}, you now have to check
> Apache->request()->subprocess_env("HTTP_USER_AGENT")). Glancing at its
> source code, I don't think CGI.pm will survive that...
> 
>   BTW, I finally got around to reading mod_perl's source, and it
> is now clear to me that the environment, when being copied from
> ->subprocess_env() into %ENV, gets tainted (around line 704 in
> src/modules/perl/mod_perl.c). The whole %ENV gets tainted, not just
> the HTTP_USER_AGENT and such from the CGI context, so PATH is tainted
> as well. This explains our now common problem - and also guarantees
> that there is no easy way out of it if you use CGI.pm yourself :-(.

You need to untaint the variables before you use them. Since they get reset on 
every request, you need to untaint them inside your script/handler's run time, 
not the BEGIN block...:
http://perl.apache.org/docs/1.0/guide/porting.html#BEGIN_blocks

it should work just fine with mp1 and mp2.

Relying on 'PerlSetupEnv Off' is not a very good idea, since if you want to 
release your code for others to use, they may not be able to turn it off, 
since it'll break their CGI-legacy code as you have observed.

FWIW, I use the following code when I need to use ``|qx:

local $ENV{PATH} = "/bin:/usr/bin";
local @ENV{ qw(IFS CDPATH ENV BASH_ENV) };


__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: untainting PATH in mod_perl

Posted by Dominique Quatravaux <do...@idealx.com>.
>   Sorry, getting out of good ideas.. 

  Surprise, surprise: I found out that my code does not work under
mod_perl 1.23 either! And I found the real solution: one has to add

  PerlSetupEnv Off

to the Apache configuration file. Now the untainting mumbo-jumbo in
<perl> section works.

  Warning: this has the consequence of breaking the part of the CGI
environment emulation that deals with environment (e.g. instead of
$ENV{"HTTP_USER_AGENT"}, you now have to check
Apache->request()->subprocess_env("HTTP_USER_AGENT")). Glancing at its
source code, I don't think CGI.pm will survive that...

  BTW, I finally got around to reading mod_perl's source, and it
is now clear to me that the environment, when being copied from
->subprocess_env() into %ENV, gets tainted (around line 704 in
src/modules/perl/mod_perl.c). The whole %ENV gets tainted, not just
the HTTP_USER_AGENT and such from the CGI context, so PATH is tainted
as well. This explains our now common problem - and also guarantees
that there is no easy way out of it if you use CGI.pm yourself :-(.

  Hope I'm being helpful at last,

-- 
Dominique QUATRAVAUX                           Ingénieur senior
01 44 42 00 08                                 IDEALX



Re: untainting PATH in mod_perl

Posted by Dominique Quatravaux <do...@idealx.com>.
> Thanks for sharing your code; unfortunately, it's not working for me.
> I copied it into my httpd.conf file, stopped/started the server and
> I still get the same error:

  Sorry, getting out of good ideas.. I'm not using mod_perl 1.99, this
probably explains why my code does not work, and also it prevents me
from further investigating your problem. There was a thread recently
on the list about <perl> ... </perl> section only being implemented
recently, do you run the latest version of mod_perl?

> Insecure $ENV{PATH} while running setgid

  While running setgid? That's odd (although I don't think this
nterfers with your problem in any way)

> foreach my $release (`/bin/ls $path`) { # $path is already untainted
>  <do stuff>
> }

  TI (still) MTOWTDI: why not try

  use IO::Pipe;
  my $pipe = new IO::Pipe()->reader("/bin/ls",$path);

  while(<$pipe>) {
  }

  (although this will not save you from having to review all your codebase)

-- 
Dominique QUATRAVAUX                           Ingénieur senior
01 44 42 00 08                                 IDEALX



Re: untainting PATH in mod_perl

Posted by Peter Ensch <pe...@ti.com>.
On Thu, Jul 10, 2003 at 10:25:59AM +0200, Dominique Quatravaux wrote:
> > I need some help with this. Can you share the code you use w/in
> > your <Perl> section?
> 
>   Sure! Here is how I untaint a selected range of variables from the
> WWW server's %ENV, and discard all the others (good move to ease
> debugging anyway):
> 
>    # From httpd.conf
>    PerlTaintCheck On
>    
>    <perl>
>       BEGIN {
>            # Untaint environment. Those variables come from
>            # Apache; even if they didn't, they would come from the root
>            # user who launched Apache. No security problems here.
>    
>            my %cleanenv;
>            foreach my $var (qw(PATH GATEWAY_INTERFACE MOD_PERL)) {
>               ($cleanenv{$var})=($ENV{$var} =~ m/^(.*)$/g);
>            }
>            %ENV=%cleanenv;
>        }   
>    </perl>
> 
> > I'm pretty confused because I was able to untaint my PATH var.
> > by putting 
> > 
> > $ENV{PATH} = '/bin';
> > 
> > in the ***same scope*** where I was getting the error.
> 
>  Makes sense to me: if you are using Apache::Registry (for example),
> your script only gets compiled once and the BEGIN blocks run at that
> time. In fact Apache::Registry reads your cgi, then cooks it into
> something like this:
> 
> package Some::Name::Made::Up::By::Apache::Registry::To::Isolate::Your::cgi;
> 
> sub handler {
>   # Your script here
> }
> 
>   Then it evals that (by that time, the BEGIN blocks run), then calls
> Some::Name::...::handler(). The purpose of these steps is caching: the
> next time the CGI is hit, the evalling needs not be redone, only the
> handler call.
> 
>   Now, my guess was that %ENV gets reset between the eval and the
> handler call. As you mention, putting the untainter in the same scope
> solves the problem, because you now circumvent the cleaning. Putting
> it in the <perl> section should also solve the problem once for all,
> because the <perl> section runs before the default %ENV value is
> stashed (even before Apache forks, in fact).
> 

Dominique,

Thanks for sharing your code; unfortunately, it's not working for me.
I copied it into my httpd.conf file, stopped/started the server and
I still get the same error:

[Thu Jul 10 11:10:38 2003] [error] 19156: ModPerl::Registry: Error executing run mode 'getlib': \
Insecure $ENV{PATH} while running setgid at /opt/asic/http/2.0.46/worker/perl-lib/Webace/Art.pm line 386

where line #386 is:

foreach my $release (`/bin/ls $path`) { # $path is already untainted
 <do stuff>
}

Any other ideas?
Thanks and regards,
P

-- 

^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
Peter Ensch,
pensch@ti.com           A-1140   (214) 480 2333
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

Re: untainting PATH in mod_perl

Posted by Dominique Quatravaux <do...@idealx.com>.
> I need some help with this. Can you share the code you use w/in
> your <Perl> section?

  Sure! Here is how I untaint a selected range of variables from the
WWW server's %ENV, and discard all the others (good move to ease
debugging anyway):

   # From httpd.conf
   PerlTaintCheck On
   
   <perl>
      BEGIN {
           # Untaint environment. Those variables come from
           # Apache; even if they didn't, they would come from the root
           # user who launched Apache. No security problems here.
   
           my %cleanenv;
           foreach my $var (qw(PATH GATEWAY_INTERFACE MOD_PERL)) {
              ($cleanenv{$var})=($ENV{$var} =~ m/^(.*)$/g);
           }
           %ENV=%cleanenv;
       }   
   </perl>

> I'm pretty confused because I was able to untaint my PATH var.
> by putting 
> 
> $ENV{PATH} = '/bin';
> 
> in the ***same scope*** where I was getting the error.

 Makes sense to me: if you are using Apache::Registry (for example),
your script only gets compiled once and the BEGIN blocks run at that
time. In fact Apache::Registry reads your cgi, then cooks it into
something like this:

package Some::Name::Made::Up::By::Apache::Registry::To::Isolate::Your::cgi;

sub handler {
  # Your script here
}

  Then it evals that (by that time, the BEGIN blocks run), then calls
Some::Name::...::handler(). The purpose of these steps is caching: the
next time the CGI is hit, the evalling needs not be redone, only the
handler call.

  Now, my guess was that %ENV gets reset between the eval and the
handler call. As you mention, putting the untainter in the same scope
solves the problem, because you now circumvent the cleaning. Putting
it in the <perl> section should also solve the problem once for all,
because the <perl> section runs before the default %ENV value is
stashed (even before Apache forks, in fact).

-- 
Dominique QUATRAVAUX                           Ingénieur senior
01 44 42 00 08                                 IDEALX



Re: untainting PATH in mod_perl

Posted by "Peter B. Ensch" <pe...@comcast.net>.
On Wed, Jul 09, 2003 at 05:40:32PM +0200, Dominique Quatravaux wrote:
> > In plain CGI, I normally do this inside a BEGIN 
> > block; in mod_perl however, this doesn't work.
> 
> This would work if this was done in a <Perl> section of the httpd.conf
> file (this is what I do). I am not sure why the BEGIN block is not
> executed, but my guess is that the environment gets automatically
> restored at the end of every script run under Apache::Registry,
> including the tainted PATH.
> 

I need some help with this. Can you share the code you use w/in
your <Perl> section?

I'm pretty confused because I was able to untaint my PATH var.
by putting 

$ENV{PATH} = '/bin';

in the ***same scope*** where I was getting the error. For example

$ENV{PATH} = '/bin';
my @files = `/bin/ls $path`; # $path is already untainted

was OK; leave out the $ENV line and I get an Insecure $ENV{PATH}
error. 

This works (don't know why) but I would prefer to fix the PATH
in one place rather than having to do so everywhere I shell out
or use backticks.

Thanks,
P


-- 
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
Peter B. Ensch (peterbe@attbi.com)     
                                       
Linux 2.4.20-4GB 8:21pm Up 18 days 2:55
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

Re: untainting PATH in mod_perl

Posted by Dominique Quatravaux <do...@idealx.com>.
> In plain CGI, I normally do this inside a BEGIN 
> block; in mod_perl however, this doesn't work.

This would work if this was done in a <Perl> section of the httpd.conf
file (this is what I do). I am not sure why the BEGIN block is not
executed, but my guess is that the environment gets automatically
restored at the end of every script run under Apache::Registry,
including the tainted PATH.

-- 
Dominique QUATRAVAUX                           Ingénieur senior
01 44 42 00 08                                 IDEALX