SafeRun - Run an executable, providing pty I/O, security against output overruns, excess runtimes, and process runaways
SafeRun [options] test_subject
SafeRun is a test harness for running a "test subject" Unix executable that has a text I/O interface. SafeRun provides the following
Text I/O programs are often tested with redirected input and output, but if they fail during the run, much or all of their output may be lost due to buffering that automatically occurs when stdout is redirected. A program might generate dozens of lines prior to a runtime fault when run directly on screen, but show no output at all when redirected to a file. SafeRun arranges input and output "piping" via ptys, so even in the presence of a fault, the output it generates looks like what you'd see on screen, despite being redirected.
Runtime fault messages, e.g. "Seg fault core dumped", are made directly to screen, and not to the error stream. SafeRun, however, creates and prints to the error stream a message reporting the fault.
Simple redirection invites huge output files from programs with runaway output. SafeRun places a byte limit on redirected data, and simply drops all output exceeding that limit, printing to stderr a message telling how many bytes were dropped.
SafeRun measures both the wallclock and CPU time of the test subject, and terminates it if either exceeds some limit.
SafeRun limits the number of simultanously running descendant processes created by the test subject, by limiting process count through Unix resource controls. SafeRun generates and reports a fault if this limit is exceeded.
SafeRun detects and kills lingering descendant processes of the test subject, and it reports via stderr a count of such processes.
It does this by one of two means. In a non-rooted configuration, it places the test subject under a new session id, and detects and kills all lingering processes running under that session id. Sufficiently malfeasant processes can defeat this by shifting session ids, but this is unlikely.
If SafeRun is run under root privilege, and is given the name of a user, it will run the test subject under that user, and kill all lingering processes running under that user, on the entire system.
SafeRun can run the test subject and its descendant processes in a chroot jail, to thwart test subjects that "explore" their environment, or attempt to corrupt it. Chroot jailing requires root privilege for SafeRun.
SafeRun determines whether the test subject left input unread, and reports this as an error, unless otherwise configured.
SafeRun accepts the following options. Each is expressed with a '-', the option letter, and any configuration information without spaces, e.g. "-T1000". Most have a default value used if no option is given.
T
Wallclock time limit in mS. The option "-T1000" results in a wallclock time limit of 1s. Default value: 1000000
t
CPU time limit, per process or child process, in mS. The option -t1000
results in a per process CPU limit of 1s. Default value: 10000
p
Max number of descendant processes. -p10 limits simultanous active test
subject descendant processes to 10, using Unix resource limits. (Note this
does not preclude an infinite number of children if each spawns another and
then dies.) Default value: 10
o
Max number of output bytes allowed in stdout or stderr (both limited
independently). -o1000 limits output to 1000 stdout and 1000 stderr bytes.
Default value: 1000000
u
Username for test subject. Requires that SafeRun run with root privilege.
-uGuest runs test subject as user Guest. Presuming Guest is not root
privileged, this means all descendant processes will also be Guest, and
SafeRun's termination of all lingering Guest processes will block even
malfeasant users from creating runaway processes. Default is no username,
which means that lingering process cleanup will be done by session id, which
is less reliable.
r
Chroot flag. Requires SafeRun have root privilege. -r turns on chroot
behavior; test subject and all descendant processes will run in a clean chroot
jail in the current directory. SafeRun does not populate the chroot jail with
any dynamic libraries, so any test subject must be statically linked. Default
behavior: no chroot jail.
i
Input control flag. Its presence makes unread input permissible. The flag alone makes any unread input, including no unread input, OK; the flag followed by a number requires exactly that many bytes of unread input, with any other amount resulting in an error message to stderr.
b
Flag for accommodation of binary input. SafeRun normally sends input to the
test subject via a pty, as described above. If input is binary, the presence
of control-characters in the binary data makes this problematic. A -b flag
causes SafeRun to use a standard pipe for input to the test subject, though it
still uses the pty for output. This handles binary input properly, at the
expense of losing the ability to detect unread input, since piped input is
usually grabbed by the test subject in large buffersfull, even if it ends up
unused.
SafeRun reports error situations on stderr, but it also returns a program
result code for use in scripting. (The code can be determined by running echo $?
immediately after a hand-run of SafeRun, per usual.) The result code is
one of the following, in descending order of priority:
180 Fork call failed
181 Error setting up parameters
182 Wait call for test subject failed
183 Chroot failed, perhaps because SafeRun lacked root privilege
184 Execution of test subject failed, perhaps using chroot with nonstatically
linked executable
185 Attempt to run test subject under another user via -u option failed
186 Unexpected error running "select" system call
187 Interrupted by control-C or control-\
188-191 Reserved for later errors
Result code is 192 plus an or of one or more of these values. E.g. a result
code of 197 indicates excess runtime plus nonterminated child processes.
1 Excess runtime, due either to slow implementation or endless loop
2 Excessively long output, again probably due to endless loop
4 Child processes not terminated and waited for
8 Runtime fault of some sort, e.g. segmentation fault
16 Failure to read all supplied input.
32 Reserved for later errors
Note that this may be at most 179 without interference with the other possible values above. But, this is not a significant limit for many applications. And the only way to obtain a 0 result code from SafeRun is for no other failures to occur and for the test subject to return a 0 result code.
Note that this means shell scripts checking for nonzero result codes will be sensitive to the result code of the test subject itself, if no other error has occured. If you get weird result codes from SafeRun, check to be sure your code is returning a valid result code, not leaving it to random chance.
SafeRun will print any nonzero result code to stderr.
In some instances where SafeRun is not in the PATH, an exit code of 127 may be
seen instead of the usual shell command not found complaint. This appears to
happen most often when redirecting stderr to stdout via 2>&1. The exit code
does not come from SafeRun or the test subject; it's set by the shell.
SafeRun is meant to be run with redirected input. It can also be run with hand-entered input, but remember that you must end your input with an EOF indication (i.e. control-D) or SafeRun will wait indefinitely, even if the test subject has long since terminated. SafeRun detects input not read by the test subject, and if you have "more to say" after the test subject has ended, it needs to know this so it can report an error.