Beat: -T Taintcheck OK auf Windows NOT OK auf UNIX

Kann mir jemand sagen, warum ein Script, das auf Windows alle Taint-Checks besteht, auf UNIX miserabel abbricht?

Möglicher Hintergrund: Unix unterscheidet sich dadurch, dass der Owner bei einigen Files verschieden ist vom Owner des ausführenden Scripts.
Ich wüsste aber nicht, dass diese eine Rolle spielt.

mfg Beat

--
><o(((°>           ><o(((°>
   <°)))o><                     ><o(((°>o
Der Valigator leibt diese Fische
  1. Moin Moin!

    Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.

    perlsec hast Du gelesen und verstanden?

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.

      Das ist ja meine alte Kritik an -T. Du bekommst einfach keinen Fehler. Allenfalls Folgefehler von nicht initialisierten Variablen.
      Statt dass ein Script sofort abbricht, läuft es Seelenruhig weiter und lässt dich in den Datengau laufen.

      perlsec hast Du gelesen und verstanden?

      ja jein

      mfg Beat

      --
      ><o(((°>           ><o(((°>
         <°)))o><                     ><o(((°>o
      Der Valigator leibt diese Fische
      1. Moin Moin!

        Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.

        Das ist ja meine alte Kritik an -T. Du bekommst einfach keinen Fehler.

        Dann machst Du was falsch. -T bricht Dein Script mit einer Fehlermeldung ab, wenn Du mit getainteten Werten eine der dokumentierten kritischen Funktionen aufrufst.

        Allenfalls Folgefehler von nicht initialisierten Variablen.

        Nein. Du machst etwas fürchterlich falsch. Hast Du einen eval-Block rund um den Teil des Codes, der die kritischen Funktionen aufruft? Dann sieh Dir mal $@ genauer an! Diese Funktionen erzeugen mit -T bei getainteten Exceptions, und die kannst Du mit eval abfangen. Exakt wie die(), nicht wie exit().

        Statt dass ein Script sofort abbricht, läuft es Seelenruhig weiter und lässt dich in den Datengau laufen.

        Nein. Getaintete Parameter für die kritischen Funktionen führen sofort zum Abbruch. Du sitzt vermutlich in einem eval-Block.

        Was erwartest Du denn, was Perl sonst machen sollte? $ENV{'PATH'} ist tainted. Soll das Script deswegen sofort abbrechen, obwohl $ENV{'PATH'} gar nicht genutzt wird? (Analog z.B. mit $0 und $^X.) Du mußt wenigstens die Chance haben, die Daten zu validieren oder durch saubere Werte zu ersetzen.

        perlsec hast Du gelesen und verstanden?

        ja jein

        Dann um so mehr: Zeig Code!

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.

          OK.
          Ich habe jetzt einen Fehlerreport
          Betrifft dies:

          open( my $LOG2, '>', $Files{logfile} ) or die("$!");  
          
          

          Es handelt sich um den einzigen Schreibzugriff.
          Ich kann nun zurückverfolgen, warum $Files{logfile} als tainted gilt.

          vorher

          ...  
          logfile => $Path{__datadir} . 'log.ehf',  
          ...
          

          vorher

          $Path{__datadir} = $Path{homedir} . '/' . '__data/';  
          $Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};  
          
          

          vorher

          $Path{scriptpath} =~ s#\\#/#g;  
          ( $Path{root}, $Path{cgi}, $Path{scriptname} ) =  
             ( $Path{scriptpath} =~ m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x );  
          
          

          vorher

          open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");  
          while(<$config>){  
          ...  
          /^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;  
          ...  
          }  
          close $config;  
          
          

          und zu vorderst

          my %Path = ( #defaults  
               ...  
              scriptpath => $0,  
          );  
            
          
          

          Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.
          Da ist kein Grund, dass diese Pfade tainted sein dürfen.

          Und wieder meine Frage: Warum auf UNIX und nicht auf Windows?

          mfg Beat

          1. Hi,

            Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.
            OK.
            Ich habe jetzt einen Fehlerreport

            Schön für Dich. Aber wenn Dir geholfen werden soll, wäre es nicht verkehrt, den auch herzuzeigen.

            cu,
            Andreas

            --
            Warum nennt sich Andreas hier MudGuard?
            O o ostern ...
            Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
          2. Moin Moin!

            Zeig Code. Wenigstens die Stelle, die Perl in der Fehlermeldung bemängelt. Und die Fehlermeldung natürlich auch.

            OK.
            Ich habe jetzt einen Fehlerreport
            Betrifft dies:

            open( my $LOG2, '>', $Files{logfile} ) or die("$!");

            
            >   
            > Es handelt sich um den einzigen Schreibzugriff.  
            
            Nö, an der Stelle machst Du ein open(), keinen Schreibzugriff.  
              
            Warum muß ich mir den Code rekonstruieren?  
              
            Und warum gibst Du nicht alle relevanten Variablen an?  
              
            Woher kommt $Path{'homedir'}? Wenn ich mir das aus $ENV{'HOME'} hole, ist $Files{'logfile'} tainted. Und zwar nur unter Unix, weil Windows $ENV{'HOME'} nicht setzt.  
              
            
            > Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.  
              
            Nö, Du kannst SO nicht waschen. $0 bleibt tainted, bis Du es ÜBERSCHREIBST, und wenn Du noch so oft matcht. Nur die RE-Puffer ($1, $2, ...) sind vom Tainting explizit ausgenommen.  
              
            
            > Da ist kein Grund, dass diese Pfade tainted sein dürfen.  
            >   
            > Und wieder meine Frage: Warum auf UNIX und nicht auf Windows?  
              
            S.o.  
              
            Das ist meine Rekonstruktion Deines Codes, zusammen mit expliziten Taint-Ausgaben. Und die sagt, dass $Files{'logfile'} am Ende tainted ist. Demzufolge verweigert open() die Arbeit und wirft stattdessen eine Exception.  
              
            ~~~perl
              
            #!/usr/bin/perl -T  
              
            use strict;  
            use warnings;  
              
            use Data::Dumper qw();  
            use Scalar::Util qw(tainted);  
              
            sub T  
            {  
            	my ($name,$val)=@_;  
            	my $line=(caller())[2];  
            	print "$name is ",tainted($val) ? "" : "not ","tainted in lline $line (value=".Data::Dumper::qquote($val).")\n";  
            }  
              
              
            my %Path=( #defaults  
            #	...  
            	scriptpath => $0,  
            	homedir => $ENV{'HOME'},  
            );  
              
            T(scriptpath => $Path{'scriptpath'});  
              
            open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");  
            while(<$config>){  
            	T('$_' => $_);  
            	/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath}=$1 and next;  
            }  
            close $config;  
              
            T(scriptpath => $Path{'scriptpath'});  
              
            $Path{scriptpath} =~ s#\\#/#g;  
              
            T(scriptpath => $Path{'scriptpath'});  
              
            ($Path{root},$Path{cgi},$Path{scriptname})=($Path{scriptpath}=~m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x);  
              
            T(scriptpath => $Path{'scriptpath'});  
            T(scriptname => $Path{'scriptname'});  
            T(root => $Path{'root'});  
            T(cgi => $Path{'cgi'});  
              
            $Path{__datadir} = $Path{homedir} . '/' . '__data/';  
              
            T(__datadir => $Path{'__datadir'});  
              
            $Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};  
              
            T(homedir => $Path{'homedir'});  
              
            my %Files;  
            $Files{'logfile'}=$Path{__datadir} . 'log.ehf';  
              
            T(logfile => $Files{'logfile'});  
              
            open( my $LOG2, '>', $Files{logfile} ) or die("$!");  
            
            

            Möchtest Du das Log übrigens wirklich jedes Mal plätten?

            Alexander

            --
            Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
            1. Moin Moin!

              Das ist meine Rekonstruktion Deines Codes, zusammen mit expliziten Taint-Ausgaben. Und die sagt, dass $Files{'logfile'} am Ende tainted ist. Demzufolge verweigert open() die Arbeit und wirft stattdessen eine Exception.

              So sieht das aus:

              /home/XXX/beat>perl -T beat.pl
              scriptpath is tainted in lline 23 (value="beat.pl")
              $_ is tainted in lline 27 (value="# config.ehf\n")
              $_ is tainted in lline 27 (value="scriptdir=/home/XXX/beat\n")
              scriptpath is tainted in lline 32 (value="beat.pl")
              scriptpath is tainted in lline 36 (value="beat.pl")
              Use of uninitialized value $Path{"cgidir"} in regexp compilation at beat.pl line 38.
              scriptpath is tainted in lline 40 (value="beat.pl")
              scriptname is not tainted in lline 41 (value="")
              root is not tainted in lline 42 (value="")
              cgi is not tainted in lline 43 (value="")
              __datadir is tainted in lline 47 (value="/home/XXX/__data/")
              Use of uninitialized value $Path{"root"} in concatenation (.) or string at beat.pl line 49.
              Use of uninitialized value in concatenation (.) or string at beat.pl line 49.
              Use of uninitialized value in concatenation (.) or string at beat.pl line 49.
              homedir is not tainted in lline 51 (value="/")
              logfile is tainted in lline 56 (value="/home/XXX/__data/log.ehf")
              Insecure dependency in open while running with -T switch at beat.pl line 58.

              Alexander

              --
              Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
              1. OK
                Ich habe jetzt mal einen wilden patch vorgenommen.

                Ich habe $0 ais einer Regex gezogen.
                Allerdings muss ich dabei so liberal vorgehen, dass Sicherheit nur besteht, wenn der Anwender den Scriptpfad im configfile vorgibt.

                Hier der Beginn des Scripts

                  
                #!/usr/bin/perl -T  
                  
                	BEGIN {  
                		use CGI::Carp qw(carpout);  
                		open(LOG, ">>","error.txt")  or die "Unable to append to error.txt: $!\n";  
                		carpout(*LOG);  
                $1.'/EHFPlugins';  
                	}  
                	use warnings;  
                	use strict;  
                	use lib qw(.);  
                	use Digest::SHA1 qw( sha1_hex );  
                	use constant { NL => "\n", CRLF => "\015\012"};  
                	use Storable qw(lock_store lock_retrieve);  
                	use Tie::File;  
                	use Encode qw(encode);  
                	use URI::Escape;  
                	use EHFLang;	# Sprachpaket für ehf-Formulare.  
                	my $L = new EHFLang();	# Die Sprache wird nach dem ersten Aufruf von $Store gesetzt  
                					# importiert die Funktion t()  translate  
                  
                # 1.b System Angaben aus config.ehf  
                	my %System = (  
                			runonce=>0,  
                			debug=>0,		# Bitmaske: 1 debug; 2 input; 4 cookies; 8 user; 16 files  
                			updatesite=>0,  
                			version=>"0.9.6.pre"  
                	);  
                  
                	my %Path = (  
                		domain => 'localhost',  
                		protokoll=>'http',  
                		htmldir => 'html',  
                		cgidir => 'cgi',  
                		ehfdatadir => 'ehf_html',  
                		scriptpath=>'',  
                	);  
                	$0 =~ /^(.*)$/ and ($Path{scriptpath}) = $1;  
                	my $ruopen=0;  
                	open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");  
                	while(<$config>){  
                		/^#/ and next;  
                		/^domain\s*=\s*([a-zA-Z0-9_.-:]+)\s*$/ and $Path{domain} = $1 and next;  
                		/^protokoll\s*=\s*(https?)\s*$/ and $Path{protokoll} = $1 and next;  
                		/^htmldir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{htmldir} = $1 and next;  
                		/^cgidir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{cgidir} = $1 and next;  
                		/^ehfdatadir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{ehfdatadir} = $1 and next;  
                		/^ehfupdatefrom\s*=\s*(\S+)\s*$/ and $System{updatesite} = $1 and next;  
                		/^ehfdebug\s*=\s*([0-9]+)\s*$/ and $System{debug} = $1 and next;  
                		/^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;  
                		/^runonce=([1-9])/ and $ruopen = 1;  
                	}  
                	close $config;  
                	# Installations-Zugriff.  
                	if($ruopen){  
                		tie( my @cf , 'Tie::File', 'config.ehf') or die ("Kein Schreibrecht auf config.ehf $!");  
                		foreach(@cf){  
                			if( /^runonce=([1-9])/ ){  
                				$System{runonce} = $1;  
                				$1 gt 3  
                					? ( $_ = 'runonce=0' )  
                					: ( $_ = 'runonce=' . ( $1 + 1 ) );  
                			}  
                		}  
                		untie( @cf );  
                	}  
                  
                  
                # 1.c Directory Angaben  
                	$Path{scriptpath} =~ s#\\#/#g;  
                	( $Path{root}, $Path{cgi}, $Path{scriptname} ) =  
                		( $Path{scriptpath} =~ m!^ (.*?/) ($Path{cgidir}/\w+/) ([a-z]+\.pl)$!x );  
                	# Der Pfad zum Homedirectory  
                	$Path{homedir} = $Path{root} . $Path{htmldir} .'/'. $Path{ehfdatadir};  
                	# Der Pfad zum CGI Verzeichnis  
                	$Path{cgidir} = $Path{root} . $Path{cgi};  
                  
                # 1.d URL Angaben  
                	# Das Schema, Domain  
                	$Path{domurl} = $Path{protokoll} . '://' . $Path{domain};  
                	# Die lokale URL zum HTML Verzeichnis, wo die Daten liegen  
                	$Path{home} = $Path{domurl} .'/'. $Path{ehfdatadir};  
                	# Die lokale URL zum CGI Verzeichnis, wo die Script und Module liegen  
                	$Path{cgiurl} = $Path{domurl} . '/'. $Path{cgi};  
                	$Path{scripturl} = $Path{cgiurl} . $Path{scriptname};  
                  
                # 1.e Ergänzung  
                	$Path{__datadir} = $Path{homedir} . '/' . '__data/';  
                	$Path{__layoutdir} = $Path{homedir} . '/' . '__layouts/';  
                	$Path{__themedir} = $Path{homedir} . '/' . '__themes/';  
                	$Path{__backupdir} = $Path{homedir} . '/' . '__backups/';  
                	$Path{__static} = $Path{homedir} . '/' . '__static/';  
                	$Path{userdata} = $Path{homedir} . '/' . 'userdata/';  
                
                

                Das Script läuft jetzt auch auf dem UNIX mit -T.
                Allerdings muss ich noch aller Routinen testen.

            2. Warum muß ich mir den Code rekonstruieren?

              Warum solltest du dir in 5000 Zeilen Code irgend eine raussuchen?
              Wenn du der Message nicht vertraust, welche Argumente hast du dann?

              Und warum gibst Du nicht alle relevanten Variablen an?

              Wie meinen?

              Woher kommt $Path{'homedir'}? Wenn ich mir das aus $ENV{'HOME'} hole, ist $Files{'logfile'} tainted. Und zwar nur unter Unix, weil Windows $ENV{'HOME'} nicht setzt.

              Ach Schneusel. Es kommt aus einem File, alles via Regex weissgewaschen.

              	open( my $config, '<','config.ehf' ) or die ("Kann nicht config.ehf lesen $!");  
              while(<$config>){  
                  /^#/ and next;  
                  /^domain\s*=\s*([a-zA-Z0-9_.-:]+)\s*$/ and $Path{domain} = $1 and next;  
                  /^protokoll\s*=\s*(https?)\s*$/ and $Path{protokoll} = $1 and next;  
                  /^htmldir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{htmldir} = $1 and next;  
                  /^cgidir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{cgidir} = $1 and next;  
                  /^ehfdatadir\s*=\s*([A-Za-z0-9_.\/-]+)\s*$/ and $Path{ehfdatadir} = $1 and next;  
                  /^ehfupdatefrom\s*=\s*(\S+)\s*$/ and $System{updatesite} = $1 and next;  
                  /^ehfdebug\s*=\s*([0-9]+)\s*$/ and $System{debug} = $1 and next;  
                  /^scriptpath\s*=\s*"([^"]+)"/ and $Path{scriptpath} = $1 and next;  
                  /^runonce=([1-9])/ and $ruopen = 1;  
              }  
              close $config;  
              
              

              Hier werden alle Bestandteile, aus welchen Pfade hergeleitet werden, konsequent gewaschen.

              Wie zu sehen wird zwar $0 verwendet, aber $0 wird auf jeden Fall über eine RE gewaschen.

              Nö, Du kannst SO nicht waschen. $0 bleibt tainted, bis Du es ÜBERSCHREIBST, und wenn Du noch so oft matcht. Nur die RE-Puffer ($1, $2, ...) sind vom Tainting explizit ausgenommen.

              Sag ich ja, Angaben aus $0 werden via Regex herausgezogen, falls die Variable, die $0 speichert, nicht über das config file überschrieben wird

              open( my $LOG2, '>', $Files{logfile} ) or die("$!");
              [/code]

              Möchtest Du das Log übrigens wirklich jedes Mal plätten?

              Aber sicher!

              Ich habe im Moment noch eine andere Baustelle,
              da die UNIX Perl Version (5.8.0) anscheinend Mühe mit
                print $fh somefunc()
              hat.
              Ganz seltsames Verhalten und nicht durchgängig der Fall.

              mfg Beat

              --
              ><o(((°>           ><o(((°>
                 <°)))o><                     ><o(((°>o
              Der Valigator leibt diese Fische