mirror of
https://github.com/perlbot/perlbuut
synced 2025-06-08 00:05:47 -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 'indirect' => 0;
|
||||||
requires 'Moo' => 0;
|
requires 'Moo' => 0;
|
||||||
requires 'autovivification' => 0;
|
requires 'autovivification' => 0;
|
||||||
|
|
||||||
|
requires 'Linux::Seccomp' => 0;
|
||||||
|
requires 'Cwd' => 0;
|
||||||
|
# requires 'Algorithm::Permute' => 0;
|
||||||
|
requires 'File::Slurper' => 0;
|
||||||
|
requires 'Path::Tiny' => 0;
|
||||||
|
|
||||||
|
|
162
lib/eval.pl
162
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/i686-linux';
|
||||||
#use lib '/home/ryan/perl5/lib/perl5';
|
#use lib '/home/ryan/perl5/lib/perl5';
|
||||||
|
@ -9,64 +9,14 @@ use Scalar::Util; #Required by Data::Dumper
|
||||||
use BSD::Resource;
|
use BSD::Resource;
|
||||||
use File::Glob;
|
use File::Glob;
|
||||||
use POSIX;
|
use POSIX;
|
||||||
|
use List::Util qw/reduce/;
|
||||||
|
use Cwd;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
use List::Util;
|
# Modules expected by many evals, load them now to avoid typing in channel
|
||||||
use List::MoreUtils;
|
use Encode qw/encode decode/;
|
||||||
use List::UtilsBy;
|
use IO::String;
|
||||||
use Data::Munge;
|
use File::Slurper qw/read_text/;
|
||||||
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 $@;
|
|
||||||
}
|
|
||||||
|
|
||||||
# save the old stdout, we're going to clobber it soon. STDOUT
|
# save the old stdout, we're going to clobber it soon. STDOUT
|
||||||
my $oldout;
|
my $oldout;
|
||||||
|
@ -78,6 +28,79 @@ select($stdh);
|
||||||
$|++;
|
$|++;
|
||||||
#*STDOUT = $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;
|
no warnings;
|
||||||
|
|
||||||
# This sub is defined here so that it is defined before the 'use charnames'
|
# This sub is defined here so that it is defined before the 'use charnames'
|
||||||
|
@ -166,9 +189,6 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem
|
||||||
|
|
||||||
my $code = do { local $/; <STDIN> };
|
my $code = do { local $/; <STDIN> };
|
||||||
|
|
||||||
# Kill @INC to shorten errors;
|
|
||||||
@INC = ('.');
|
|
||||||
|
|
||||||
# Close every other filehandle we may have open
|
# Close every other filehandle we may have open
|
||||||
# this is probably legacy code at this point since it was used
|
# this is probably legacy code at this point since it was used
|
||||||
# inside the original bb2 which forked to execute this code.
|
# 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
|
# The chroot section
|
||||||
chdir("./jail") or
|
chdir($FindBin::Bin."/../jail") or die "Jail not made, see bin/makejail.sh";
|
||||||
do {
|
|
||||||
mkdir "./jail";
|
|
||||||
chdir "./jail" or die "Failed to find a jail live in, couldn't make one either: $!\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
# redirect STDIN to /dev/null, to avoid warnings in convoluted cases.
|
# redirect STDIN to /dev/null, to avoid warnings in convoluted cases.
|
||||||
open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!";
|
open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!";
|
||||||
|
@ -210,6 +226,7 @@ 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.
|
POSIX::setgid($nobody_uid); #We just assume the uid is the same as the gid. Hot.
|
||||||
|
|
||||||
|
|
||||||
die "Failed to drop to nobody"
|
die "Failed to drop to nobody"
|
||||||
if $> != $nobody_uid
|
if $> != $nobody_uid
|
||||||
or $< != $nobody_uid;
|
or $< != $nobody_uid;
|
||||||
|
@ -227,11 +244,11 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_NPROC, 1,1)
|
setrlimit(RLIMIT_NPROC, 1,1)
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_NOFILE, 0,0)
|
setrlimit(RLIMIT_NOFILE, 20,20)
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_OFILE, 0,0)
|
setrlimit(RLIMIT_OFILE, 20,20)
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_OPEN_MAX,0,0)
|
setrlimit(RLIMIT_OPEN_MAX,20,20)
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_LOCKS, 0,0)
|
setrlimit(RLIMIT_LOCKS, 0,0)
|
||||||
and
|
and
|
||||||
|
@ -239,7 +256,7 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_MEMLOCK,100,100)
|
setrlimit(RLIMIT_MEMLOCK,100,100)
|
||||||
and
|
and
|
||||||
setrlimit(RLIMIT_CPU, 10,10)
|
setrlimit(RLIMIT_CPU, 10, 10)
|
||||||
)
|
)
|
||||||
or die "Failed to set rlimit: $!";
|
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;
|
die "Failed to drop root: $<" if $< == 0;
|
||||||
# close STDIN;
|
# close STDIN;
|
||||||
|
|
||||||
|
# Setup SECCOMP for us
|
||||||
|
get_seccomp();
|
||||||
|
|
||||||
$code =~ s/^\s*(\w+)\s*//
|
$code =~ s/^\s*(\w+)\s*//
|
||||||
or die "Failed to parse code type! $code";
|
or die "Failed to parse code type! $code";
|
||||||
my $type = $1;
|
my $type = $1;
|
||||||
|
@ -299,7 +319,7 @@ use Storable qw/nfreeze/; nfreeze([]); #Preload Nfreeze since it's loaded on dem
|
||||||
sub perl_code {
|
sub perl_code {
|
||||||
my( $code ) = @_;
|
my( $code ) = @_;
|
||||||
local $@;
|
local $@;
|
||||||
local @INC = ('.');
|
local @INC = map {s|/home/ryan||r} @INC;
|
||||||
|
|
||||||
local $_;
|
local $_;
|
||||||
|
|
||||||
|
|
|
@ -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