diff --git a/bin/makejail.sh b/bin/makejail.sh new file mode 100755 index 0000000..25840c1 --- /dev/null +++ b/bin/makejail.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +mkdir -p jail +mkdir -p jail/perl5 +mkdir -p jail/lib +mkdir -p jail/usr/lib +mkdir -p jail/dev +mknod jail/dev/urandom c 1 9 diff --git a/bin/mountjail.sh b/bin/mountjail.sh new file mode 100644 index 0000000..60700db --- /dev/null +++ b/bin/mountjail.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +mount -o bind /home/ryan/perl5 jail/perl5 +mount -o bind /lib jail/lib +mount -o bind /usr/lib jail/usr/lib diff --git a/cpanfile b/cpanfile index 357d31b..70fe8bb 100644 --- a/cpanfile +++ b/cpanfile @@ -68,3 +68,10 @@ requires 'Math::BigRat' => 0; requires 'indirect' => 0; requires 'Moo' => 0; requires 'autovivification' => 0; + +requires 'Linux::Seccomp' => 0; +requires 'Cwd' => 0; +# requires 'Algorithm::Permute' => 0; +requires 'File::Slurper' => 0; +requires 'Path::Tiny' => 0; + diff --git a/lib/eval.pl b/lib/eval.pl index bf79335..a624f47 100755 --- a/lib/eval.pl +++ b/lib/eval.pl @@ -1,4 +1,4 @@ -#!perl +#!/usr/bin/env perl #use lib '/home/ryan/perl5/lib/perl5/i686-linux'; #use lib '/home/ryan/perl5/lib/perl5'; @@ -9,75 +9,98 @@ use Scalar::Util; #Required by Data::Dumper use BSD::Resource; use File::Glob; use POSIX; +use List::Util qw/reduce/; +use Cwd; +use FindBin; -use List::Util; -use List::MoreUtils; -use List::UtilsBy; -use Data::Munge; -use Scalar::MoreUtils; -use Regexp::Common; -use Encode; -use Digest::MD5; -use Digest::SHA; -use DateTime; -# use DateTimeX::Easy; -use Date::Parse; -use Time::Piece; -use Time::HiRes; -use URI; -use URI::Encode; -# use Rand::MersenneTwister; -use Mojo::DOM; -use Mojo::DOM::HTML; -use Mojo::DOM::CSS; -#use Mojo::Collection; -#use YAPE::Regex::Explain; - -require Function::Parameters; -require experimental; -#require "if.pm"; -#use JSON; -#use JSON::XS; -require Cpanel::JSON::XS; -require JSON::MaybeXS; -require JSON::XS; -require JSON; - -require Moo; -require Moo::Object; -require Moo::Role; -require Moose; -require Moose::Role; -require Method::Generate::Accessor; -require Method::Generate::Constructor; -require MooseX::Declare; -# eval "use MooseX::Declare; class LoadAllMooseXDeclare { has dongs => ( is => ro, isa => 'Int' ); };"; -require "utf8_heavy.pl"; -use arybase; -use Errno; - -require indirect; - -eval 'use bigint; use Math::BigInt; 1e1000'; -eval 'use Math::BigFloat; 1.1e1000'; -eval 'use Math::BigRat; 1e1000'; -require autovivification; - -{ -my $len = eval "lc 'ẞ'"; -warn $@ if $@; -} +# Modules expected by many evals, load them now to avoid typing in channel +use Encode qw/encode decode/; +use IO::String; +use File::Slurper qw/read_text/; # save the old stdout, we're going to clobber it soon. STDOUT my $oldout; my $outbuffer = ""; open($oldout, ">&STDOUT") or die "Can't dup STDOUT: $!"; -open(my $stdh, ">", \$outbuffer) +open(my $stdh, ">", \$outbuffer) or die "Can't dup to buffer: $!"; select($stdh); $|++; #*STDOUT = $stdh; +sub get_seccomp { + use Linux::Seccomp ':all'; + my $seccomp = Linux::Seccomp->new(SCMP_ACT_KILL); + ##### set seccomp + # + # Rules should only allow: + # 1. open as read + # 2. write to stderr/stdout + # 3. exit + # 4. close file handle + # 5. random syscall + # 6. read + # 7. seek +# 8. fstat/fcntl +# 9. brk +# 10. + + my $rule_add = sub { + my $name = shift; + $seccomp->rule_add(SCMP_ACT_ALLOW, syscall_resolve_name($name), @_); + }; + + $rule_add->(write => [0, '==', 2]); # STDERR + $rule_add->(write => [0, '==', 1]); # STDOUT + + #mmap(NULL, 2112544, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 7, 0) = 0x7efedad0e000 + #mprotect(0x7efedad12000, 2093056, PROT_NONE) = 0 + #mmap(0x7efedaf11000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 7, 0x3000) = 0x7efedaf11000 + ## MMAP? I don't know what it's being used for exactly. I'll leave it out and see what happens + # Used when loading executable code. Might need to figure out what to do to make it more secure? + # also seems to be used when freeing/allocating large blocks of memory, as you'd expect + $rule_add->(mmap => ); + $rule_add->(munmap => ); + $rule_add->(mprotect =>); + + # These are the allowed modes on open, allow that to work in any combo + my ($O_DIRECTORY, $O_CLOEXEC, $O_NOCTTY) = (00200000, 02000000, 00000400); + my @allowed_open_modes = (&POSIX::O_RDONLY, &POSIX::O_NONBLOCK, $O_DIRECTORY, $O_CLOEXEC, $O_NOCTTY); + + # this annoying bitch of code is because Algorithm::Permute doesn't work with newer perls + # Also this ends up more efficient. We skip 0 because it's redundant + for my $b (1..(2**@allowed_open_modes) - 1) { + my $q = 1; + my $mode = 0; + #printf "%04b: ", $b; + do { + if ($q & $b) { + my $r = int(log($q)/log(2)+0.5); # get the thing + + $mode |= $allowed_open_modes[$r]; + + #print "$r"; + } + $q <<= 1; + } while ($q <= $b); + + $rule_add->(open => [1, '==', $mode]); + $rule_add->(openat => [2, '==', $mode]); + #print " => $mode\n"; + } + + # 4352 ioctl(4, TCGETS, 0x7ffd10963820) = -1 ENOTTY (Inappropriate ioctl for device) + $rule_add->(ioctl => [1, '==', 0x5401]); # This happens on opened files for some reason? wtf + + my @blind_syscalls = qw/read exit exit_group brk lseek fstat fcntl stat rt_sigaction rt_sigprocmask geteuid getuid getcwd close getdents getgid getegid getgroups lstat/; + + for my $syscall (@blind_syscalls) { + $rule_add->($syscall); + } + + $seccomp->load; +} + no warnings; # This sub is defined here so that it is defined before the 'use charnames' @@ -85,7 +108,7 @@ no warnings; # deparse output being much longer than it should be. sub deparse_perl_code { my( $code ) = @_; - my $sub; + my $sub; { no strict; no warnings; no charnames; $sub = eval "use $]; sub{ $code\n }"; @@ -141,14 +164,14 @@ use Tie::Hash::NamedCapture; # # Evil K20 stuff # BEGIN { # local $@; -# eval "use Language::K20;"; +# eval "use Language::K20;"; # unless( $@ ) { # Language::K20::k20eval( "2+2\n" ); # This eval loads the dynamic components before the chroot. # # Note that k20eval always tries to output to stdout so we # # must end the command with a \n to prevent this output. # } # } -# +# # BEGIN { chdir "var/"; $0="../$0"; } # CHDIR to stop inline from creating stupid _Inline directories everywhere # # Inline::Lua doesn't seem to provide an eval function. SIGH. # BEGIN { eval 'use Inline Lua => "function lua_eval(str) return loadstring(str) end";'; } @@ -166,9 +189,6 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem my $code = do { local $/; }; - # Kill @INC to shorten errors; - @INC = ('.'); - # 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. @@ -193,11 +213,7 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem } # The chroot section - chdir("./jail") or - do { - mkdir "./jail"; - chdir "./jail" or die "Failed to find a jail live in, couldn't make one either: $!\n"; - }; + chdir($FindBin::Bin."/../jail") or die "Jail not made, see bin/makejail.sh"; # redirect STDIN to /dev/null, to avoid warnings in convoluted cases. open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!"; @@ -209,11 +225,12 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem $(=$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; - + my $kilo = 1024; my $meg = $kilo * $kilo; my $limit = 300 * $meg; @@ -227,11 +244,11 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem and setrlimit(RLIMIT_NPROC, 1,1) and - setrlimit(RLIMIT_NOFILE, 0,0) + setrlimit(RLIMIT_NOFILE, 20,20) and - setrlimit(RLIMIT_OFILE, 0,0) + setrlimit(RLIMIT_OFILE, 20,20) and - setrlimit(RLIMIT_OPEN_MAX,0,0) + setrlimit(RLIMIT_OPEN_MAX,20,20) and setrlimit(RLIMIT_LOCKS, 0,0) and @@ -239,7 +256,7 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem and setrlimit(RLIMIT_MEMLOCK,100,100) and - setrlimit(RLIMIT_CPU, 10,10) + setrlimit(RLIMIT_CPU, 10, 10) ) or die "Failed to set rlimit: $!"; @@ -249,6 +266,9 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem die "Failed to drop root: $<" if $< == 0; # close STDIN; +# Setup SECCOMP for us +get_seccomp(); + $code =~ s/^\s*(\w+)\s*// or die "Failed to parse code type! $code"; my $type = $1; @@ -299,8 +319,8 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem sub perl_code { my( $code ) = @_; local $@; - local @INC = ('.'); - + local @INC = map {s|/home/ryan||r} @INC; + local $_; my $ret; @@ -331,85 +351,85 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem # sub javascript_code { # my( $code ) = @_; # local $@; -# +# # my $js = JavaScript::V8::Context->new; -# +# # # Set up the Environment for ENVJS # $js->bind("print", sub { print @_ } ); # $js->bind("write", sub { print @_ } ); -# +# # # for( qw/log debug info warn error/ ) { # # $js->eval("Envjs.$_=function(x){}"); # # } -# +# # # $js->eval($JSENV_CODE) or die $@; -# +# # $code =~ s/(["\\])/\\$1/g; # my $rcode = qq{write(eval("$code"))}; -# -# -# +# +# +# # my $out = eval { $js->eval($rcode) }; -# +# # if( $@ ) { print "ERROR: $@"; } # else { print encode_json $out } # } -# +# # sub ruby_code { # my( $code ) = @_; # local $@; -# +# # print rb_eval( $code ); # } -# +# # sub php_code { # my( $code ) = @_; # local $@; -# +# # #warn "PHP - [$code]"; -# +# # my $php = PHP::Interpreter->new; -# +# # $php->set_output_handler(\ my $output ); -# +# # $php->eval("$code;"); -# +# # print $php->get_output; -# +# # #warn "ENDING"; -# +# # if( $@ ) { print "ERROR: $@"; } # } -# +# # sub k20_code { # my( $code ) = @_; -# +# # $code =~ s/\r?\n//g; -# -# +# +# # Language::K20::k20eval( '."\\\\r ' . int(rand(2**31)) . '";' . "\n"); # set random seed -# +# # Language::K20::k20eval( $code ); # } -# +# # sub python_code { # my( $code ) = @_; -# +# # py_eval( $code, 2 ); # } -# +# # sub lua_code { # my( $code ) = @_; -# +# # #print lua_eval( $code )->(); -# +# # my $ret = lua_eval( $code ); -# +# # print ref $ret ? $ret->() : $ret; # } -# +# # sub j_code { # my( $code ) = @_; -# +# # Jplugin::jplugin( $code ); # } diff --git a/lib/jail/.svn/entries b/lib/jail/.svn/entries deleted file mode 100644 index 8fc3790..0000000 --- a/lib/jail/.svn/entries +++ /dev/null @@ -1,28 +0,0 @@ -10 - -dir -475 -svn://erxz.com/bb3/branches/perlbuut/lib/jail -svn://erxz.com/bb3 - - - -2009-10-03T22:53:42.528878Z -475 -simcop - - - - - - - - - - - - - - -dcb1cea6-7f7e-4c78-8a22-148ace8ce36e -