#!/bin/sh # # Run a program binary in a sandbox. # # File: hpcm_sandbox # Author: Bob Walton # Date: Sat May 6 07:17:43 EDT 2006 # # The authors have placed this program in the public # domain; they make no warranty and accept no liability # for this program. # # RCS Info (may not be true date or author): # # $Author: hc3 $ # $Date: 2006/05/06 11:17:04 $ # $RCSfile: hpcm_sandbox,v $ # $Revision: 1.16 $ # This works as-is for LINUX systems. See comments # below for SUN UNIX operating systems. For other UNIX # systems you may need to change the ulimit(1) command # and possibly the processing of signal exit codes for # -watch. # Set defaults for resource limits. # cputime=600 space=`expr 512 \* 1024 \* 1024` datasize=`expr 4 \* 1024 \* 1024` filesize=`expr 4 \* 1024 \* 1024` stacksize=`expr 4 \* 1024 \* 1024` core=`expr 4 \* 1024 \* 1024` openfiles=30 processes=50 # Collect information from arguments. # # Operation is last argument if that is -cputime, ... . # Watch is "" if no and "yes" if yes. # Program is the name of the program plus arguments. # operation="" watch="" tee="" file="" program="" for arg in "$@"; do if test ! -z "$program"; then program="$program '$arg'" else case "$arg" in -cputime | -space | -datasize | -filesize \ | -stacksize | -openfiles \ | -processes | -core | -tee ) if test -z "$operation"; then operation=$arg else echo "ERROR: misplaced argument: $arg" exit 1 fi ;; [0-9]* ) if test `expr $arg : '.*[^0-9]' ` -ne 0 then number=`expr $arg : '\([0-9]*\)[^0-9]' ` scale=`expr $arg : \ '[0-9]*\([^0-9].*\)$' ` case $scale in k ) number=`expr $number \* 1024` ;; m ) number=`expr $number \* 1024 \ \* 1024` ;; * ) echo "ERROR: bad number: $arg" exit 1 ;; esac else number=$arg fi case $operation in -cputime ) cputime=$number ;; -space ) space=$number ;; -datasize ) datasize=$number ;; -stacksize ) stacksize=$number ;; -filesize ) filesize=$number ;; -openfiles ) openfiles=$number ;; -processes ) processes=$number ;; -core ) core=$number ;; * ) echo ERROR: misplaced \ argument: "$arg" exit 1 ;; esac operation="" ;; -watch ) if test -z "$operation"; then watch=yes else echo "ERROR: misplaced argument: $arg" exit 1 fi ;; * ) if test -z "$operation"; then program="'$arg'" elif test "$operation" = "-tee"; then tee=yes file="$arg" operation="" else echo "ERROR: misplaced argument: $arg" exit 1 fi ;; esac; fi done if test "$operation" != ""; then echo "ERROR: too few arguments to hpcm_sandbox" exit 1 fi case "$program" in "" | -* ) echo " hpcm_sandbox [options] program arguments This program first checks its arguments for options that set resource limits: -cputime N Cpu Time in Seconds (600) -space N Virtual Address Space Size in Bytes (512m) -datasize N Data Area Size in Bytes (4m) -stacksize N Stack Size in Bytes (4m) -filesize N Output File Size in Bytes (4m) -core N Core Dump Size in Bytes (4m) -openfiles N Number of Open Files (30) -processes N Number of Processes (50) Here N is a positive decimal integer that can end with \`k' to multiply it by 1024 or \`m' to multiply it by 1024 * 1024. The values above in parentheses are the default values. There is also another possible option: -watch With this option, this program forks with the parent waiting for the child to complete the the rest of this program's action. If the child terminates with a signal, the parent prints an error message identifying the signal. The parent returns a 0 exit code if the child does not terminate with a signal, and returns 128 + the signal number as an exit code if the child does terminate with a signal. This version of the program actually just emulates the real hpcm_sandbox program, the main difference being that this version does not change the process real and effective user and group IDs, and does not alter the program environment (as set by \`setenv' or \`export'). " exit 1 ;; esac # Set the resource limits. Ignore errors; but all # these in fact work in linux. If something does # not work, comment it out. # ulimit -t $cputime ulimit -v `expr $space / 1024` ulimit -d `expr $datasize / 1024` ulimit -f `expr $filesize / 1024` ulimit -s `expr $stacksize / 1024` ulimit -c `expr $core / 1024` ulimit -u $processes ulimit -n $openfiles # Execute the program. If -watch given, look to see if # the program returned with a signal, and if yes, print # a message identifying the signal and exit with a code # equal to 128+signal number (just as /bin/sh does). # Otherwise exit with code 0 (so contestants do not have # to control their exit code). # if test ! -z "$watch" -o ! -z "$tee"; then if test ! -z "$tee"; then program="$program | 'tee' '$file'" fi eval $program status=$? if test $status -ge 128; then signal=`expr $status - 128` case $signal in 1 ) signame=SIGHUP ;; 2 ) signame=SIGINT ;; 3 ) signame=SIGQUIT ;; 4 ) signame=SIGILL ;; 5 ) signame=SIGTRAP ;; 6 ) signame=SIGABRT ;; 6 ) signame=SIGIOT ;; 7 ) signame=SIGBUS ;; 8 ) signame=SIGFPE ;; 9 ) signame=SIGKILL ;; 10 ) signame=SIGUSR1 ;; 11 ) signame=SIGSEGV ;; 12 ) signame=SIGUSR2 ;; 13 ) signame=SIGPIPE ;; 14 ) signame=SIGALRM ;; 15 ) signame=SIGTERM ;; 16 ) signame=SIGSTKFLT ;; 17 ) signame=SIGCHLD ;; 18 ) signame=SIGCONT ;; 19 ) signame=SIGSTOP ;; 20 ) signame=SIGTSTP ;; 21 ) signame=SIGTTIN ;; 22 ) signame=SIGTTOU ;; 23 ) signame=SIGURG ;; 24 ) signame=SIGXCPU ;; 25 ) signame=SIGXFSZ ;; 26 ) signame=SIGVTALRM ;; 27 ) signame=SIGPROF ;; 28 ) signame=SIGWINCH ;; 29 ) signame=SIGIO ;; 30 ) signame=SIGPWR ;; * ) signame=UNKNOWN ;; esac echo "Program terminated by signal: $signame" exit $status fi else eval $program fi exit 0