[perl #32039] Chained goto &sub drops data too early.
[p5sagit/p5-mst-13.2.git] / t / op / taint.t
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
6 # tests that I've missed here, please add them. But this is
7 # better than having no tests at all, right?
8 #
9
10 BEGIN {
11     chdir 't' if -d 't';
12     @INC = '../lib';
13 }
14
15 use strict;
16 use Config;
17 use File::Spec::Functions;
18
19 my $total_tests = 236;
20 my $test = 177;
21 sub ok ($;$) {
22     my($ok, $name) = @_;
23
24     # You have to do it this way or VMS will get confused.
25     print $ok ? "ok $test - $name\n" : "not ok $test - $name\n";
26
27     printf "# Failed test at line %d\n", (caller)[2] unless $ok;
28
29     $test++;
30     return $ok;
31 }
32
33
34 $| = 1;
35
36 use vars qw($ipcsysv); # did we manage to load IPC::SysV?
37
38 BEGIN {
39   if ($^O eq 'VMS' && !defined($Config{d_setenv})) {
40       $ENV{PATH} = $ENV{PATH};
41       $ENV{TERM} = $ENV{TERM} ne ''? $ENV{TERM} : 'dummy';
42   }
43   if ($Config{'extensions'} =~ /\bIPC\/SysV\b/
44       && ($Config{d_shm} || $Config{d_msg})) {
45       eval { require IPC::SysV };
46       unless ($@) {
47           $ipcsysv++;
48           IPC::SysV->import(qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU IPC_NOWAIT));
49       }
50   }
51 }
52
53 my $Is_MacOS = $^O eq 'MacOS';
54 my $Is_VMS = $^O eq 'VMS';
55 my $Is_MSWin32 = $^O eq 'MSWin32';
56 my $Is_NetWare = $^O eq 'NetWare';
57 my $Is_Dos = $^O eq 'dos';
58 my $Is_Cygwin = $^O eq 'cygwin';
59 my $Invoke_Perl = $Is_VMS ? 'MCR Sys$Disk:[]Perl.' :
60                   ($Is_MSWin32 ? '.\perl' :
61                   $Is_MacOS ? ':perl' :
62                   ($Is_NetWare ? 'perl' : './perl'));
63 my @MoreEnv = qw/IFS CDPATH ENV BASH_ENV/;
64
65 if ($Is_VMS) {
66     my (%old, $x);
67     for $x ('DCL$PATH', @MoreEnv) {
68         ($old{$x}) = $ENV{$x} =~ /^(.*)$/ if exists $ENV{$x};
69     }
70     eval <<EndOfCleanup;
71         END {
72             \$ENV{PATH} = '' if $Config{d_setenv};
73             warn "# Note: logical name 'PATH' may have been deleted\n";
74             \@ENV{keys %old} = values %old;
75         }
76 EndOfCleanup
77 }
78
79 # Sources of taint:
80 #   The empty tainted value, for tainting strings
81 my $TAINT = substr($^X, 0, 0);
82 #   A tainted zero, useful for tainting numbers
83 my $TAINT0 = 0 + $TAINT;
84
85 # This taints each argument passed. All must be lvalues.
86 # Side effect: It also stringifies them. :-(
87 sub taint_these (@) {
88     for (@_) { $_ .= $TAINT }
89 }
90
91 # How to identify taint when you see it
92 sub any_tainted (@) {
93     not eval { join("",@_), kill 0; 1 };
94 }
95 sub tainted ($) {
96     any_tainted @_;
97 }
98 sub all_tainted (@) {
99     for (@_) { return 0 unless tainted $_ }
100     1;
101 }
102
103 sub test ($$;$) {
104     my($serial, $boolean, $diag) = @_;
105     if ($boolean) {
106         print "ok $serial\n";
107     } else {
108         print "not ok $serial\n";
109         for (split m/^/m, $diag) {
110             print "# $_";
111         }
112         print "\n" unless
113             $diag eq ''
114             or substr($diag, -1) eq "\n";
115     }
116 }
117
118 # We need an external program to call.
119 my $ECHO = ($Is_MSWin32 ? ".\\echo$$" : $Is_MacOS ? ":echo$$" : ($Is_NetWare ? "echo$$" : "./echo$$"));
120 END { unlink $ECHO }
121 open PROG, "> $ECHO" or die "Can't create $ECHO: $!";
122 print PROG 'print "@ARGV\n"', "\n";
123 close PROG;
124 my $echo = "$Invoke_Perl $ECHO";
125
126 my $TEST = catfile(curdir(), 'TEST');
127
128 print "1..$total_tests\n";
129
130 # First, let's make sure that Perl is checking the dangerous
131 # environment variables. Maybe they aren't set yet, so we'll
132 # taint them ourselves.
133 {
134     $ENV{'DCL$PATH'} = '' if $Is_VMS;
135
136     $ENV{PATH} = '';
137     delete @ENV{@MoreEnv};
138     $ENV{TERM} = 'dumb';
139
140     if ($Is_Cygwin && ! -f 'cygwin1.dll') {
141         system("/usr/bin/cp /usr/bin/cygwin1.dll .") &&
142             die "$0: failed to cp cygwin1.dll: $!\n";
143         eval q{
144             END { unlink "cygwin1.dll" }
145         };
146     }
147
148     if ($Is_Cygwin && ! -f 'cygcrypt-0.dll' && -f '/usr/bin/cygcrypt-0.dll') {
149         system("/usr/bin/cp /usr/bin/cygcrypt-0.dll .") &&
150             die "$0: failed to cp cygcrypt-0.dll: $!\n";
151         eval q{
152             END { unlink "cygcrypt-0.dll" }
153         };
154     }
155
156     test 1, eval { `$echo 1` } eq "1\n";
157
158     if ($Is_MSWin32 || $Is_NetWare || $Is_VMS || $Is_Dos || $Is_MacOS) {
159         print "# Environment tainting tests skipped\n";
160         for (2..5) { print "ok $_\n" }
161     }
162     else {
163         my @vars = ('PATH', @MoreEnv);
164         while (my $v = $vars[0]) {
165             local $ENV{$v} = $TAINT;
166             last if eval { `$echo 1` };
167             last unless $@ =~ /^Insecure \$ENV{$v}/;
168             shift @vars;
169         }
170         test 2, !@vars, "\$$vars[0]";
171
172         # tainted $TERM is unsafe only if it contains metachars
173         local $ENV{TERM};
174         $ENV{TERM} = 'e=mc2';
175         test 3, eval { `$echo 1` } eq "1\n";
176         $ENV{TERM} = 'e=mc2' . $TAINT;
177         test 4, eval { `$echo 1` } eq '';
178         test 5, $@ =~ /^Insecure \$ENV{TERM}/, $@;
179     }
180
181     my $tmp;
182     if ($^O eq 'os2' || $^O eq 'amigaos' || $Is_MSWin32 || $Is_NetWare || $Is_Dos) {
183         print "# all directories are writeable\n";
184     }
185     else {
186         $tmp = (grep { defined and -d and (stat _)[2] & 2 }
187                      qw(sys$scratch /tmp /var/tmp /usr/tmp),
188                      @ENV{qw(TMP TEMP)})[0]
189             or print "# can't find world-writeable directory to test PATH\n";
190     }
191
192     if ($tmp) {
193         local $ENV{PATH} = $tmp;
194         test 6, eval { `$echo 1` } eq '';
195         test 7, $@ =~ /^Insecure directory in \$ENV{PATH}/, $@;
196     }
197     else {
198         for (6..7) { print "ok $_ # Skipped: all directories are writeable\n" }
199     }
200
201     if ($Is_VMS) {
202         $ENV{'DCL$PATH'} = $TAINT;
203         test 8,  eval { `$echo 1` } eq '';
204         test 9, $@ =~ /^Insecure \$ENV{DCL\$PATH}/, $@;
205         if ($tmp) {
206             $ENV{'DCL$PATH'} = $tmp;
207             test 10, eval { `$echo 1` } eq '';
208             test 11, $@ =~ /^Insecure directory in \$ENV{DCL\$PATH}/, $@;
209         }
210         else {
211             for (10..11) { print "ok $_ # Skipped: can't find world-writeable directory to test DCL\$PATH\n" }
212         }
213         $ENV{'DCL$PATH'} = '';
214     }
215     else {
216         for (8..11) { print "ok $_ # Skipped: This is not VMS\n"; }
217     }
218 }
219
220 # Let's see that we can taint and untaint as needed.
221 {
222     my $foo = $TAINT;
223     test 12, tainted $foo;
224
225     # That was a sanity check. If it failed, stop the insanity!
226     die "Taint checks don't seem to be enabled" unless tainted $foo;
227
228     $foo = "foo";
229     test 13, not tainted $foo;
230
231     taint_these($foo);
232     test 14, tainted $foo;
233
234     my @list = 1..10;
235     test 15, not any_tainted @list;
236     taint_these @list[1,3,5,7,9];
237     test 16, any_tainted @list;
238     test 17, all_tainted @list[1,3,5,7,9];
239     test 18, not any_tainted @list[0,2,4,6,8];
240
241     ($foo) = $foo =~ /(.+)/;
242     test 19, not tainted $foo;
243
244     $foo = $1 if ('bar' . $TAINT) =~ /(.+)/;
245     test 20, not tainted $foo;
246     test 21, $foo eq 'bar';
247
248     {
249       use re 'taint';
250
251       ($foo) = ('bar' . $TAINT) =~ /(.+)/;
252       test 22, tainted $foo;
253       test 23, $foo eq 'bar';
254
255       $foo = $1 if ('bar' . $TAINT) =~ /(.+)/;
256       test 24, tainted $foo;
257       test 25, $foo eq 'bar';
258     }
259
260     $foo = $1 if 'bar' =~ /(.+)$TAINT/;
261     test 26, tainted $foo;
262     test 27, $foo eq 'bar';
263
264     my $pi = 4 * atan2(1,1) + $TAINT0;
265     test 28, tainted $pi;
266
267     ($pi) = $pi =~ /(\d+\.\d+)/;
268     test 29, not tainted $pi;
269     test 30, sprintf("%.5f", $pi) eq '3.14159';
270 }
271
272 # How about command-line arguments? The problem is that we don't
273 # always get some, so we'll run another process with some.
274 SKIP: {
275     my $arg = catfile(curdir(), "arg$$");
276     open PROG, "> $arg" or die "Can't create $arg: $!";
277     print PROG q{
278         eval { join('', @ARGV), kill 0 };
279         exit 0 if $@ =~ /^Insecure dependency/;
280         print "# Oops: \$@ was [$@]\n";
281         exit 1;
282     };
283     close PROG;
284     print `$Invoke_Perl "-T" $arg and some suspect arguments`;
285     test 31, !$?, "Exited with status $?";
286     unlink $arg;
287 }
288
289 # Reading from a file should be tainted
290 {
291     test 32, open(FILE, $TEST), "Couldn't open '$TEST': $!";
292
293     my $block;
294     sysread(FILE, $block, 100);
295     my $line = <FILE>;
296     close FILE;
297     test 33, tainted $block;
298     test 34, tainted $line;
299 }
300
301 # Globs should be forbidden, except under VMS,
302 #   which doesn't spawn an external program.
303 if (1  # built-in glob
304     or $Is_VMS) {
305     for (35..36) { print "ok $_\n"; }
306 }
307 else {
308     my @globs = eval { <*> };
309     test 35, @globs == 0 && $@ =~ /^Insecure dependency/;
310
311     @globs = eval { glob '*' };
312     test 36, @globs == 0 && $@ =~ /^Insecure dependency/;
313 }
314
315 # Output of commands should be tainted
316 {
317     my $foo = `$echo abc`;
318     test 37, tainted $foo;
319 }
320
321 # Certain system variables should be tainted
322 {
323     test 38, all_tainted $^X, $0;
324 }
325
326 # Results of matching should all be untainted
327 {
328     my $foo = "abcdefghi" . $TAINT;
329     test 39, tainted $foo;
330
331     $foo =~ /def/;
332     test 40, not any_tainted $`, $&, $';
333
334     $foo =~ /(...)(...)(...)/;
335     test 41, not any_tainted $1, $2, $3, $+;
336
337     my @bar = $foo =~ /(...)(...)(...)/;
338     test 42, not any_tainted @bar;
339
340     test 43, tainted $foo;      # $foo should still be tainted!
341     test 44, $foo eq "abcdefghi";
342 }
343
344 # Operations which affect files can't use tainted data.
345 {
346     test 45, eval { chmod 0, $TAINT } eq '', 'chmod';
347     test 46, $@ =~ /^Insecure dependency/, $@;
348
349     # There is no feature test in $Config{} for truncate,
350     #   so we allow for the possibility that it's missing.
351     test 47, eval { truncate 'NoSuChFiLe', $TAINT0 } eq '', 'truncate';
352     test 48, $@ =~ /^(?:Insecure dependency|truncate not implemented)/, $@;
353
354     test 49, eval { rename '', $TAINT } eq '', 'rename';
355     test 50, $@ =~ /^Insecure dependency/, $@;
356
357     test 51, eval { unlink $TAINT } eq '', 'unlink';
358     test 52, $@ =~ /^Insecure dependency/, $@;
359
360     test 53, eval { utime $TAINT } eq '', 'utime';
361     test 54, $@ =~ /^Insecure dependency/, $@;
362
363     if ($Config{d_chown}) {
364         test 55, eval { chown -1, -1, $TAINT } eq '', 'chown';
365         test 56, $@ =~ /^Insecure dependency/, $@;
366     }
367     else {
368         for (55..56) { print "ok $_ # Skipped: chown() is not available\n" }
369     }
370
371     if ($Config{d_link}) {
372         test 57, eval { link $TAINT, '' } eq '', 'link';
373         test 58, $@ =~ /^Insecure dependency/, $@;
374     }
375     else {
376         for (57..58) { print "ok $_ # Skipped: link() is not available\n" }
377     }
378
379     if ($Config{d_symlink}) {
380         test 59, eval { symlink $TAINT, '' } eq '', 'symlink';
381         test 60, $@ =~ /^Insecure dependency/, $@;
382     }
383     else {
384         for (59..60) { print "ok $_ # Skipped: symlink() is not available\n" }
385     }
386 }
387
388 # Operations which affect directories can't use tainted data.
389 {
390     test 61, eval { mkdir $TAINT0, $TAINT } eq '', 'mkdir';
391     test 62, $@ =~ /^Insecure dependency/, $@;
392
393     test 63, eval { rmdir $TAINT } eq '', 'rmdir';
394     test 64, $@ =~ /^Insecure dependency/, $@;
395
396     test 65, eval { chdir $TAINT } eq '', 'chdir';
397     test 66, $@ =~ /^Insecure dependency/, $@;
398
399     if ($Config{d_chroot}) {
400         test 67, eval { chroot $TAINT } eq '', 'chroot';
401         test 68, $@ =~ /^Insecure dependency/, $@;
402     }
403     else {
404         for (67..68) { print "ok $_ # Skipped: chroot() is not available\n" }
405     }
406 }
407
408 # Some operations using files can't use tainted data.
409 {
410     my $foo = "imaginary library" . $TAINT;
411     test 69, eval { require $foo } eq '', 'require';
412     test 70, $@ =~ /^Insecure dependency/, $@;
413
414     my $filename = "./taintB$$";        # NB: $filename isn't tainted!
415     END { unlink $filename if defined $filename }
416     $foo = $filename . $TAINT;
417     unlink $filename;   # in any case
418
419     test 71, eval { open FOO, $foo } eq '', 'open for read';
420     test 72, $@ eq '', $@;              # NB: This should be allowed
421
422     # Try first new style but allow also old style.
423     # We do not want the whole taint.t to fail
424     # just because Errno possibly failing.
425     test 73, eval('$!{ENOENT}') ||
426         $! == 2 || # File not found
427         ($Is_Dos && $! == 22) ||
428         ($^O eq 'mint' && $! == 33);
429
430     test 74, eval { open FOO, "> $foo" } eq '', 'open for write';
431     test 75, $@ =~ /^Insecure dependency/, $@;
432 }
433
434 # Commands to the system can't use tainted data
435 {
436     my $foo = $TAINT;
437
438     if ($^O eq 'amigaos') {
439         for (76..79) { print "ok $_ # Skipped: open('|') is not available\n" }
440     }
441     else {
442         test 76, eval { open FOO, "| x$foo" } eq '', 'popen to';
443         test 77, $@ =~ /^Insecure dependency/, $@;
444
445         test 78, eval { open FOO, "x$foo |" } eq '', 'popen from';
446         test 79, $@ =~ /^Insecure dependency/, $@;
447     }
448
449     test 80, eval { exec $TAINT } eq '', 'exec';
450     test 81, $@ =~ /^Insecure dependency/, $@;
451
452     test 82, eval { system $TAINT } eq '', 'system';
453     test 83, $@ =~ /^Insecure dependency/, $@;
454
455     $foo = "*";
456     taint_these $foo;
457
458     test 84, eval { `$echo 1$foo` } eq '', 'backticks';
459     test 85, $@ =~ /^Insecure dependency/, $@;
460
461     if ($Is_VMS) { # wildcard expansion doesn't invoke shell, so is safe
462         test 86, join('', eval { glob $foo } ) ne '', 'globbing';
463         test 87, $@ eq '', $@;
464     }
465     else {
466         for (86..87) { print "ok $_ # Skipped: This is not VMS\n"; }
467     }
468 }
469
470 # Operations which affect processes can't use tainted data.
471 {
472     test 88, eval { kill 0, $TAINT } eq '', 'kill';
473     test 89, $@ =~ /^Insecure dependency/, $@;
474
475     if ($Config{d_setpgrp}) {
476         test 90, eval { setpgrp 0, $TAINT } eq '', 'setpgrp';
477         test 91, $@ =~ /^Insecure dependency/, $@;
478     }
479     else {
480         for (90..91) { print "ok $_ # Skipped: setpgrp() is not available\n" }
481     }
482
483     if ($Config{d_setprior}) {
484         test 92, eval { setpriority 0, $TAINT, $TAINT } eq '', 'setpriority';
485         test 93, $@ =~ /^Insecure dependency/, $@;
486     }
487     else {
488         for (92..93) { print "ok $_ # Skipped: setpriority() is not available\n" }
489     }
490 }
491
492 # Some miscellaneous operations can't use tainted data.
493 {
494     if ($Config{d_syscall}) {
495         test 94, eval { syscall $TAINT } eq '', 'syscall';
496         test 95, $@ =~ /^Insecure dependency/, $@;
497     }
498     else {
499         for (94..95) { print "ok $_ # Skipped: syscall() is not available\n" }
500     }
501
502     {
503         my $foo = "x" x 979;
504         taint_these $foo;
505         local *FOO;
506         my $temp = "./taintC$$";
507         END { unlink $temp }
508         test 96, open(FOO, "> $temp"), "Couldn't open $temp for write: $!";
509
510         test 97, eval { ioctl FOO, $TAINT, $foo } eq '', 'ioctl';
511         test 98, $@ =~ /^Insecure dependency/, $@;
512
513         if ($Config{d_fcntl}) {
514             test 99, eval { fcntl FOO, $TAINT, $foo } eq '', 'fcntl';
515             test 100, $@ =~ /^Insecure dependency/, $@;
516         }
517         else {
518             for (99..100) { print "ok $_ # Skipped: fcntl() is not available\n" }
519         }
520
521         close FOO;
522     }
523 }
524
525 # Some tests involving references
526 {
527     my $foo = 'abc' . $TAINT;
528     my $fooref = \$foo;
529     test 101, not tainted $fooref;
530     test 102, tainted $$fooref;
531     test 103, tainted $foo;
532 }
533
534 # Some tests involving assignment
535 {
536     my $foo = $TAINT0;
537     my $bar = $foo;
538     test 104, all_tainted $foo, $bar;
539     test 105, tainted($foo = $bar);
540     test 106, tainted($bar = $bar);
541     test 107, tainted($bar += $bar);
542     test 108, tainted($bar -= $bar);
543     test 109, tainted($bar *= $bar);
544     test 110, tainted($bar++);
545     test 111, tainted($bar /= $bar);
546     test 112, tainted($bar += 0);
547     test 113, tainted($bar -= 2);
548     test 114, tainted($bar *= -1);
549     test 115, tainted($bar /= 1);
550     test 116, tainted($bar--);
551     test 117, $bar == 0;
552 }
553
554 # Test assignment and return of lists
555 {
556     my @foo = ("A", "tainted" . $TAINT, "B");
557     test 118, not tainted $foo[0];
558     test 119,     tainted $foo[1];
559     test 120, not tainted $foo[2];
560     my @bar = @foo;
561     test 121, not tainted $bar[0];
562     test 122,     tainted $bar[1];
563     test 123, not tainted $bar[2];
564     my @baz = eval { "A", "tainted" . $TAINT, "B" };
565     test 124, not tainted $baz[0];
566     test 125,     tainted $baz[1];
567     test 126, not tainted $baz[2];
568     my @plugh = eval q[ "A", "tainted" . $TAINT, "B" ];
569     test 127, not tainted $plugh[0];
570     test 128,     tainted $plugh[1];
571     test 129, not tainted $plugh[2];
572     my $nautilus = sub { "A", "tainted" . $TAINT, "B" };
573     test 130, not tainted ((&$nautilus)[0]);
574     test 131,     tainted ((&$nautilus)[1]);
575     test 132, not tainted ((&$nautilus)[2]);
576     my @xyzzy = &$nautilus;
577     test 133, not tainted $xyzzy[0];
578     test 134,     tainted $xyzzy[1];
579     test 135, not tainted $xyzzy[2];
580     my $red_october = sub { return "A", "tainted" . $TAINT, "B" };
581     test 136, not tainted ((&$red_october)[0]);
582     test 137,     tainted ((&$red_october)[1]);
583     test 138, not tainted ((&$red_october)[2]);
584     my @corge = &$red_october;
585     test 139, not tainted $corge[0];
586     test 140,     tainted $corge[1];
587     test 141, not tainted $corge[2];
588 }
589
590 # Test for system/library calls returning string data of dubious origin.
591 {
592     # No reliable %Config check for getpw*
593     if (eval { setpwent(); getpwent() }) {
594         setpwent();
595         my @getpwent = getpwent();
596         die "getpwent: $!\n" unless (@getpwent);
597         test 142,(    not tainted $getpwent[0]
598                   and     tainted $getpwent[1]
599                   and not tainted $getpwent[2]
600                   and not tainted $getpwent[3]
601                   and not tainted $getpwent[4]
602                   and not tainted $getpwent[5]
603                   and     tainted $getpwent[6]          # ge?cos
604                   and not tainted $getpwent[7]
605                   and     tainted $getpwent[8]);        # shell
606         endpwent();
607     } else {
608         for (142) { print "ok $_ # Skipped: getpwent() is not available\n" }
609     }
610
611     if ($Config{d_readdir}) { # pretty hard to imagine not
612         local(*D);
613         opendir(D, "op") or die "opendir: $!\n";
614         my $readdir = readdir(D);
615         test 143, tainted $readdir;
616         closedir(OP);
617     } else {
618         for (143) { print "ok $_ # Skipped: readdir() is not available\n" }
619     }
620
621     if ($Config{d_readlink} && $Config{d_symlink}) {
622         my $symlink = "sl$$";
623         unlink($symlink);
624         my $sl = "/something/naughty";
625         # it has to be a real path on Mac OS
626         $sl = MacPerl::MakePath((MacPerl::Volumes())[0]) if $Is_MacOS;
627         symlink($sl, $symlink) or die "symlink: $!\n";
628         my $readlink = readlink($symlink);
629         test 144, tainted $readlink;
630         unlink($symlink);
631     } else {
632         for (144) { print "ok $_ # Skipped: readlink() or symlink() is not available\n"; }
633     }
634 }
635
636 # test bitwise ops (regression bug)
637 {
638     my $why = "y";
639     my $j = "x" | $why;
640     test 145, not tainted $j;
641     $why = $TAINT."y";
642     $j = "x" | $why;
643     test 146,     tainted $j;
644 }
645
646 # test target of substitution (regression bug)
647 {
648     my $why = $TAINT."y";
649     $why =~ s/y/z/;
650     test 147,     tainted $why;
651
652     my $z = "[z]";
653     $why =~ s/$z/zee/;
654     test 148,     tainted $why;
655
656     $why =~ s/e/'-'.$$/ge;
657     test 149,     tainted $why;
658 }
659
660 # test shmread
661 {
662     unless ($ipcsysv) {
663         print "ok 150 # skipped: no IPC::SysV\n";
664         last;
665     }
666     if ($Config{'extensions'} =~ /\bIPC\/SysV\b/ && $Config{d_shm}) {
667         no strict 'subs';
668         my $sent = "foobar";
669         my $rcvd;
670         my $size = 2000;
671         my $id = shmget(IPC_PRIVATE, $size, S_IRWXU);
672
673         if (defined $id) {
674             if (shmwrite($id, $sent, 0, 60)) {
675                 if (shmread($id, $rcvd, 0, 60)) {
676                     substr($rcvd, index($rcvd, "\0")) = '';
677                 } else {
678                     warn "# shmread failed: $!\n";
679                 }
680             } else {
681                 warn "# shmwrite failed: $!\n";
682             }
683             shmctl($id, IPC_RMID, 0) or warn "# shmctl failed: $!\n";
684         } else {
685             warn "# shmget failed: $!\n";
686         }
687
688         if ($rcvd eq $sent) {
689             test 150, tainted $rcvd;
690         } else {
691             print "ok 150 # Skipped: SysV shared memory operation failed\n";
692         }
693     } else {
694         print "ok 150 # Skipped: SysV shared memory is not available\n";
695     }
696 }
697
698 # test msgrcv
699 {
700     unless ($ipcsysv) {
701         print "ok 151 # skipped: no IPC::SysV\n";
702         last;
703     }
704     if ($Config{'extensions'} =~ /\bIPC\/SysV\b/ && $Config{d_msg}) {
705         no strict 'subs';
706         my $id = msgget(IPC_PRIVATE, IPC_CREAT | S_IRWXU);
707
708         my $sent      = "message";
709         my $type_sent = 1234;
710         my $rcvd;
711         my $type_rcvd;
712
713         if (defined $id) {
714             if (msgsnd($id, pack("l! a*", $type_sent, $sent), IPC_NOWAIT)) {
715                 if (msgrcv($id, $rcvd, 60, 0, IPC_NOWAIT)) {
716                     ($type_rcvd, $rcvd) = unpack("l! a*", $rcvd);
717                 } else {
718                     warn "# msgrcv failed: $!\n";
719                 }
720             } else {
721                 warn "# msgsnd failed: $!\n";
722             }
723             msgctl($id, IPC_RMID, 0) or warn "# msgctl failed: $!\n";
724         } else {
725             warn "# msgget failed\n";
726         }
727
728         if ($rcvd eq $sent && $type_sent == $type_rcvd) {
729             test 151, tainted $rcvd;
730         } else {
731             print "ok 151 # Skipped: SysV message queue operation failed\n";
732         }
733     } else {
734         print "ok 151 # Skipped: SysV message queues are not available\n";
735     }
736 }
737
738 {
739     # bug id 20001004.006
740
741     open IN, $TEST or warn "$0: cannot read $TEST: $!" ;
742     local $/;
743     my $a = <IN>;
744     my $b = <IN>;
745     print "not " unless tainted($a) && tainted($b) && !defined($b);
746     print "ok 152\n";
747     close IN;
748 }
749
750 {
751     # bug id 20001004.007
752
753     open IN, $TEST or warn "$0: cannot read $TEST: $!" ;
754     my $a = <IN>;
755
756     my $c = { a => 42,
757               b => $a };
758     print "not " unless !tainted($c->{a}) && tainted($c->{b});
759     print "ok 153\n";
760
761     my $d = { a => $a,
762               b => 42 };
763     print "not " unless tainted($d->{a}) && !tainted($d->{b});
764     print "ok 154\n";
765
766     my $e = { a => 42,
767               b => { c => $a, d => 42 } };
768     print "not " unless !tainted($e->{a}) &&
769                         !tainted($e->{b}) &&
770                          tainted($e->{b}->{c}) &&
771                         !tainted($e->{b}->{d});
772     print "ok 155\n";
773
774     close IN;
775 }
776
777 {
778     # bug id 20010519.003
779
780     BEGIN {
781         use vars qw($has_fcntl);
782         eval { require Fcntl; import Fcntl; };
783         unless ($@) {
784             $has_fcntl = 1;
785         }
786     }
787
788     unless ($has_fcntl) {
789         for (156..173) {
790             print "ok $_ # Skip: no Fcntl (no dynaloading?)\n";
791         }
792     } else {
793         my $evil = "foo" . $TAINT;
794
795         eval { sysopen(my $ro, $evil, &O_RDONLY) };
796         test 156, $@ !~ /^Insecure dependency/, $@;
797         
798         eval { sysopen(my $wo, $evil, &O_WRONLY) };
799         test 157, $@ =~ /^Insecure dependency/, $@;
800         
801         eval { sysopen(my $rw, $evil, &O_RDWR) };
802         test 158, $@ =~ /^Insecure dependency/, $@;
803         
804         eval { sysopen(my $ap, $evil, &O_APPEND) };
805         test 159, $@ =~ /^Insecure dependency/, $@;
806         
807         eval { sysopen(my $cr, $evil, &O_CREAT) };
808         test 160, $@ =~ /^Insecure dependency/, $@;
809         
810         eval { sysopen(my $tr, $evil, &O_TRUNC) };
811         test 161, $@ =~ /^Insecure dependency/, $@;
812         
813         eval { sysopen(my $ro, "foo", &O_RDONLY | $evil) };
814         test 162, $@ !~ /^Insecure dependency/, $@;
815         
816         eval { sysopen(my $wo, "foo", &O_WRONLY | $evil) };
817         test 163, $@ =~ /^Insecure dependency/, $@;
818
819         eval { sysopen(my $rw, "foo", &O_RDWR | $evil) };
820         test 164, $@ =~ /^Insecure dependency/, $@;
821
822         eval { sysopen(my $ap, "foo", &O_APPEND | $evil) };
823         test 165, $@ =~ /^Insecure dependency/, $@;
824         
825         eval { sysopen(my $cr, "foo", &O_CREAT | $evil) };
826         test 166, $@ =~ /^Insecure dependency/, $@;
827
828         eval { sysopen(my $tr, "foo", &O_TRUNC | $evil) };
829         test 167, $@ =~ /^Insecure dependency/, $@;
830
831         eval { sysopen(my $ro, "foo", &O_RDONLY, $evil) };
832         test 168, $@ !~ /^Insecure dependency/, $@;
833         
834         eval { sysopen(my $wo, "foo", &O_WRONLY, $evil) };
835         test 169, $@ =~ /^Insecure dependency/, $@;
836         
837         eval { sysopen(my $rw, "foo", &O_RDWR, $evil) };
838         test 170, $@ =~ /^Insecure dependency/, $@;
839         
840         eval { sysopen(my $ap, "foo", &O_APPEND, $evil) };
841         test 171, $@ =~ /^Insecure dependency/, $@;
842         
843         eval { sysopen(my $cr, "foo", &O_CREAT, $evil) };
844         test 172, $@ =~ /^Insecure dependency/, $@;
845
846         eval { sysopen(my $tr, "foo", &O_TRUNC, $evil) };
847         test 173, $@ =~ /^Insecure dependency/, $@;
848         
849         unlink("foo"); # not unlink($evil), because that would fail...
850     }
851 }
852
853 {
854     # bug 20010526.004
855
856     use warnings;
857
858     local $SIG{__WARN__} = sub { print "not " };
859
860     sub fmi {
861         my $divnum = shift()/1;
862         sprintf("%1.1f\n", $divnum);
863     }
864
865     fmi(21 . $TAINT);
866     fmi(37);
867     fmi(248);
868
869     print "ok 174\n";
870 }
871
872
873 {
874     # Bug ID 20010730.010
875
876     my $i = 0;
877
878     sub Tie::TIESCALAR {
879         my $class =  shift;
880         my $arg   =  shift;
881
882         bless \$arg => $class;
883     }
884
885     sub Tie::FETCH {
886         $i ++;
887         ${$_ [0]}
888     }
889
890  
891     package main;
892  
893     my $bar = "The Big Bright Green Pleasure Machine";
894     taint_these $bar;
895     tie my ($foo), Tie => $bar;
896
897     my $baz = $foo;
898
899     print $i == 1 ? "ok 175\n" : "not ok 175\n"
900
901 }
902
903 {
904     # Check that all environment variables are tainted.
905     my @untainted;
906     while (my ($k, $v) = each %ENV) {
907         if (!tainted($v) &&
908             # These we have explicitly untainted or set earlier.
909             $k !~ /^(BASH_ENV|CDPATH|ENV|IFS|PATH|PERL_CORE|TEMP|TERM|TMP)$/) {
910             push @untainted, "# '$k' = '$v'\n";
911         }
912     }
913     print @untainted == 0 ? "ok 176\n" : "not ok 176\n";
914     print "# untainted:\n", @untainted if @untainted; 
915 }
916
917
918 ok( ${^TAINT} == 1, '$^TAINT is on' );
919
920 eval { ${^TAINT} = 0 };
921 ok( ${^TAINT},  '$^TAINT is not assignable' );
922 ok( $@ =~ /^Modification of a read-only value attempted/,
923                                 'Assigning to ${^TAINT} fails' );
924
925 {
926     # bug 20011111.105
927     
928     my $re1 = qr/x$TAINT/;
929     test 180, tainted $re1;
930     
931     my $re2 = qr/^$re1\z/;
932     test 181, tainted $re2;
933     
934     my $re3 = "$re2";
935     test 182, tainted $re3;
936 }
937
938 if ($Is_MSWin32) {
939     print "ok 183 # Skipped: system {} has different semantics\n"; 
940 }
941 else
942 {
943     # bug 20010221.005
944     local $ENV{PATH} .= $TAINT;
945     eval { system { "echo" } "/arg0", "arg1" };
946     test 183, $@ =~ /^Insecure \$ENV/;
947 }
948 if ($Is_VMS) {
949     for (184..205) {print "not ok $_ # TODO tainted %ENV warning occludes tainted arguments warning\n";}
950 }
951 else 
952 {
953     # bug 20020208.005 plus some extras
954     # single arg exec/system are tests 80-83
955     my $err = qr/^Insecure dependency/ ;
956     test 184, eval { exec $TAINT, $TAINT } eq '', 'exec';
957     test 185, $@ =~ $err, $@;
958     test 186, eval { exec $TAINT $TAINT } eq '', 'exec';
959     test 187, $@ =~ $err, $@;
960     test 188, eval { exec $TAINT $TAINT, $TAINT } eq '', 'exec';
961     test 189, $@ =~ $err, $@;
962     test 190, eval { exec $TAINT 'notaint' } eq '', 'exec';
963     test 191, $@ =~ $err, $@;
964     test 192, eval { exec {'notaint'} $TAINT } eq '', 'exec';
965     test 193, $@ =~ $err, $@;
966
967     test 194, eval { system $TAINT, $TAINT } eq '', 'system';
968     test 195, $@ =~ $err, $@;
969     test 196, eval { system $TAINT $TAINT } eq '', 'system';
970     test 197, $@ =~ $err, $@;
971     test 198, eval { system $TAINT $TAINT, $TAINT } eq '', 'system';
972     test 199, $@ =~ $err, $@;
973     test 200, eval { system $TAINT 'notaint' } eq '', 'system';
974     test 201, $@ =~ $err, $@;
975     test 202, eval { system {'notaint'} $TAINT } eq '', 'system';
976     test 203, $@ =~ $err, $@;
977
978     eval { system("lskdfj does not exist","with","args"); };
979     test 204, $@ eq '';
980     if ($Is_MacOS) {
981         print "ok 205 # no exec()\n";
982     } else {
983         eval { exec("lskdfj does not exist","with","args"); };
984         test 205, $@ eq '';
985     }
986
987     # If you add tests here update also the above skip block for VMS.
988 }
989
990 {
991     # [ID 20020704.001] taint propagation failure
992     use re 'taint';
993     $TAINT =~ /(.*)/;
994     test 206, tainted(my $foo = $1);
995 }
996
997 {
998     # [perl #24291] this used to dump core
999     our %nonmagicalenv = ( PATH => "util" );
1000     local *ENV = \%nonmagicalenv;
1001     eval { system("lskdfj"); };
1002     test 207, $@ =~ /^%ENV is aliased to another variable while running with -T switch/;
1003     local *ENV = *nonmagicalenv;
1004     eval { system("lskdfj"); };
1005     test 208, $@ =~ /^%ENV is aliased to %nonmagicalenv while running with -T switch/;
1006 }
1007 {
1008     # [perl #24248]
1009     $TAINT =~ /(.*)/;
1010     test 209, !tainted($1);
1011     my $notaint = $1;
1012     test 210, !tainted($notaint);
1013
1014     my $l;
1015     $notaint =~ /($notaint)/;
1016     $l = $1;
1017     test 211, !tainted($1);
1018     test 212, !tainted($l);
1019     $notaint =~ /($TAINT)/;
1020     $l = $1;
1021     test 213, tainted($1);
1022     test 214, tainted($l);
1023
1024     $TAINT =~ /($notaint)/;
1025     $l = $1;
1026     test 215, !tainted($1);
1027     test 216, !tainted($l);
1028     $TAINT =~ /($TAINT)/;
1029     $l = $1;
1030     test 217, tainted($1);
1031     test 218, tainted($l);
1032
1033     my $r;
1034     ($r = $TAINT) =~ /($notaint)/;
1035     test 219, !tainted($1);
1036     ($r = $TAINT) =~ /($TAINT)/;
1037     test 220, tainted($1);
1038
1039     #  [perl #24674]
1040     # accessing $^O  shoudn't taint it as a side-effect;
1041     # assigning tainted data to it is now an error
1042
1043     test 221, !tainted($^O);
1044     if (!$^X) { } elsif ($^O eq 'bar') { }
1045     test 222, !tainted($^O);
1046     eval '$^O = $^X';
1047     test 223, $@ =~ /Insecure dependency in/;
1048 }
1049
1050 EFFECTIVELY_CONSTANTS: {
1051     my $tainted_number = 12 + $TAINT0;
1052     test 224, tainted( $tainted_number );
1053
1054     # Even though it's always 0, it's still tainted
1055     my $tainted_product = $tainted_number * 0;
1056     test 225, tainted( $tainted_product );
1057     test 226, $tainted_product == 0;
1058 }
1059
1060 TERNARY_CONDITIONALS: {
1061     my $tainted_true  = $TAINT . "blah blah blah";
1062     my $tainted_false = $TAINT0;
1063     test 227, tainted( $tainted_true );
1064     test 228, tainted( $tainted_false );
1065
1066     my $result = $tainted_true ? "True" : "False";
1067     test 229, $result eq "True";
1068     test 230, !tainted( $result );
1069
1070     $result = $tainted_false ? "True" : "False";
1071     test 231, $result eq "False";
1072     test 232, !tainted( $result );
1073
1074     my $untainted_whatever = "The Fabulous Johnny Cash";
1075     my $tainted_whatever = "Soft Cell" . $TAINT;
1076
1077     $result = $tainted_true ? $tainted_whatever : $untainted_whatever;
1078     test 233, $result eq "Soft Cell";
1079     test 234, tainted( $result );
1080
1081     $result = $tainted_false ? $tainted_whatever : $untainted_whatever;
1082     test 235, $result eq "The Fabulous Johnny Cash";
1083     test 236, !tainted( $result );
1084 }