Creating Systrace Policies
by Michael W. Lucas02/27/2003
In the last article, we examined basic systrace policies. This time we're going to learn how to create and use systrace policies. In a true paranoid's ideal world, sysadmins would read the source code for every application on their system and be able to build system call access policies by hand, relying only on their intimate understanding of every feature of the application. Most system administrators don't have that sort of time and would have better things to do with that sort of time if they did.
A second choice would be to take policies from a selection of publicly-audited policies. The Hairy Eyeball project contains systrace policies for almost two hundred programs. The policies are designed for use with OpenBSD, but could easily be edited for binaries on any operating system. I recommend that you download the entire Hairy Eyeball distribution to use as examples, if nothing else. Using a predefined policy can save you a lot of annoyance, but you still need to be able to edit these to fit your particular circumstances. Also, you'll have to generate policies from scratch for programs that are not in the repository.
systrace(1) includes an policy-generation tool that
will generate a policy listing every system call the application wants
to make. You can use that policy as a starting point to narrow down
the access you will allow the application. We'll use this method to
generate a policy for inetd(8). Use the -A
flag to systrace, and the full path to the program you
want to run.
systrace -A /usr/sbin/inetd
To pass flags to inetd, add them at the end of the command
line.
Then use the program for which you're developing a policy. This
system has ident, daytime, and
time services open, so run programs that require those
services. Fire up an IRC client to trigger ident
requests, and telnet to port 13 and 37 to get time services. Once you
have put inetd through its paces, shut it down.
inetd has no control program, so you need to kill it by
process ID. Checking the process list will show two processes:
# ps -ax | grep inet
24421 ?? Ixs 0:00.00 /usr/sbin/inetd
12929 ?? Is 0:00.01 systrace -A /usr/sbin/inetd
#
Do not kill the systrace process (pid 12929 in this
example). That process has all the records of the system calls that
inetd(8) has made. Just kill the inetd
process, and the systrace process will exit normally.
Now check your home directory for a .systrace
directory, which will contain systrace(1)'s first stab at
an inetd(8) policy. Remember, policies are placed in
files named after the full path to the program, replacing slashes with
underscores.
# ls .systrace
usr_libexec_identd usr_sbin_inetd
#
|
Also in Big Scary Daemons: Running Commercial Linux Software on FreeBSD Building Detailed Network Reports with Netflow Visualizing Network Traffic with Netflow and FlowScan |
systrace created two policies, not one. In addition
to the expected policy for /usr/sbin/inetd, there's one
for /usr/libexec/identd. If you're familiar with
inetd(8), you've probably already guessed why this
happened. Those new to inetd should consult the man
page, which explains that inetd implements
time services internally while ident calls a
separate program to service requests. As inetd spawned
identd, systrace captured the
identd system calls as well.
By reading the policy, you can improve your understanding of what the program actually does. Look up each system call the program uses, and see if you can restrict access further. An experienced system administrator can probably find ways to tighten access, but junior sysadmins can just use the autogenerated policy. If you run the autogenerated policy, you've already improved your systems' security. For example, the autogenerated policy contains rules that only allow it to listen on particular TCP/IP ports and only read certain files on the system.
Applying a policy to a program is much like creating the systrace
policy itself; just run the program as an argument to
systrace, using the -a option.
# systrace -a /usr/sbin/inetd
If the program tries to perform system calls not listed in the
policy, they will fail. This may cause the program to behave
unpredictably. systrace will log failed entries in
/var/log/messages. For example, after running
inetd under this particular systrace policy I found
messages like this throughout /var/log/messages:
Dec 2 01:31:11 openbsdtest systrace: deny user: _identd, \
prog: /usr/libexec/identd, pid: 27046(1)[12989], \
policy: /usr/libexec/identd, filters: 24, syscall: native-fsread(5), \
filename: /etc/spwd.db
Dec 2 01:31:11 openbsdtest identd[27046]: /etc/pwd.db: Operation not permitted
Dec 2 01:31:11 openbsdtest identd[27046]: \
getpwuid() could not map uid (25) to name
We can trace this back and see what exactly happened. In the
first log entry, identd tried to real
/etc/spwd.db. This is the hash of the password file.
identd(8) should certainly be able to look up system
users--that's the service it provides, after all. I need to add an
appropriate entry to the policy to allow this access.
Editing a policy is very simple: just add the desired statement to
the end of the rule list, and it will be picked up. You could do this
by hand, of course, but that's the hard way. systrace
includes a tool to let you edit policies in real time, as the system
call is made. This is excellent for use in a network operations
center environment, where the person responsible for watching the
network monitor can also be assigned to watch for system calls and
bring them to the attention of the appropriate sysadmin. You can
specify which program you wish to monitor by using
systrace's -p flag. This is called
"attaching" to the program.
For example, earlier we saw two processes containing
inetd. One was the actual inetd process,
the other was the systrace process managing
inetd. Attach to the systrace process, not
the actual program; in this case, process 12929. Also give the full
path to the managed program as an argument.
# systrace -p 12929 /usr/sbin/inetd
At first nothing will happen. When the program attempts to make an unauthorized system call, however, a GUI will pop up. You will have the options to allow the system call, deny the system call, always permit the call, or always deny it. The program will hang until you make a decision, however, so decide quickly.
|
Related Reading
The Unix CD Bookshelf |
Note that these changes will only take effect so long as the current process is running. If you restart the program, you must also restart the attached systrace monitor, and any changes you set in the monitor are gone. You must add those rules to the policy if you want them to be permanent.
Once you've mastered the basics, check out gtk-systrace.
It includes policy suggestions that can help you create a policy very
quickly. We'll spend some time with gtk-systrace and
other systrace features in a future article.
While systrace has a vast number of functions and
abilities, this should be enough to get you started. Experiment with
the tool, look at some existing policies, and be sure to read section
2 of the man pages when you're in doubt. systrace is
starting to spread to other operating systems; not only is it on
OpenBSD, but NetBSD and Linux, with ports underway to Mac OS X and
FreeBSD.
(The author wishes to thank systrace's author, Neils
Provos, for taking time out of his busy schedule to answer questions
and review the previous two articles.)
Read more Big Scary Daemons columns.
Return to the BSD DevCenter.
