1
0
Fork 0
mirror of https://github.com/perlbot/perlbuut synced 2025-06-07 10:35:41 -04:00

Now use the awesome power of SECCOMP to secure the eval, and enable new functionality

This commit is contained in:
Ryan Voots 2016-10-15 08:04:58 -04:00
parent d4e272c467
commit 66bc4ad0e9
5 changed files with 150 additions and 138 deletions

8
bin/makejail.sh Executable file
View 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
View 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

View file

@ -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;

View file

@ -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 );
# }

View file

@ -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