File Coverage

blib/lib/Taint/Runtime.pm
Criterion Covered Total %
statement 42 68 61.7
branch 23 40 57.5
condition 3 8 37.5
subroutine 14 18 77.7
pod 9 10 90.0
total 91 144 63.1


line stmt bran cond sub pod time code
1             package Taint::Runtime;
2              
3             =head1 NAME
4              
5             Taint::Runtime - Runtime enable taint checking
6              
7             =cut
8              
9 6     6   156895 use strict;
  6         14  
  6         240  
10 6     6   154 use Exporter;
  6         12  
  6         428  
11 6     6   33 use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $TAINT);
  6         15  
  6         695  
12 6     6   33 use XSLoader;
  6         11  
  6         7235  
13              
14             @ISA = qw(Exporter);
15             %EXPORT_TAGS = (
16             'all' => [qw(
17             taint_start
18             taint_stop
19             taint_enabled
20             tainted
21             is_tainted
22             taint
23             untaint
24             taint_env
25             taint_deeply
26             $TAINT
27             ) ],
28             );
29             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
30             @EXPORT = qw(taint_start taint_stop);
31              
32             $VERSION = '0.03';
33             XSLoader::load('Taint::Runtime', $VERSION);
34              
35             ###----------------------------------------------------------------###
36              
37             tie $TAINT, __PACKAGE__;
38              
39             sub TIESCALAR {
40 6     6   28 return bless [], __PACKAGE__;
41             }
42              
43             sub FETCH {
44 5 100   5   58 _taint_enabled() ? 1 : 0;
45             }
46              
47             sub STORE {
48 7     7   286 my ($self, $val) = @_;
49 7 100 66     38 $val = 0 if ! $val || $val eq 'disable';
50 7 100       38 $val ? _taint_start() : _taint_stop();
51             }
52              
53             ###----------------------------------------------------------------###
54              
55             ### allow for special enable/disable keywords
56             sub import {
57 12     12   103 my $change;
58 12         59 for my $i (reverse 1 .. $#_) {
59 17 100       69 next if $_[$i] !~ /^(dis|en)able$/;
60 2 100       8 my $val = $1 eq 'dis' ? 0 : 1;
61 2         4 splice @_, $i, 1, ();
62 2 50 33     9 die 'Cannot both enable and disable $TAINT during import' if defined $change && $change != $val;
63 2         7 $TAINT = $val;
64             }
65 12         1325 __PACKAGE__->export_to_level(1, @_);
66             }
67              
68             ###----------------------------------------------------------------###
69              
70 1     1 1 6 sub taint_start { _taint_start(); }
71              
72 0     0 1 0 sub taint_stop { _taint_stop() }
73              
74 8     8 1 60 sub taint_enabled { _taint_enabled() }
75              
76 4     4 1 25 sub tainted { _tainted() }
77              
78 11 50   11 1 51 sub is_tainted { return if ! defined $_[0]; ! eval { eval '#'.substr($_[0], 0, 0); 1 } }
  11         22  
  11         310  
  6         44  
79              
80             # slower on tainted and undef
81             # modified version from standard lib/perl/5.8.5/tainted.pl
82 0     0 0 0 sub is_tainted2 { local $^W = 0; local $@; eval { kill 0 * $_[0] }; $@ =~ /^Insecure/ }
  0         0  
  0         0  
  0         0  
  0         0  
83              
84             sub taint {
85 4     4 1 9 my $str = shift;
86 4 100       16 my $ref = ref($str) ? $str : \$str;
87 4 50       20 $$ref = '' if ! defined $$ref;
88 4         12 $$ref .= tainted();
89 4 100       27 return ref($str) ? 1 : $str;
90             }
91              
92             sub untaint {
93 4     4 1 12 my $str = shift;
94 4 100       21 my $ref = ref($str) ? $str : \$str;
95 4 50       14 if (! defined $$ref) {
96 0         0 $$ref = undef;
97             } else {
98 4 50       30 $$ref = ($$ref =~ /(.*)/s) ? $1 : do { require Carp; Carp::confess("Couldn't find data to untaint") };
  0         0  
  0         0  
99             }
100 4 100       23 return ref($str) ? 1 : $str;
101             }
102              
103             ###----------------------------------------------------------------###
104              
105             sub taint_env {
106 0     0 1   taint_deeply(\%ENV);
107             }
108              
109             sub taint_deeply {
110 0     0 1   my ($ref, $seen) = @_;
111              
112 0 0         return if ! defined $ref; # can undefined be tainted ?
113              
114 0 0         if (! ref $ref) {
    0          
115 0           taint \$_[0]; # better be modifyable
116 0           return;
117              
118             } elsif (UNIVERSAL::isa($ref, 'SCALAR')) {
119 0           taint $ref;
120 0           return;
121             }
122              
123             ### avoid circular descent
124 0   0       $seen ||= {};
125 0 0         return if $seen->{$ref};
126 0           $seen->{$ref} = 1;
127              
128 0 0         if (UNIVERSAL::isa($ref, 'ARRAY')) {
    0          
129 0           taint_deeply($_, $seen) foreach @$ref;
130              
131             } elsif (UNIVERSAL::isa($ref, 'HASH')) {
132 0           while (my ($key, $val) = each %$ref) {
133 0           taint_deeply($key);
134 0           taint_deeply($val, $seen);
135 0           $ref->{$key} = $val;
136             }
137             } else {
138             # not really sure if or what to do for GLOBS or CODE refs
139             }
140             }
141              
142             ###----------------------------------------------------------------###
143              
144             1;
145              
146             __END__