Fix AUTOLOAD, or kill me
[p5sagit/p5-mst-13.2.git] / t / op / taint.t
CommitLineData
1e422769 1#!./perl -T
2#
3# Taint tests by Tom Phoenix <rootbeer@teleport.com>.
4#
5# I don't claim to know all about tainting. If anyone sees
9607fc9c 6# tests that I've missed here, please add them. But this is
1e422769 7# better than having no tests at all, right?
8#
9
10BEGIN {
11 chdir 't' if -d 't';
12 @INC = '../lib' if -d '../lib';
13}
14
15use strict;
16use Config;
17
18my $Is_VMS = $^O eq 'VMS';
68dc0745 19my $Is_MSWin32 = $^O eq 'MSWin32';
20my $Invoke_Perl = $Is_VMS ? 'MCR Sys$Disk:[]Perl.' :
21 $Is_MSWin32 ? '.\perl' : './perl';
1e422769 22if ($Is_VMS) {
68dc0745 23 my ($olddcl) = $ENV{'DCL$PATH'} =~ /^(.*)$/;
24 my ($oldifs) = $ENV{IFS} =~ /^(.*)$/;
1e422769 25 eval <<EndOfCleanup;
26 END {
27 \$ENV{PATH} = '';
28 warn "# Note: logical name 'PATH' may have been deleted\n";
68dc0745 29 \$ENV{IFS} = \$oldifs;
30 \$ENV{'DCL\$PATH'} = \$olddcl;
1e422769 31 }
32EndOfCleanup
33}
34
35# Sources of taint:
36# The empty tainted value, for tainting strings
37my $TAINT = substr($^X, 0, 0);
38# A tainted zero, useful for tainting numbers
39my $TAINT0 = 0 + $TAINT;
40
41# This taints each argument passed. All must be lvalues.
42# Side effect: It also stringifies them. :-(
43sub taint_these (@) {
44 for (@_) { $_ .= $TAINT }
45}
46
47# How to identify taint when you see it
48sub any_tainted (@) {
49 not eval { join("",@_), kill 0; 1 };
50}
51sub tainted ($) {
52 any_tainted @_;
53}
54sub all_tainted (@) {
55 for (@_) { return 0 unless tainted $_ }
56 1;
57}
58
59sub test ($$;$) {
60 my($serial, $boolean, $diag) = @_;
61 if ($boolean) {
62 print "ok $serial\n";
63 } else {
64 print "not ok $serial\n";
65 for (split m/^/m, $diag) {
66 print "# $_";
67 }
9607fc9c 68 print "\n" unless
1e422769 69 $diag eq ''
70 or substr($diag, -1) eq "\n";
71 }
72}
73
74# We need an external program to call.
75my $ECHO = "./echo$$";
76END { unlink $ECHO }
77open PROG, "> $ECHO" or die "Can't create $ECHO: $!";
78print PROG 'print "@ARGV\n"', "\n";
79close PROG;
80my $echo = "$Invoke_Perl $ECHO";
81
54310121 82print "1..112\n";
1e422769 83
84# First, let's make sure that Perl is checking the dangerous
85# environment variables. Maybe they aren't set yet, so we'll
86# taint them ourselves.
87{
88 $ENV{'DCL$PATH'} = '' if $Is_VMS;
89
90 $ENV{PATH} = $TAINT;
9607fc9c 91 $ENV{IFS} = " \t\n";
1e422769 92 test 1, eval { `$echo 1` } eq '';
93 test 2, $@ =~ /^Insecure \$ENV{PATH}/, $@;
94
95 $ENV{PATH} = '';
96 $ENV{IFS} = $TAINT;
97 test 3, eval { `$echo 1` } eq '';
98 test 4, $@ =~ /^Insecure \$ENV{IFS}/, $@;
99
9607fc9c 100 my $tmp;
101 if ($^O eq 'os2' || $^O eq 'amigaos') {
102 print "# all directories are writeable\n";
103 }
104 else {
105 $tmp = (grep { defined and -d and (stat _)[2] & 2 }
106 qw(/tmp /var/tmp /usr/tmp /sys$scratch),
107 @ENV{qw(TMP TEMP)})[0]
108 or print "# can't find world-writeable directory to test PATH\n";
109 }
110
385588b3 111 if ($tmp) {
1e422769 112 $ENV{PATH} = $tmp;
9607fc9c 113 $ENV{IFS} = " \t\n";
1e422769 114 test 5, eval { `$echo 1` } eq '';
115 test 6, $@ =~ /^Insecure directory in \$ENV{PATH}/, $@;
116 }
117 else {
1e422769 118 for (5..6) { print "ok $_\n" }
119 }
120
121 $ENV{PATH} = '';
9607fc9c 122 $ENV{IFS} = " \t\n";
1e422769 123 test 7, eval { `$echo 1` } eq "1\n";
124 test 8, $@ eq '', $@;
125
126 if ($Is_VMS) {
127 $ENV{'DCL$PATH'} = $TAINT;
128 test 9, eval { `$echo 1` } eq '';
129 test 10, $@ =~ /^Insecure \$ENV{DCL\$PATH}/, $@;
9607fc9c 130 if ($tmp) {
131 $ENV{'DCL$PATH'} = $tmp;
132 test 11, eval { `$echo 1` } eq '';
133 test 12, $@ =~ /^Insecure directory in \$ENV{DCL\$PATH}/, $@;
134 }
135 else {
136 print "# can't find world-writeable directory to test DCL\$PATH\n";
137 for (11..12) { print "ok $_\n" }
138 }
1e422769 139 $ENV{'DCL$PATH'} = '';
140 }
141 else {
142 print "# This is not VMS\n";
9607fc9c 143 for (9..12) { print "ok $_\n"; }
1e422769 144 }
145}
146
147# Let's see that we can taint and untaint as needed.
148{
149 my $foo = $TAINT;
9607fc9c 150 test 13, tainted $foo;
151
152 # That was a sanity check. If it failed, stop the insanity!
153 die "Taint checks don't seem to be enabled" unless tainted $foo;
1e422769 154
155 $foo = "foo";
9607fc9c 156 test 14, not tainted $foo;
1e422769 157
158 taint_these($foo);
9607fc9c 159 test 15, tainted $foo;
1e422769 160
161 my @list = 1..10;
9607fc9c 162 test 16, not any_tainted @list;
1e422769 163 taint_these @list[1,3,5,7,9];
9607fc9c 164 test 17, any_tainted @list;
165 test 18, all_tainted @list[1,3,5,7,9];
166 test 19, not any_tainted @list[0,2,4,6,8];
1e422769 167
168 ($foo) = $foo =~ /(.+)/;
9607fc9c 169 test 20, not tainted $foo;
1e422769 170
171 $foo = $1 if ('bar' . $TAINT) =~ /(.+)/;
9607fc9c 172 test 21, not tainted $foo;
173 test 22, $foo eq 'bar';
1e422769 174
175 my $pi = 4 * atan2(1,1) + $TAINT0;
9607fc9c 176 test 23, tainted $pi;
1e422769 177
178 ($pi) = $pi =~ /(\d+\.\d+)/;
9607fc9c 179 test 24, not tainted $pi;
180 test 25, sprintf("%.5f", $pi) eq '3.14159';
1e422769 181}
182
183# How about command-line arguments? The problem is that we don't
184# always get some, so we'll run another process with some.
185{
186 my $arg = "./arg$$";
187 open PROG, "> $arg" or die "Can't create $arg: $!";
188 print PROG q{
189 eval { join('', @ARGV), kill 0 };
190 exit 0 if $@ =~ /^Insecure dependency/;
191 print "# Oops: \$@ was [$@]\n";
192 exit 1;
193 };
194 close PROG;
195 print `$Invoke_Perl "-T" $arg and some suspect arguments`;
9607fc9c 196 test 26, !$?, "Exited with status $?";
1e422769 197 unlink $arg;
198}
199
200# Reading from a file should be tainted
201{
9607fc9c 202 my $file = './TEST';
203 test 27, open(FILE, $file), "Couldn't open '$file': $!";
1e422769 204
205 my $block;
206 sysread(FILE, $block, 100);
9607fc9c 207 my $line = <FILE>;
1e422769 208 close FILE;
9607fc9c 209 test 28, tainted $block;
210 test 29, tainted $line;
1e422769 211}
212
9607fc9c 213# Globs should be tainted.
1e422769 214{
9607fc9c 215 # Some glob implementations need to spawn system programs.
216 local $ENV{PATH} = '';
217 $ENV{PATH} = (-l '/bin' ? '' : '/bin:') . '/usr/bin' unless $Is_VMS;
218
1e422769 219 my @globs = <*>;
9607fc9c 220 test 30, all_tainted @globs;
1e422769 221
222 @globs = glob '*';
9607fc9c 223 test 31, all_tainted @globs;
1e422769 224}
225
226# Output of commands should be tainted
227{
228 my $foo = `$echo abc`;
9607fc9c 229 test 32, tainted $foo;
1e422769 230}
231
232# Certain system variables should be tainted
233{
9607fc9c 234 test 33, all_tainted $^X, $0;
1e422769 235}
236
237# Results of matching should all be untainted
238{
239 my $foo = "abcdefghi" . $TAINT;
9607fc9c 240 test 34, tainted $foo;
1e422769 241
242 $foo =~ /def/;
9607fc9c 243 test 35, not any_tainted $`, $&, $';
1e422769 244
245 $foo =~ /(...)(...)(...)/;
9607fc9c 246 test 36, not any_tainted $1, $2, $3, $+;
1e422769 247
248 my @bar = $foo =~ /(...)(...)(...)/;
9607fc9c 249 test 37, not any_tainted @bar;
1e422769 250
9607fc9c 251 test 38, tainted $foo; # $foo should still be tainted!
252 test 39, $foo eq "abcdefghi";
1e422769 253}
254
255# Operations which affect files can't use tainted data.
256{
9607fc9c 257 test 40, eval { chmod 0, $TAINT } eq '', 'chmod';
1e422769 258 test 41, $@ =~ /^Insecure dependency/, $@;
259
9607fc9c 260 # There is no feature test in $Config{} for truncate,
261 # so we allow for the possibility that it's missing.
262 test 42, eval { truncate 'NoSuChFiLe', $TAINT0 } eq '', 'truncate';
263 test 43, $@ =~ /^(?:Insecure dependency|truncate not implemented)/, $@;
1e422769 264
9607fc9c 265 test 44, eval { rename '', $TAINT } eq '', 'rename';
1e422769 266 test 45, $@ =~ /^Insecure dependency/, $@;
267
9607fc9c 268 test 46, eval { unlink $TAINT } eq '', 'unlink';
1e422769 269 test 47, $@ =~ /^Insecure dependency/, $@;
270
9607fc9c 271 test 48, eval { utime $TAINT } eq '', 'utime';
272 test 49, $@ =~ /^Insecure dependency/, $@;
273
1e422769 274 if ($Config{d_chown}) {
9607fc9c 275 test 50, eval { chown -1, -1, $TAINT } eq '', 'chown';
276 test 51, $@ =~ /^Insecure dependency/, $@;
1e422769 277 }
278 else {
279 print "# chown() is not available\n";
9607fc9c 280 for (50..51) { print "ok $_\n" }
1e422769 281 }
282
283 if ($Config{d_link}) {
9607fc9c 284 test 52, eval { link $TAINT, '' } eq '', 'link';
285 test 53, $@ =~ /^Insecure dependency/, $@;
1e422769 286 }
287 else {
288 print "# link() is not available\n";
9607fc9c 289 for (52..53) { print "ok $_\n" }
1e422769 290 }
291
292 if ($Config{d_symlink}) {
9607fc9c 293 test 54, eval { symlink $TAINT, '' } eq '', 'symlink';
294 test 55, $@ =~ /^Insecure dependency/, $@;
1e422769 295 }
296 else {
297 print "# symlink() is not available\n";
9607fc9c 298 for (54..55) { print "ok $_\n" }
1e422769 299 }
300}
301
302# Operations which affect directories can't use tainted data.
303{
9607fc9c 304 test 56, eval { mkdir $TAINT0, $TAINT } eq '', 'mkdir';
1e422769 305 test 57, $@ =~ /^Insecure dependency/, $@;
306
9607fc9c 307 test 58, eval { rmdir $TAINT } eq '', 'rmdir';
1e422769 308 test 59, $@ =~ /^Insecure dependency/, $@;
309
9607fc9c 310 test 60, eval { chdir $TAINT } eq '', 'chdir';
311 test 61, $@ =~ /^Insecure dependency/, $@;
312
1e422769 313 if ($Config{d_chroot}) {
9607fc9c 314 test 62, eval { chroot $TAINT } eq '', 'chroot';
315 test 63, $@ =~ /^Insecure dependency/, $@;
1e422769 316 }
317 else {
318 print "# chroot() is not available\n";
9607fc9c 319 for (62..63) { print "ok $_\n" }
1e422769 320 }
321}
322
323# Some operations using files can't use tainted data.
324{
325 my $foo = "imaginary library" . $TAINT;
9607fc9c 326 test 64, eval { require $foo } eq '', 'require';
327 test 65, $@ =~ /^Insecure dependency/, $@;
1e422769 328
329 my $filename = "./taintB$$"; # NB: $filename isn't tainted!
330 END { unlink $filename if defined $filename }
331 $foo = $filename . $TAINT;
332 unlink $filename; # in any case
333
9607fc9c 334 test 66, eval { open FOO, $foo } eq '', 'open for read';
335 test 67, $@ eq '', $@; # NB: This should be allowed
336 test 68, $! == 2; # File not found
1e422769 337
9607fc9c 338 test 69, eval { open FOO, "> $foo" } eq '', 'open for write';
339 test 70, $@ =~ /^Insecure dependency/, $@;
1e422769 340}
341
342# Commands to the system can't use tainted data
343{
344 my $foo = $TAINT;
345
346 if ($^O eq 'amigaos') {
347 print "# open(\"|\") is not available\n";
9607fc9c 348 for (71..74) { print "ok $_\n" }
1e422769 349 }
350 else {
9607fc9c 351 test 71, eval { open FOO, "| $foo" } eq '', 'popen to';
1e422769 352 test 72, $@ =~ /^Insecure dependency/, $@;
1e422769 353
9607fc9c 354 test 73, eval { open FOO, "$foo |" } eq '', 'popen from';
355 test 74, $@ =~ /^Insecure dependency/, $@;
356 }
1e422769 357
9607fc9c 358 test 75, eval { exec $TAINT } eq '', 'exec';
1e422769 359 test 76, $@ =~ /^Insecure dependency/, $@;
360
9607fc9c 361 test 77, eval { system $TAINT } eq '', 'system';
362 test 78, $@ =~ /^Insecure dependency/, $@;
363
1e422769 364 $foo = "*";
365 taint_these $foo;
366
9607fc9c 367 test 79, eval { `$echo 1$foo` } eq '', 'backticks';
368 test 80, $@ =~ /^Insecure dependency/, $@;
1e422769 369
370 if ($Is_VMS) { # wildcard expansion doesn't invoke shell, so is safe
9607fc9c 371 test 81, join('', eval { glob $foo } ) ne '', 'globbing';
372 test 82, $@ eq '', $@;
1e422769 373 }
374 else {
9607fc9c 375 test 81, join('', eval { glob $foo } ) eq '', 'globbing';
376 test 82, $@ =~ /^Insecure dependency/, $@;
1e422769 377 }
378}
379
380# Operations which affect processes can't use tainted data.
381{
9607fc9c 382 test 83, eval { kill 0, $TAINT } eq '', 'kill';
383 test 84, $@ =~ /^Insecure dependency/, $@;
1e422769 384
385 if ($Config{d_setpgrp}) {
9607fc9c 386 test 85, eval { setpgrp 0, $TAINT } eq '', 'setpgrp';
387 test 86, $@ =~ /^Insecure dependency/, $@;
1e422769 388 }
389 else {
390 print "# setpgrp() is not available\n";
9607fc9c 391 for (85..86) { print "ok $_\n" }
1e422769 392 }
393
394 if ($Config{d_setprior}) {
9607fc9c 395 test 87, eval { setpriority 0, $TAINT, $TAINT } eq '', 'setpriority';
396 test 88, $@ =~ /^Insecure dependency/, $@;
1e422769 397 }
398 else {
399 print "# setpriority() is not available\n";
9607fc9c 400 for (87..88) { print "ok $_\n" }
1e422769 401 }
402}
403
404# Some miscellaneous operations can't use tainted data.
405{
406 if ($Config{d_syscall}) {
9607fc9c 407 test 89, eval { syscall $TAINT } eq '', 'syscall';
408 test 90, $@ =~ /^Insecure dependency/, $@;
1e422769 409 }
410 else {
411 print "# syscall() is not available\n";
9607fc9c 412 for (89..90) { print "ok $_\n" }
1e422769 413 }
414
415 {
416 my $foo = "x" x 979;
417 taint_these $foo;
418 local *FOO;
419 my $temp = "./taintC$$";
420 END { unlink $temp }
9607fc9c 421 test 91, open(FOO, "> $temp"), "Couldn't open $temp for write: $!";
1e422769 422
9607fc9c 423 test 92, eval { ioctl FOO, $TAINT, $foo } eq '', 'ioctl';
424 test 93, $@ =~ /^Insecure dependency/, $@;
1e422769 425
426 if ($Config{d_fcntl}) {
9607fc9c 427 test 94, eval { fcntl FOO, $TAINT, $foo } eq '', 'fcntl';
428 test 95, $@ =~ /^Insecure dependency/, $@;
1e422769 429 }
430 else {
431 print "# fcntl() is not available\n";
9607fc9c 432 for (94..95) { print "ok $_\n" }
1e422769 433 }
434
435 close FOO;
436 }
437}
438
9607fc9c 439# Some tests involving references
1e422769 440{
441 my $foo = 'abc' . $TAINT;
442 my $fooref = \$foo;
9607fc9c 443 test 96, not tainted $fooref;
444 test 97, tainted $$fooref;
445 test 98, tainted $foo;
1e422769 446}
54310121 447
448# Some tests involving assignment
449{
450 my $foo = $TAINT0;
451 my $bar = $foo;
452 test 99, all_tainted $foo, $bar;
453 test 100, tainted($foo = $bar);
454 test 101, tainted($bar = $bar);
455 test 102, tainted($bar += $bar);
456 test 103, tainted($bar -= $bar);
457 test 104, tainted($bar *= $bar);
458 test 105, tainted($bar++);
459 test 106, tainted($bar /= $bar);
460 test 107, tainted($bar += 0);
461 test 108, tainted($bar -= 2);
462 test 109, tainted($bar *= -1);
463 test 110, tainted($bar /= 1);
464 test 111, tainted($bar--);
465 test 112, $bar == 0;
466}