mirror of
https://github.com/perlbot/perlbuut
synced 2025-06-07 18:35:49 -04:00
Now use the awesome power of SECCOMP to secure the eval, and enable new functionality
This commit is contained in:
parent
d4e272c467
commit
66bc4ad0e9
5 changed files with 150 additions and 138 deletions
8
bin/makejail.sh
Executable file
8
bin/makejail.sh
Executable file
|
@ -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
|
5
bin/mountjail.sh
Normal file
5
bin/mountjail.sh
Normal file
|
@ -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
|
7
cpanfile
7
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;
|
||||
|
||||
|
|
240
lib/eval.pl
240
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 $/; <STDIN> };
|
||||
|
||||
# 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 );
|
||||
# }
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Add table
Reference in a new issue