diff --git a/jail_root b/jail_root index fe69764..afea70c 160000 --- a/jail_root +++ b/jail_root @@ -1 +1 @@ -Subproject commit fe69764c77d5f9047c006de6944d4a36b46e510e +Subproject commit afea70ce7a9ce085620a20101d85af40eca16f92 diff --git a/lib/EvalServer.pm b/lib/EvalServer.pm index 6b7b416..52d88a6 100644 --- a/lib/EvalServer.pm +++ b/lib/EvalServer.pm @@ -8,20 +8,7 @@ use POE::Filter::Line; use POE::Filter::Stream; use POE::Wheel::Run; use strict; -use Config; -use Sys::Linux::Namespace; -use Sys::Linux::Mount qw/:all/; -my %sig_map; -use FindBin; - -do { - my @sig_names = split ' ', $Config{sig_name}; - my @sig_nums = split ' ', $Config{sig_num}; - @sig_map{@sig_nums} = map {'SIG' . $_} @sig_names; - $sig_map{31} = "SIGSYS (Illegal Syscall)"; -}; - -my $namespace = Sys::Linux::Namespace->new(private_pid => 1, no_proc => 1, private_mount => 1, private_uts => 1, private_ipc => 1, private_sysvsem => 1); +use EvalServer::Sandbox; sub start { my( $class ) = @_; @@ -54,31 +41,8 @@ sub spawn_eval { } warn "Spawning Eval: $args->{code}\n"; my $wheel = POE::Wheel::Run->new( - Program => sub { - $namespace->run(code => sub { - mount($FindBin::Bin."/../jail_root", $FindBin::Bin."/../jail", undef, MS_BIND|MS_RDONLY, undef); - mount("tmpfs", $FindBin::Bin."/../jail/tmp", "tmpfs", 0, {size => "16m"}); - mount("tmpfs", $FindBin::Bin."/../jail/tmp", "tmpfs", MS_PRIVATE, {size => "16m"}); - mount("/lib64", $FindBin::Bin."/../jail/lib64", undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); - mount("/lib", $FindBin::Bin."/../jail/lib", undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); - mount("/usr/bin", $FindBin::Bin."/../jail/usr/bin", undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); - mount("/usr/lib", $FindBin::Bin."/../jail/usr/lib", undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); - mount("/home/ryan/perl5", $FindBin::Bin."/../jail/perl5", undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); - #my $q = qx|ls -lh /home/ryan/bots/perlbuut/jail/perl5/perlbrew/perls/perl-5.18*/bin|; - #print $q; - - system($^X, $filename); - my ($exit, $signal) = (($?&0xFF00)>>8, $?&0xFF); - - if ($exit) { - print "[Exited $exit]"; - } elsif ($signal) { - my $signame = $sig_map{$signal} // $signal; - print "[Died $signame]"; - } - }); - }, - ProgramArgs => [ ], + Program => \&EvalServer::Sandbox::run_eval, + ProgramArgs => [ ], CloseOnCall => 1, #Make sure all of the filehandles are closed. Priority => 10, #Let's be nice! diff --git a/lib/EvalServer/Sandbox.pm b/lib/EvalServer/Sandbox.pm new file mode 100644 index 0000000..a7f9101 --- /dev/null +++ b/lib/EvalServer/Sandbox.pm @@ -0,0 +1,73 @@ +package EvalServer::Sandbox; + +use strict; +use warnings; + +use Config; +use Sys::Linux::Namespace; +use Sys::Linux::Mount qw/:all/; +my %sig_map; +use FindBin; + +do { + my @sig_names = split ' ', $Config{sig_name}; + my @sig_nums = split ' ', $Config{sig_num}; + @sig_map{@sig_nums} = map {'SIG' . $_} @sig_names; + $sig_map{31} = "SIGSYS (Illegal Syscall)"; +}; + +my $namespace = Sys::Linux::Namespace->new(private_pid => 1, no_proc => 1, private_mount => 1, private_uts => 1, private_ipc => 1, private_sysvsem => 1); + +# {files => [ +# {filename => '...', +# contents => '...',}, +# ...,], +# main_file => 'filename', +# main_language => '', +# } +# + +sub run_eval { + my $code = shift; # TODO this should be more than just code + my $jail_path = $FindBin::Bin."/../jail"; + my $jail_root_path = $FindBin::Bin."/../jail_root"; + + my $filename = '/eval/elib/eval.pl'; + + $namespace->run(code => sub { + my @binds = ( + {src => $jail_root_path, target => "/"}, + {src => "/lib64", target => "/lib64"}, + {src => "/lib", target => "/lib"}, + {src => "/usr/lib", target => "/usr/lib"}, + {src => "/usr/bin", target => "/usr/bin"}, + {src => "/home/ryan/perl5", target => "/perl5"}, + {src => "/home/ryan/perl5", target => "/home/ryan/perl5"}, + {src => $FindBin::Bin."/../lib", target => "/eval/elib"}, + ); + + for my $bind (@binds) { + # printf "mount: %s => %s\n", $bind->{src}, $jail_path . $bind->{target}; + mount($bind->{src}, $jail_path . $bind->{target}, undef, MS_BIND|MS_PRIVATE|MS_RDONLY, undef); + } + + mount("tmpfs", $FindBin::Bin."/../jail/tmp", "tmpfs", 0, {size => "16m"}); + mount("tmpfs", $FindBin::Bin."/../jail/tmp", "tmpfs", MS_PRIVATE, {size => "16m"}); + + + chdir($jail_path) or die "Jail not made, see bin/makejail.sh"; + chroot($jail_path) or die $!; + + system("/perl5/perlbrew/perls/perlbot-inuse/bin/perl", $filename); + my ($exit, $signal) = (($?&0xFF00)>>8, $?&0xFF); + + if ($exit) { + print "[Exited $exit]"; + } elsif ($signal) { + my $signame = $sig_map{$signal} // $signal; + print "[Died $signame]"; + } + }); +} + +1; diff --git a/lib/eval.pl b/lib/eval.pl index e24708b..7081583 100755 --- a/lib/eval.pl +++ b/lib/eval.pl @@ -328,24 +328,13 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem chomp $q; $q }; - my $code; -# if ($type ne 'perl4') { # Perl 4 has special needs. It rides on the short bus. - $code = do {local $/; }; - # redirect STDIN to /dev/null, to avoid warnings in convoluted cases. - # we have to leave this open for perl4, so only do this for other systems - open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!"; -# } - -# print Dumper({type => $type, code => $code}); - - # Close every other filehandle we may have open - # this is probably legacy code at this point since it was used - # inside the original bb2 which forked to execute this code. - opendir my $dh, "/proc/self/fd" or die $!; - while(my $fd = readdir($dh)) { next unless $fd > 2; POSIX::close($fd) } + my $code = do {local $/; }; + # redirect STDIN to /dev/null, to avoid warnings in convoluted cases. + # we have to leave this open for perl4, so only do this for other systems + open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!"; # Get the nobody uid before we chroot. - my $nobody_uid = getpwnam("nobody"); + my $nobody_uid = 65534; #getpwnam("nobody"); die "Error, can't find a uid for 'nobody'. Replace with someone who exists" unless $nobody_uid; # Set the CPU LIMIT. @@ -362,27 +351,23 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem # } # The chroot section - chdir($FindBin::Bin."/../jail") or die "Jail not made, see bin/makejail.sh"; - - - chroot(".") or die $!; chdir("/eval") or die $!; # It's now safe for us to do this so that we can load modules and files provided by the user push @INC, "/eval/lib"; - if ($< == 0) { - # Here's where we actually drop our root privilege - $)="$nobody_uid $nobody_uid"; - $(=$nobody_uid; - $<=$>=$nobody_uid; - POSIX::setgid($nobody_uid); #We just assume the uid is the same as the gid. Hot. + if ($< == 0) { + # Here's where we actually drop our root privilege + $)="$nobody_uid $nobody_uid"; + $(=$nobody_uid; + $<=$>=$nobody_uid; + POSIX::setgid($nobody_uid); #We just assume the uid is the same as the gid. Hot. - die "Failed to drop to nobody" - if $> != $nobody_uid - or $< != $nobody_uid; - } + die "Failed to drop to nobody" + if $> != $nobody_uid + or $< != $nobody_uid; + } my $kilo = 1024; my $meg = $kilo * $kilo; @@ -413,16 +398,14 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem ) or die "Failed to set rlimit: $!"; - %ENV=(TZ=>'Asia/Pyongyang'); + %ENV=(TZ=>'Asia/Pyongyang'); #setrlimit(RLIMIT_MSGQUEUE,100,100); die "Failed to drop root: $<" if $< == 0; # close STDIN; -# Setup SECCOMP for us -get_seccomp($type); - - + # Setup SECCOMP for us + get_seccomp($type); # Chomp code.. $code =~ s/\s*$//;