📄 taint.t
字号:
#!./perl -T## Taint tests by Tom Phoenix <rootbeer@teleport.com>.## I don't claim to know all about tainting. If anyone sees# tests that I've missed here, please add them. But this is# better than having no tests at all, right?#BEGIN { chdir 't' if -d 't'; @INC = '../lib';}use strict;use Config;# We do not want the whole taint.t to fail# just because Errno possibly failing.eval { require Errno; import Errno };use vars qw($ipcsysv); # did we manage to load IPC::SysV?BEGIN { if ($^O eq 'VMS' && !defined($Config{d_setenv})) { $ENV{PATH} = $ENV{PATH}; $ENV{TERM} = $ENV{TERM} ne ''? $ENV{TERM} : 'dummy'; } if ($Config{'extensions'} =~ /\bIPC\/SysV\b/ && ($Config{d_shm} || $Config{d_msg})) { eval { require IPC::SysV }; unless ($@) { $ipcsysv++; IPC::SysV->import(qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU)); } }}my $Is_VMS = $^O eq 'VMS';my $Is_MSWin32 = $^O eq 'MSWin32';my $Is_Dos = $^O eq 'dos';my $Invoke_Perl = $Is_VMS ? 'MCR Sys$Disk:[]Perl.' : $Is_MSWin32 ? '.\perl' : './perl';my @MoreEnv = qw/IFS CDPATH ENV BASH_ENV/;if ($Is_VMS) { my (%old, $x); for $x ('DCL$PATH', @MoreEnv) { ($old{$x}) = $ENV{$x} =~ /^(.*)$/ if exists $ENV{$x}; } eval <<EndOfCleanup; END { \$ENV{PATH} = '' if $Config{d_setenv}; warn "# Note: logical name 'PATH' may have been deleted\n"; \@ENV{keys %old} = values %old; }EndOfCleanup}# Sources of taint:# The empty tainted value, for tainting stringsmy $TAINT = substr($^X, 0, 0);# A tainted zero, useful for tainting numbersmy $TAINT0 = 0 + $TAINT;# This taints each argument passed. All must be lvalues.# Side effect: It also stringifies them. :-(sub taint_these (@) { for (@_) { $_ .= $TAINT }}# How to identify taint when you see itsub any_tainted (@) { not eval { join("",@_), kill 0; 1 };}sub tainted ($) { any_tainted @_;}sub all_tainted (@) { for (@_) { return 0 unless tainted $_ } 1;}sub test ($$;$) { my($serial, $boolean, $diag) = @_; if ($boolean) { print "ok $serial\n"; } else { print "not ok $serial\n"; for (split m/^/m, $diag) { print "# $_"; } print "\n" unless $diag eq '' or substr($diag, -1) eq "\n"; }}# We need an external program to call.my $ECHO = ($Is_MSWin32 ? ".\\echo$$" : "./echo$$");END { unlink $ECHO }open PROG, "> $ECHO" or die "Can't create $ECHO: $!";print PROG 'print "@ARGV\n"', "\n";close PROG;my $echo = "$Invoke_Perl $ECHO";print "1..155\n";# First, let's make sure that Perl is checking the dangerous# environment variables. Maybe they aren't set yet, so we'll# taint them ourselves.{ $ENV{'DCL$PATH'} = '' if $Is_VMS; $ENV{PATH} = ''; delete @ENV{@MoreEnv}; $ENV{TERM} = 'dumb'; test 1, eval { `$echo 1` } eq "1\n"; if ($Is_MSWin32 || $Is_VMS || $Is_Dos) { print "# Environment tainting tests skipped\n"; for (2..5) { print "ok $_\n" } } else { my @vars = ('PATH', @MoreEnv); while (my $v = $vars[0]) { local $ENV{$v} = $TAINT; last if eval { `$echo 1` }; last unless $@ =~ /^Insecure \$ENV{$v}/; shift @vars; } test 2, !@vars, "\$$vars[0]"; # tainted $TERM is unsafe only if it contains metachars local $ENV{TERM}; $ENV{TERM} = 'e=mc2'; test 3, eval { `$echo 1` } eq "1\n"; $ENV{TERM} = 'e=mc2' . $TAINT; test 4, eval { `$echo 1` } eq ''; test 5, $@ =~ /^Insecure \$ENV{TERM}/, $@; } my $tmp; if ($^O eq 'os2' || $^O eq 'amigaos' || $Is_MSWin32 || $Is_Dos) { print "# all directories are writeable\n"; } else { $tmp = (grep { defined and -d and (stat _)[2] & 2 } qw(sys$scratch /tmp /var/tmp /usr/tmp), @ENV{qw(TMP TEMP)})[0] or print "# can't find world-writeable directory to test PATH\n"; } if ($tmp) { local $ENV{PATH} = $tmp; test 6, eval { `$echo 1` } eq ''; test 7, $@ =~ /^Insecure directory in \$ENV{PATH}/, $@; } else { for (6..7) { print "ok $_ # Skipped: all directories are writeable\n" } } if ($Is_VMS) { $ENV{'DCL$PATH'} = $TAINT; test 8, eval { `$echo 1` } eq ''; test 9, $@ =~ /^Insecure \$ENV{DCL\$PATH}/, $@; if ($tmp) { $ENV{'DCL$PATH'} = $tmp; test 10, eval { `$echo 1` } eq ''; test 11, $@ =~ /^Insecure directory in \$ENV{DCL\$PATH}/, $@; } else { for (10..11) { print "ok $_ # Skipped: can't find world-writeable directory to test DCL\$PATH\n" } } $ENV{'DCL$PATH'} = ''; } else { for (8..11) { print "ok $_ # Skipped: This is not VMS\n"; } }}# Let's see that we can taint and untaint as needed.{ my $foo = $TAINT; test 12, tainted $foo; # That was a sanity check. If it failed, stop the insanity! die "Taint checks don't seem to be enabled" unless tainted $foo; $foo = "foo"; test 13, not tainted $foo; taint_these($foo); test 14, tainted $foo; my @list = 1..10; test 15, not any_tainted @list; taint_these @list[1,3,5,7,9]; test 16, any_tainted @list; test 17, all_tainted @list[1,3,5,7,9]; test 18, not any_tainted @list[0,2,4,6,8]; ($foo) = $foo =~ /(.+)/; test 19, not tainted $foo; $foo = $1 if ('bar' . $TAINT) =~ /(.+)/; test 20, not tainted $foo; test 21, $foo eq 'bar'; { use re 'taint'; ($foo) = ('bar' . $TAINT) =~ /(.+)/; test 22, tainted $foo; test 23, $foo eq 'bar'; $foo = $1 if ('bar' . $TAINT) =~ /(.+)/; test 24, tainted $foo; test 25, $foo eq 'bar'; } $foo = $1 if 'bar' =~ /(.+)$TAINT/; test 26, tainted $foo; test 27, $foo eq 'bar'; my $pi = 4 * atan2(1,1) + $TAINT0; test 28, tainted $pi; ($pi) = $pi =~ /(\d+\.\d+)/; test 29, not tainted $pi; test 30, sprintf("%.5f", $pi) eq '3.14159';}# How about command-line arguments? The problem is that we don't# always get some, so we'll run another process with some.{ my $arg = "./arg$$"; open PROG, "> $arg" or die "Can't create $arg: $!"; print PROG q{ eval { join('', @ARGV), kill 0 }; exit 0 if $@ =~ /^Insecure dependency/; print "# Oops: \$@ was [$@]\n"; exit 1; }; close PROG; print `$Invoke_Perl "-T" $arg and some suspect arguments`; test 31, !$?, "Exited with status $?"; unlink $arg;}# Reading from a file should be tainted{ my $file = './TEST'; test 32, open(FILE, $file), "Couldn't open '$file': $!"; my $block; sysread(FILE, $block, 100); my $line = <FILE>; close FILE; test 33, tainted $block; test 34, tainted $line;}# Globs should be forbidden, except under VMS,# which doesn't spawn an external program.if (1 # built-in glob or $Is_VMS) { for (35..36) { print "ok $_\n"; }}else { my @globs = eval { <*> }; test 35, @globs == 0 && $@ =~ /^Insecure dependency/; @globs = eval { glob '*' }; test 36, @globs == 0 && $@ =~ /^Insecure dependency/;}# Output of commands should be tainted{ my $foo = `$echo abc`; test 37, tainted $foo;}# Certain system variables should be tainted{ test 38, all_tainted $^X, $0;}# Results of matching should all be untainted{ my $foo = "abcdefghi" . $TAINT; test 39, tainted $foo; $foo =~ /def/; test 40, not any_tainted $`, $&, $'; $foo =~ /(...)(...)(...)/; test 41, not any_tainted $1, $2, $3, $+; my @bar = $foo =~ /(...)(...)(...)/; test 42, not any_tainted @bar; test 43, tainted $foo; # $foo should still be tainted! test 44, $foo eq "abcdefghi";}# Operations which affect files can't use tainted data.{ test 45, eval { chmod 0, $TAINT } eq '', 'chmod'; test 46, $@ =~ /^Insecure dependency/, $@; # There is no feature test in $Config{} for truncate, # so we allow for the possibility that it's missing. test 47, eval { truncate 'NoSuChFiLe', $TAINT0 } eq '', 'truncate'; test 48, $@ =~ /^(?:Insecure dependency|truncate not implemented)/, $@; test 49, eval { rename '', $TAINT } eq '', 'rename'; test 50, $@ =~ /^Insecure dependency/, $@; test 51, eval { unlink $TAINT } eq '', 'unlink'; test 52, $@ =~ /^Insecure dependency/, $@; test 53, eval { utime $TAINT } eq '', 'utime'; test 54, $@ =~ /^Insecure dependency/, $@; if ($Config{d_chown}) { test 55, eval { chown -1, -1, $TAINT } eq '', 'chown'; test 56, $@ =~ /^Insecure dependency/, $@; } else { for (55..56) { print "ok $_ # Skipped: chown() is not available\n" } } if ($Config{d_link}) { test 57, eval { link $TAINT, '' } eq '', 'link'; test 58, $@ =~ /^Insecure dependency/, $@; } else { for (57..58) { print "ok $_ # Skipped: link() is not available\n" } } if ($Config{d_symlink}) { test 59, eval { symlink $TAINT, '' } eq '', 'symlink'; test 60, $@ =~ /^Insecure dependency/, $@; } else { for (59..60) { print "ok $_ # Skipped: symlink() is not available\n" } }}# Operations which affect directories can't use tainted data.{ test 61, eval { mkdir $TAINT0, $TAINT } eq '', 'mkdir'; test 62, $@ =~ /^Insecure dependency/, $@; test 63, eval { rmdir $TAINT } eq '', 'rmdir'; test 64, $@ =~ /^Insecure dependency/, $@; test 65, eval { chdir $TAINT } eq '', 'chdir'; test 66, $@ =~ /^Insecure dependency/, $@; if ($Config{d_chroot}) { test 67, eval { chroot $TAINT } eq '', 'chroot'; test 68, $@ =~ /^Insecure dependency/, $@; } else { for (67..68) { print "ok $_ # Skipped: chroot() is not available\n" }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -