This is an individual assignment. The goal of this assignment is to write a program that ``confines'' the behaviour of other programs. Such programs are useful in variety of situations -- examining malicious programs, running untrusted programs, and autograding.
You will write a program called confine
, that runs another program
with several restrictions. The program confine
will be called as:
./confine /path/to/program-to-be-confined [args-to-program1 [args-to-program2...]]
The program being confined need not accept any arguments, so
./confine /path/to/program-to-be-confined
is valid too.
An example of a call to confine will look like this:
./confine ./samples/sub1 1 2 3 0
This will cause confine
to execute ./samples/sub1
with the arguments 1 2 3 0
.
The confine
program should prevent the confined programs from:
Using more than 64MB of memory (64x1024x1024 bytes).
Creating a file greater than 4MB (4x1024x1024 bytes).
Running for more than 1 minute real time (i.e. wall-clock time).
The confine
program should return the confined program's return
value if the confined program ran normally without exceeding the
restrictions.
It should return 127
if the confined program was terminated because
it encountered a restriction.
It should return 128
if the confined program died because it
encountered a bug.
It should also create a file confine_result.txt
, in the following format:
First line contains confined program and its arguments
Second line contains "NORMAL", "TERMINATED", "TIMEOUT" depending on whether the confined program i) ran normally, ii) was terminated for any reason, iii) was terminated for a timeout respectively.
This assignment requires you to use (among others) fork
, execve
,
waitpid
, setitimer
system calls, as well as set up signal handlers
using sigaction
.
Read the manual pages, and ask questions on Piazza if needed.
Write confine
to execute the program specified on the command line.
The manual page for
execve
contains sample code for a program myecho.c
that you can use to
verify correctness. It also contains example code for how to execute a
program, and you can adapt it for this assignment.
Detect cases when the program exits normally and when it dies because of a bug (e.g. segmentation fault).
Return the appropriate value (the program's return value) or 128.
None of the programs to be confined in this assignment will ordinarily return a value greater than 64.
The programs in the included samples/
directory all show various
pathological behaviour. See the source code and the included
README.txt
.
Use the Linux system calls setrlimit
and getrlimit
to set limits
on memory, file size, and CPU time. Note, these limits should only
apply to the confined process, not confine
itself.
The setrlimit
CPU time restriction applies only when the program is
actually running. In some instances, a program may not make progress
and not consume CPU time -- for example, when it is waiting for input.
To detect and terminate such errant programs, you will need to set up
a timer before running the program (using setitimer
or alarm
for
example). If the program has not terminated by the time you receive
SIGALRM, you should kill it using kill
and SIGKILL
.
Note, SIGALRM is not guaranteed to deliver a signal exactly on time, and that's okay.