1*0Sstevel@tonic-gatepackage Safe; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gateuse 5.003_11; 4*0Sstevel@tonic-gateuse strict; 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate$Safe::VERSION = "2.10"; 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate# *** Don't declare any lexicals above this point *** 9*0Sstevel@tonic-gate# 10*0Sstevel@tonic-gate# This function should return a closure which contains an eval that can't 11*0Sstevel@tonic-gate# see any lexicals in scope (apart from __ExPr__ which is unavoidable) 12*0Sstevel@tonic-gate 13*0Sstevel@tonic-gatesub lexless_anon_sub { 14*0Sstevel@tonic-gate # $_[0] is package; 15*0Sstevel@tonic-gate # $_[1] is strict flag; 16*0Sstevel@tonic-gate my $__ExPr__ = $_[2]; # must be a lexical to create the closure that 17*0Sstevel@tonic-gate # can be used to pass the value into the safe 18*0Sstevel@tonic-gate # world 19*0Sstevel@tonic-gate 20*0Sstevel@tonic-gate # Create anon sub ref in root of compartment. 21*0Sstevel@tonic-gate # Uses a closure (on $__ExPr__) to pass in the code to be executed. 22*0Sstevel@tonic-gate # (eval on one line to keep line numbers as expected by caller) 23*0Sstevel@tonic-gate eval sprintf 24*0Sstevel@tonic-gate 'package %s; %s strict; sub { @_=(); eval q[my $__ExPr__;] . $__ExPr__; }', 25*0Sstevel@tonic-gate $_[0], $_[1] ? 'use' : 'no'; 26*0Sstevel@tonic-gate} 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gateuse Carp; 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gateuse Opcode 1.01, qw( 31*0Sstevel@tonic-gate opset opset_to_ops opmask_add 32*0Sstevel@tonic-gate empty_opset full_opset invert_opset verify_opset 33*0Sstevel@tonic-gate opdesc opcodes opmask define_optag opset_to_hex 34*0Sstevel@tonic-gate); 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate*ops_to_opset = \&opset; # Temporary alias for old Penguins 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gatemy $default_root = 0; 40*0Sstevel@tonic-gatemy $default_share = ['*_']; #, '*main::']; 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gatesub new { 43*0Sstevel@tonic-gate my($class, $root, $mask) = @_; 44*0Sstevel@tonic-gate my $obj = {}; 45*0Sstevel@tonic-gate bless $obj, $class; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate if (defined($root)) { 48*0Sstevel@tonic-gate croak "Can't use \"$root\" as root name" 49*0Sstevel@tonic-gate if $root =~ /^main\b/ or $root !~ /^\w[:\w]*$/; 50*0Sstevel@tonic-gate $obj->{Root} = $root; 51*0Sstevel@tonic-gate $obj->{Erase} = 0; 52*0Sstevel@tonic-gate } 53*0Sstevel@tonic-gate else { 54*0Sstevel@tonic-gate $obj->{Root} = "Safe::Root".$default_root++; 55*0Sstevel@tonic-gate $obj->{Erase} = 1; 56*0Sstevel@tonic-gate } 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate # use permit/deny methods instead till interface issues resolved 59*0Sstevel@tonic-gate # XXX perhaps new Safe 'Root', mask => $mask, foo => bar, ...; 60*0Sstevel@tonic-gate croak "Mask parameter to new no longer supported" if defined $mask; 61*0Sstevel@tonic-gate $obj->permit_only(':default'); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate # We must share $_ and @_ with the compartment or else ops such 64*0Sstevel@tonic-gate # as split, length and so on won't default to $_ properly, nor 65*0Sstevel@tonic-gate # will passing argument to subroutines work (via @_). In fact, 66*0Sstevel@tonic-gate # for reasons I don't completely understand, we need to share 67*0Sstevel@tonic-gate # the whole glob *_ rather than $_ and @_ separately, otherwise 68*0Sstevel@tonic-gate # @_ in non default packages within the compartment don't work. 69*0Sstevel@tonic-gate $obj->share_from('main', $default_share); 70*0Sstevel@tonic-gate Opcode::_safe_pkg_prep($obj->{Root}) if($Opcode::VERSION > 1.04); 71*0Sstevel@tonic-gate return $obj; 72*0Sstevel@tonic-gate} 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gatesub DESTROY { 75*0Sstevel@tonic-gate my $obj = shift; 76*0Sstevel@tonic-gate $obj->erase('DESTROY') if $obj->{Erase}; 77*0Sstevel@tonic-gate} 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gatesub erase { 80*0Sstevel@tonic-gate my ($obj, $action) = @_; 81*0Sstevel@tonic-gate my $pkg = $obj->root(); 82*0Sstevel@tonic-gate my ($stem, $leaf); 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate no strict 'refs'; 85*0Sstevel@tonic-gate $pkg = "main::$pkg\::"; # expand to full symbol table name 86*0Sstevel@tonic-gate ($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate # The 'my $foo' is needed! Without it you get an 89*0Sstevel@tonic-gate # 'Attempt to free unreferenced scalar' warning! 90*0Sstevel@tonic-gate my $stem_symtab = *{$stem}{HASH}; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate #warn "erase($pkg) stem=$stem, leaf=$leaf"; 93*0Sstevel@tonic-gate #warn " stem_symtab hash ".scalar(%$stem_symtab)."\n"; 94*0Sstevel@tonic-gate # ", join(', ', %$stem_symtab),"\n"; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate# delete $stem_symtab->{$leaf}; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate my $leaf_glob = $stem_symtab->{$leaf}; 99*0Sstevel@tonic-gate my $leaf_symtab = *{$leaf_glob}{HASH}; 100*0Sstevel@tonic-gate# warn " leaf_symtab ", join(', ', %$leaf_symtab),"\n"; 101*0Sstevel@tonic-gate %$leaf_symtab = (); 102*0Sstevel@tonic-gate #delete $leaf_symtab->{'__ANON__'}; 103*0Sstevel@tonic-gate #delete $leaf_symtab->{'foo'}; 104*0Sstevel@tonic-gate #delete $leaf_symtab->{'main::'}; 105*0Sstevel@tonic-gate# my $foo = undef ${"$stem\::"}{"$leaf\::"}; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if ($action and $action eq 'DESTROY') { 108*0Sstevel@tonic-gate delete $stem_symtab->{$leaf}; 109*0Sstevel@tonic-gate } else { 110*0Sstevel@tonic-gate $obj->share_from('main', $default_share); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 1; 113*0Sstevel@tonic-gate} 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gatesub reinit { 117*0Sstevel@tonic-gate my $obj= shift; 118*0Sstevel@tonic-gate $obj->erase; 119*0Sstevel@tonic-gate $obj->share_redo; 120*0Sstevel@tonic-gate} 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gatesub root { 123*0Sstevel@tonic-gate my $obj = shift; 124*0Sstevel@tonic-gate croak("Safe root method now read-only") if @_; 125*0Sstevel@tonic-gate return $obj->{Root}; 126*0Sstevel@tonic-gate} 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gatesub mask { 130*0Sstevel@tonic-gate my $obj = shift; 131*0Sstevel@tonic-gate return $obj->{Mask} unless @_; 132*0Sstevel@tonic-gate $obj->deny_only(@_); 133*0Sstevel@tonic-gate} 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate# v1 compatibility methods 136*0Sstevel@tonic-gatesub trap { shift->deny(@_) } 137*0Sstevel@tonic-gatesub untrap { shift->permit(@_) } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gatesub deny { 140*0Sstevel@tonic-gate my $obj = shift; 141*0Sstevel@tonic-gate $obj->{Mask} |= opset(@_); 142*0Sstevel@tonic-gate} 143*0Sstevel@tonic-gatesub deny_only { 144*0Sstevel@tonic-gate my $obj = shift; 145*0Sstevel@tonic-gate $obj->{Mask} = opset(@_); 146*0Sstevel@tonic-gate} 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gatesub permit { 149*0Sstevel@tonic-gate my $obj = shift; 150*0Sstevel@tonic-gate # XXX needs testing 151*0Sstevel@tonic-gate $obj->{Mask} &= invert_opset opset(@_); 152*0Sstevel@tonic-gate} 153*0Sstevel@tonic-gatesub permit_only { 154*0Sstevel@tonic-gate my $obj = shift; 155*0Sstevel@tonic-gate $obj->{Mask} = invert_opset opset(@_); 156*0Sstevel@tonic-gate} 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gatesub dump_mask { 160*0Sstevel@tonic-gate my $obj = shift; 161*0Sstevel@tonic-gate print opset_to_hex($obj->{Mask}),"\n"; 162*0Sstevel@tonic-gate} 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gatesub share { 167*0Sstevel@tonic-gate my($obj, @vars) = @_; 168*0Sstevel@tonic-gate $obj->share_from(scalar(caller), \@vars); 169*0Sstevel@tonic-gate} 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gatesub share_from { 172*0Sstevel@tonic-gate my $obj = shift; 173*0Sstevel@tonic-gate my $pkg = shift; 174*0Sstevel@tonic-gate my $vars = shift; 175*0Sstevel@tonic-gate my $no_record = shift || 0; 176*0Sstevel@tonic-gate my $root = $obj->root(); 177*0Sstevel@tonic-gate croak("vars not an array ref") unless ref $vars eq 'ARRAY'; 178*0Sstevel@tonic-gate no strict 'refs'; 179*0Sstevel@tonic-gate # Check that 'from' package actually exists 180*0Sstevel@tonic-gate croak("Package \"$pkg\" does not exist") 181*0Sstevel@tonic-gate unless keys %{"$pkg\::"}; 182*0Sstevel@tonic-gate my $arg; 183*0Sstevel@tonic-gate foreach $arg (@$vars) { 184*0Sstevel@tonic-gate # catch some $safe->share($var) errors: 185*0Sstevel@tonic-gate croak("'$arg' not a valid symbol table name") 186*0Sstevel@tonic-gate unless $arg =~ /^[\$\@%*&]?\w[\w:]*$/ 187*0Sstevel@tonic-gate or $arg =~ /^\$\W$/; 188*0Sstevel@tonic-gate my ($var, $type); 189*0Sstevel@tonic-gate $type = $1 if ($var = $arg) =~ s/^(\W)//; 190*0Sstevel@tonic-gate # warn "share_from $pkg $type $var"; 191*0Sstevel@tonic-gate *{$root."::$var"} = (!$type) ? \&{$pkg."::$var"} 192*0Sstevel@tonic-gate : ($type eq '&') ? \&{$pkg."::$var"} 193*0Sstevel@tonic-gate : ($type eq '$') ? \${$pkg."::$var"} 194*0Sstevel@tonic-gate : ($type eq '@') ? \@{$pkg."::$var"} 195*0Sstevel@tonic-gate : ($type eq '%') ? \%{$pkg."::$var"} 196*0Sstevel@tonic-gate : ($type eq '*') ? *{$pkg."::$var"} 197*0Sstevel@tonic-gate : croak(qq(Can't share "$type$var" of unknown type)); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate $obj->share_record($pkg, $vars) unless $no_record or !$vars; 200*0Sstevel@tonic-gate} 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gatesub share_record { 203*0Sstevel@tonic-gate my $obj = shift; 204*0Sstevel@tonic-gate my $pkg = shift; 205*0Sstevel@tonic-gate my $vars = shift; 206*0Sstevel@tonic-gate my $shares = \%{$obj->{Shares} ||= {}}; 207*0Sstevel@tonic-gate # Record shares using keys of $obj->{Shares}. See reinit. 208*0Sstevel@tonic-gate @{$shares}{@$vars} = ($pkg) x @$vars if @$vars; 209*0Sstevel@tonic-gate} 210*0Sstevel@tonic-gatesub share_redo { 211*0Sstevel@tonic-gate my $obj = shift; 212*0Sstevel@tonic-gate my $shares = \%{$obj->{Shares} ||= {}}; 213*0Sstevel@tonic-gate my($var, $pkg); 214*0Sstevel@tonic-gate while(($var, $pkg) = each %$shares) { 215*0Sstevel@tonic-gate # warn "share_redo $pkg\:: $var"; 216*0Sstevel@tonic-gate $obj->share_from($pkg, [ $var ], 1); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate} 219*0Sstevel@tonic-gatesub share_forget { 220*0Sstevel@tonic-gate delete shift->{Shares}; 221*0Sstevel@tonic-gate} 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gatesub varglob { 224*0Sstevel@tonic-gate my ($obj, $var) = @_; 225*0Sstevel@tonic-gate no strict 'refs'; 226*0Sstevel@tonic-gate return *{$obj->root()."::$var"}; 227*0Sstevel@tonic-gate} 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gatesub reval { 231*0Sstevel@tonic-gate my ($obj, $expr, $strict) = @_; 232*0Sstevel@tonic-gate my $root = $obj->{Root}; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate my $evalsub = lexless_anon_sub($root,$strict, $expr); 235*0Sstevel@tonic-gate return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); 236*0Sstevel@tonic-gate} 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gatesub rdo { 239*0Sstevel@tonic-gate my ($obj, $file) = @_; 240*0Sstevel@tonic-gate my $root = $obj->{Root}; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate my $evalsub = eval 243*0Sstevel@tonic-gate sprintf('package %s; sub { @_ = (); do $file }', $root); 244*0Sstevel@tonic-gate return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); 245*0Sstevel@tonic-gate} 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate1; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate__END__ 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate=head1 NAME 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gateSafe - Compile and execute code in restricted compartments 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate=head1 SYNOPSIS 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate use Safe; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate $compartment = new Safe; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate $compartment->permit(qw(time sort :browse)); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate $result = $compartment->reval($unsafe_code); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate=head1 DESCRIPTION 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gateThe Safe extension module allows the creation of compartments 269*0Sstevel@tonic-gatein which perl code can be evaluated. Each compartment has 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate=over 8 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate=item a new namespace 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gateThe "root" of the namespace (i.e. "main::") is changed to a 276*0Sstevel@tonic-gatedifferent package and code evaluated in the compartment cannot 277*0Sstevel@tonic-gaterefer to variables outside this namespace, even with run-time 278*0Sstevel@tonic-gateglob lookups and other tricks. 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gateCode which is compiled outside the compartment can choose to place 281*0Sstevel@tonic-gatevariables into (or I<share> variables with) the compartment's namespace 282*0Sstevel@tonic-gateand only that data will be visible to code evaluated in the 283*0Sstevel@tonic-gatecompartment. 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gateBy default, the only variables shared with compartments are the 286*0Sstevel@tonic-gate"underscore" variables $_ and @_ (and, technically, the less frequently 287*0Sstevel@tonic-gateused %_, the _ filehandle and so on). This is because otherwise perl 288*0Sstevel@tonic-gateoperators which default to $_ will not work and neither will the 289*0Sstevel@tonic-gateassignment of arguments to @_ on subroutine entry. 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate=item an operator mask 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gateEach compartment has an associated "operator mask". Recall that 294*0Sstevel@tonic-gateperl code is compiled into an internal format before execution. 295*0Sstevel@tonic-gateEvaluating perl code (e.g. via "eval" or "do 'file'") causes 296*0Sstevel@tonic-gatethe code to be compiled into an internal format and then, 297*0Sstevel@tonic-gateprovided there was no error in the compilation, executed. 298*0Sstevel@tonic-gateCode evaluated in a compartment compiles subject to the 299*0Sstevel@tonic-gatecompartment's operator mask. Attempting to evaluate code in a 300*0Sstevel@tonic-gatecompartment which contains a masked operator will cause the 301*0Sstevel@tonic-gatecompilation to fail with an error. The code will not be executed. 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gateThe default operator mask for a newly created compartment is 304*0Sstevel@tonic-gatethe ':default' optag. 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gateIt is important that you read the Opcode(3) module documentation 307*0Sstevel@tonic-gatefor more information, especially for detailed definitions of opnames, 308*0Sstevel@tonic-gateoptags and opsets. 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gateSince it is only at the compilation stage that the operator mask 311*0Sstevel@tonic-gateapplies, controlled access to potentially unsafe operations can 312*0Sstevel@tonic-gatebe achieved by having a handle to a wrapper subroutine (written 313*0Sstevel@tonic-gateoutside the compartment) placed into the compartment. For example, 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate $cpt = new Safe; 316*0Sstevel@tonic-gate sub wrapper { 317*0Sstevel@tonic-gate # vet arguments and perform potentially unsafe operations 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate $cpt->share('&wrapper'); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate=back 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate=head1 WARNING 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gateThe authors make B<no warranty>, implied or otherwise, about the 327*0Sstevel@tonic-gatesuitability of this software for safety or security purposes. 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gateThe authors shall not in any case be liable for special, incidental, 330*0Sstevel@tonic-gateconsequential, indirect or other similar damages arising from the use 331*0Sstevel@tonic-gateof this software. 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gateYour mileage will vary. If in any doubt B<do not use it>. 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate=head2 RECENT CHANGES 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gateThe interface to the Safe module has changed quite dramatically since 339*0Sstevel@tonic-gateversion 1 (as supplied with Perl5.002). Study these pages carefully if 340*0Sstevel@tonic-gateyou have code written to use Safe version 1 because you will need to 341*0Sstevel@tonic-gatemakes changes. 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate=head2 Methods in class Safe 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gateTo create a new compartment, use 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate $cpt = new Safe; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gateOptional argument is (NAMESPACE), where NAMESPACE is the root namespace 351*0Sstevel@tonic-gateto use for the compartment (defaults to "Safe::Root0", incremented for 352*0Sstevel@tonic-gateeach new compartment). 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gateNote that version 1.00 of the Safe module supported a second optional 355*0Sstevel@tonic-gateparameter, MASK. That functionality has been withdrawn pending deeper 356*0Sstevel@tonic-gateconsideration. Use the permit and deny methods described below. 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gateThe following methods can then be used on the compartment 359*0Sstevel@tonic-gateobject returned by the above constructor. The object argument 360*0Sstevel@tonic-gateis implicit in each case. 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate=over 8 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate=item permit (OP, ...) 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gatePermit the listed operators to be used when compiling code in the 368*0Sstevel@tonic-gatecompartment (in I<addition> to any operators already permitted). 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate=item permit_only (OP, ...) 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gatePermit I<only> the listed operators to be used when compiling code in 373*0Sstevel@tonic-gatethe compartment (I<no> other operators are permitted). 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate=item deny (OP, ...) 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gateDeny the listed operators from being used when compiling code in the 378*0Sstevel@tonic-gatecompartment (other operators may still be permitted). 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate=item deny_only (OP, ...) 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gateDeny I<only> the listed operators from being used when compiling code 383*0Sstevel@tonic-gatein the compartment (I<all> other operators will be permitted). 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate=item trap (OP, ...) 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate=item untrap (OP, ...) 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gateThe trap and untrap methods are synonyms for deny and permit 390*0Sstevel@tonic-gaterespectfully. 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate=item share (NAME, ...) 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gateThis shares the variable(s) in the argument list with the compartment. 395*0Sstevel@tonic-gateThis is almost identical to exporting variables using the L<Exporter> 396*0Sstevel@tonic-gatemodule. 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gateEach NAME must be the B<name> of a non-lexical variable, typically 399*0Sstevel@tonic-gatewith the leading type identifier included. A bareword is treated as a 400*0Sstevel@tonic-gatefunction name. 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gateExamples of legal names are '$foo' for a scalar, '@foo' for an 403*0Sstevel@tonic-gatearray, '%foo' for a hash, '&foo' or 'foo' for a subroutine and '*foo' 404*0Sstevel@tonic-gatefor a glob (i.e. all symbol table entries associated with "foo", 405*0Sstevel@tonic-gateincluding scalar, array, hash, sub and filehandle). 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gateEach NAME is assumed to be in the calling package. See share_from 408*0Sstevel@tonic-gatefor an alternative method (which share uses). 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate=item share_from (PACKAGE, ARRAYREF) 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gateThis method is similar to share() but allows you to explicitly name the 413*0Sstevel@tonic-gatepackage that symbols should be shared from. The symbol names (including 414*0Sstevel@tonic-gatetype characters) are supplied as an array reference. 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate $safe->share_from('main', [ '$foo', '%bar', 'func' ]); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate=item varglob (VARNAME) 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gateThis returns a glob reference for the symbol table entry of VARNAME in 422*0Sstevel@tonic-gatethe package of the compartment. VARNAME must be the B<name> of a 423*0Sstevel@tonic-gatevariable without any leading type marker. For example, 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate $cpt = new Safe 'Root'; 426*0Sstevel@tonic-gate $Root::foo = "Hello world"; 427*0Sstevel@tonic-gate # Equivalent version which doesn't need to know $cpt's package name: 428*0Sstevel@tonic-gate ${$cpt->varglob('foo')} = "Hello world"; 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate=item reval (STRING) 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gateThis evaluates STRING as perl code inside the compartment. 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gateThe code can only see the compartment's namespace (as returned by the 436*0Sstevel@tonic-gateB<root> method). The compartment's root package appears to be the 437*0Sstevel@tonic-gateC<main::> package to the code inside the compartment. 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gateAny attempt by the code in STRING to use an operator which is not permitted 440*0Sstevel@tonic-gateby the compartment will cause an error (at run-time of the main program 441*0Sstevel@tonic-gatebut at compile-time for the code in STRING). The error is of the form 442*0Sstevel@tonic-gate"'%s' trapped by operation mask...". 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gateIf an operation is trapped in this way, then the code in STRING will 445*0Sstevel@tonic-gatenot be executed. If such a trapped operation occurs or any other 446*0Sstevel@tonic-gatecompile-time or return error, then $@ is set to the error message, just 447*0Sstevel@tonic-gateas with an eval(). 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gateIf there is no error, then the method returns the value of the last 450*0Sstevel@tonic-gateexpression evaluated, or a return statement may be used, just as with 451*0Sstevel@tonic-gatesubroutines and B<eval()>. The context (list or scalar) is determined 452*0Sstevel@tonic-gateby the caller as usual. 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gateThis behaviour differs from the beta distribution of the Safe extension 455*0Sstevel@tonic-gatewhere earlier versions of perl made it hard to mimic the return 456*0Sstevel@tonic-gatebehaviour of the eval() command and the context was always scalar. 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gateSome points to note: 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gateIf the entereval op is permitted then the code can use eval "..." to 461*0Sstevel@tonic-gate'hide' code which might use denied ops. This is not a major problem 462*0Sstevel@tonic-gatesince when the code tries to execute the eval it will fail because the 463*0Sstevel@tonic-gateopmask is still in effect. However this technique would allow clever, 464*0Sstevel@tonic-gateand possibly harmful, code to 'probe' the boundaries of what is 465*0Sstevel@tonic-gatepossible. 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gateAny string eval which is executed by code executing in a compartment, 468*0Sstevel@tonic-gateor by code called from code executing in a compartment, will be eval'd 469*0Sstevel@tonic-gatein the namespace of the compartment. This is potentially a serious 470*0Sstevel@tonic-gateproblem. 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gateConsider a function foo() in package pkg compiled outside a compartment 473*0Sstevel@tonic-gatebut shared with it. Assume the compartment has a root package called 474*0Sstevel@tonic-gate'Root'. If foo() contains an eval statement like eval '$foo = 1' then, 475*0Sstevel@tonic-gatenormally, $pkg::foo will be set to 1. If foo() is called from the 476*0Sstevel@tonic-gatecompartment (by whatever means) then instead of setting $pkg::foo, the 477*0Sstevel@tonic-gateeval will actually set $Root::pkg::foo. 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gateThis can easily be demonstrated by using a module, such as the Socket 480*0Sstevel@tonic-gatemodule, which uses eval "..." as part of an AUTOLOAD function. You can 481*0Sstevel@tonic-gate'use' the module outside the compartment and share an (autoloaded) 482*0Sstevel@tonic-gatefunction with the compartment. If an autoload is triggered by code in 483*0Sstevel@tonic-gatethe compartment, or by any code anywhere that is called by any means 484*0Sstevel@tonic-gatefrom the compartment, then the eval in the Socket module's AUTOLOAD 485*0Sstevel@tonic-gatefunction happens in the namespace of the compartment. Any variables 486*0Sstevel@tonic-gatecreated or used by the eval'd code are now under the control of 487*0Sstevel@tonic-gatethe code in the compartment. 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gateA similar effect applies to I<all> runtime symbol lookups in code 490*0Sstevel@tonic-gatecalled from a compartment but not compiled within it. 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate=item rdo (FILENAME) 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gateThis evaluates the contents of file FILENAME inside the compartment. 497*0Sstevel@tonic-gateSee above documentation on the B<reval> method for further details. 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate=item root (NAMESPACE) 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gateThis method returns the name of the package that is the root of the 502*0Sstevel@tonic-gatecompartment's namespace. 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gateNote that this behaviour differs from version 1.00 of the Safe module 505*0Sstevel@tonic-gatewhere the root module could be used to change the namespace. That 506*0Sstevel@tonic-gatefunctionality has been withdrawn pending deeper consideration. 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate=item mask (MASK) 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gateThis is a get-or-set method for the compartment's operator mask. 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gateWith no MASK argument present, it returns the current operator mask of 513*0Sstevel@tonic-gatethe compartment. 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gateWith the MASK argument present, it sets the operator mask for the 516*0Sstevel@tonic-gatecompartment (equivalent to calling the deny_only method). 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate=back 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate=head2 Some Safety Issues 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gateThis section is currently just an outline of some of the things code in 524*0Sstevel@tonic-gatea compartment might do (intentionally or unintentionally) which can 525*0Sstevel@tonic-gatehave an effect outside the compartment. 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate=over 8 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate=item Memory 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gateConsuming all (or nearly all) available memory. 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate=item CPU 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gateCausing infinite loops etc. 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate=item Snooping 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gateCopying private information out of your system. Even something as 540*0Sstevel@tonic-gatesimple as your user name is of value to others. Much useful information 541*0Sstevel@tonic-gatecould be gleaned from your environment variables for example. 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate=item Signals 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gateCausing signals (especially SIGFPE and SIGALARM) to affect your process. 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gateSetting up a signal handler will need to be carefully considered 548*0Sstevel@tonic-gateand controlled. What mask is in effect when a signal handler 549*0Sstevel@tonic-gategets called? If a user can get an imported function to get an 550*0Sstevel@tonic-gateexception and call the user's signal handler, does that user's 551*0Sstevel@tonic-gaterestricted mask get re-instated before the handler is called? 552*0Sstevel@tonic-gateDoes an imported handler get called with its original mask or 553*0Sstevel@tonic-gatethe user's one? 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate=item State Changes 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gateOps such as chdir obviously effect the process as a whole and not just 558*0Sstevel@tonic-gatethe code in the compartment. Ops such as rand and srand have a similar 559*0Sstevel@tonic-gatebut more subtle effect. 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate=back 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate=head2 AUTHOR 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gateOriginally designed and implemented by Malcolm Beattie, 566*0Sstevel@tonic-gatembeattie@sable.ox.ac.uk. 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gateReworked to use the Opcode module and other changes added by Tim Bunce 569*0Sstevel@tonic-gateE<lt>F<Tim.Bunce@ig.co.uk>E<gt>. 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate=cut 572*0Sstevel@tonic-gate 573