Safe.pm 2.08 This CPAN release is a minor update of Safe.pm that fixes a security problem in reval and rdo where they would only be safe on the first run. The following is from Andreas Jurenda who discovered the bug. From: "Andreas Jurenda" To: Subject: Security-Hole in module Safe.pm Date: Fri, 4 Oct 2002 09:24:10 +0100 Well, I have found a security problem in module Safe.pm Sorry at may english, but my tongues are Pascal, Basic, C, C++,... maybe Perl but neither german nor english, but I will do my best ;-) The problem belongs to these two versions of Safe.pm: Safe.pm Version 2.06 at Perl 5.6.1 and Safe.pm Version 2.07 at Perl 5.8.0 In both versions there is the same code for Safe::reval() Safe::reval() execute a given code in a safe compartment. But this routine has a one-time safeness. If you call reval() a second (or more) time with the same compartment, you are potential unsafe. These depends on the values of @_ at the entrypoint of the safe compartment. Have a look at the source code of Safe::reval() Source: ======= sub reval { my ($obj, $expr, $strict) = @_; my $root = $obj->{Root}; # Create anon sub ref in root of compartment. # Uses a closure (on $expr) to pass in the code to be executed. # (eval on one line to keep line numbers as expected by caller) my $evalcode = sprintf('package %s; sub { eval $expr; }', $root); my $evalsub; if ($strict) { use strict; $evalsub = eval $evalcode; } else { no strict; $evalsub = eval $evalcode; } return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); } In the last line there is the call for the execution of our $expr. Inside $expr at runtime there are @_ set with ($root, $obj->{Mask}, $evalsub). And thats the hole, because $_[1] is directly linked to $obj->{Mask}. Modifying of $_[1] manipulate directly the operationmask of the safe compartment! At the first time calling reval() and manipulation $_[1] has no effect. But after that the second (and more) call you get the (un-)"safe" compartment with the manipulatet operation mask! Example: ======== $codefullopmask = '$_[1] = chr(0x00) x 44;'; # at Perl 5.6.1 and 5.8.0 there are 352 built in opcodes (352/8=44) $codewithtrape = <<'EOC'; opendir(DIR,"."); @d=readdir(DIR); closedir(DIR); foreach my $dt (@d) { print "$dt\n"; } EOC use Safe; $safe=new Safe; $safe->deny(qw(opendir)); # deny opendir: You can't use opendir() inside the safe compartment $safe->reval($codefullopmask); # this manipulate the operation mask to full capability of all opcodes $safe->reval($codewithtrap); # now there is NO trap for opendir, and you get the directory!