The traditional method of restricting a process is with the chroot(2) system call. This system call changes the root directory from which all other paths are referenced for a process and any child processes. Of course, the process must have access to this path to begin with. The new environment does not actually take effect until chdir(2) is called to place the process into the new environment. Unfortunately, a process can break out of this environment if root access is obtained.
Often, jail(2) can be used to create a more complete and enclosed environment than chroot(2) can provide. A jail limits all processes inside that environment, including processes with superuser privileges.
Fine grained privileges, as described by POSIX .1e extensions, are currently a work in progress, and the focus of the TrustedBSD Project. More information can be found at http://www.TrustedBSD.org/.
Programs should not make assumptions about the environment in which they are running. This includes user input, signals, environment variables, system resources, interprocess communications, and shared memory, amongst other things that are beyond the control of the program. They should not assume that all forms of invalid data can be detected either. Instead, they should use positive filtering, and only allow a specific subset of inputs that are known to be safe. This is the same logic that an administrator should apply to a firewall, that is, deny by default and specify what is to be accepted.
A race condition is anomalous behavior caused by the relative timing of events. Programs should not assume that a particular event will occur before another. The most common causes of race conditions are signals, access checks, and file reads. Signals are asynchronous by nature, so special care must be taken while dealing with them. Attempting to check access with sequential non-atomic operations is a very bad idea, as files can be moved and changed at any given time. Instead of using a sequence of access(2) and open(2), use seteuid(2) and then call open(2) directly. Set umask(2) properly beforehand.
jail(2), setuid(2), strlcat(3), strlcpy(3)