Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe compartments with shared symbols causes Perl debugger to croak

Tags:

perl

I'm using Perl 5.22.1. Safe 2.39

I'm debugging a program which incidentally runs code in a Safe compartment. The code executes a subroutine shared from another package. I'm not interested in the code running in the compartment, but cannot avoid its execution. The Perl debugger croaks inside the compartment when the shared subroutine is executed.

Here's test code:

use warnings;
use strict;

use Safe;

sub MyPkg::foo { 33; }

my $safe= Safe->new;
$safe->share_from( 'MyPkg', [ '&foo' ] );
print $safe->reval(q[foo]), "\n";
print STDERR $@ if $@;

When run directly, I get the expected output:

% perl tdebug.pl
33

However, when run under the Perl debugger, the debugger is very unhappy:

% perl -d tdebug.pl

Loading DB routines from perl5db.pl version 1.49
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(tdebug.pl:8):    my $safe= Safe->new;
                                                                                                                                                                   DB<1> c

Undefined subroutine &MyPkg::foo called at [...]/lib/5.22.1/perl5db.pl line 4183.
Debugged program terminated.                       

I deduce that the debugger is attempting to execute the shared subroutine by using its original name, and since that is not available in the compartment, cannot access it.

I can think of two approaches to side step this:

  1. Rename the subrefs so that caller, etc see them as being in the compartment (e.g. with Sub::Name::subname )
  2. Instruct the debugger to not insert itself into the execution of code in Safe compartments

I've attempted to implement the first approach, as follows,

use warnings;
use strict;

use Safe;

{ package MyPkg;
  sub foo { 33; }
}

use Sub::Name;
use Opcode 'empty_opset';

my $safe= Safe->new;
$safe->mask( empty_opset() );
$safe->share_from( 'MyPkg', [ '&foo' ] );
$safe->reval( q[use Sub::Name;]) or die "use Sub::Name: ", $@;
$safe->reval( q[subname foo => \&foo; 1;]) or die "subname call", $@;
$safe->permit_only( ':default' );
print $safe->reval( q[ foo ] ), "\n";
print STDERR $@ if $@;

but am stymied by the following run time error:

use Sub::Name: Can't load module Sub::Name, dynamic loading not available in this perl.
  (You may need to build a new perl executable which either supports
  dynamic loading or has the Sub::Name module statically linked into it.)
 at (eval 6) line 1.
Compilation failed in require at (eval 6) line 1.
BEGIN failed--compilation aborted at (eval 6) line 1.

As for approach 2, would anyone have any ideas on how to implement that?

like image 387
Diab Jerius Avatar asked Mar 16 '17 16:03

Diab Jerius


1 Answers

Forget about Sub::Name trickery for the debugger. It's also a very broken module. Simple glob assignment (core aliases) or coderef assignment is always easier.

As @ThisSuitIsBlackNot already found out, you need to add more shares, the one from the main:: stash to the loaded module, and need to use the full name in the safe compartment.

use warnings;
use strict;

use Safe;

sub MyPkg::foo { 33; }

my $safe= Safe->new;
$safe->share_from( 'MyPkg', [ '&foo' ] );
$safe->share_from( 'main', [ 'MyPkg::foo' ] );
print $safe->reval(q[MyPkg::foo]);
print STDERR $@ if $@;
like image 114
rurban Avatar answered Sep 22 '22 15:09

rurban