16.5 Using chroot( )
You can enhance the security of your programs by using the
chroot( )
system call. The chroot( ) call changes the
root directory of a process to a specified
subdirectory within your filesystem. This change essentially gives
the calling process a private world from which it cannot
escape. Several widely-used network daemons, such as the BIND
nameserver, are written so they can run in a chroot(
) environment.
For example, if you have a program that only needs to listen to the
network and write into a log file that is stored in the directory
/usr/local/logs, then you could execute the
following code to restrict the program to that directory:
assert(chdir("/usr/local/logs") == 0);
assert(chroot("/usr/local/logs") == 0);
assert(chdir("/") == 0);
There are several issues that you must be aware of when using the
chroot( ) system call that are not immediately
obvious:
It is imperative that you successfully chdir( )
into the chroot area before doing anything
important (and best if you chdir( ) there before
you call chroot( )). chroot(
) does not change the working directory, and a privileged
program can break out of a chroot area if its
working directory is outside the area.
With some systems, it is also critical that you set the current
working directory to be "/" after
the chdir is executed. Otherwise, it is possible
to break out of the chroot( ) system in some
cases.
If your operating system supports shared libraries and you are able
to statically link your program, you should be sure that your program
is statically linked. On some systems, static linking is not
possible. On these systems, you should make certain that the
necessary shared libraries are available within the restricted
directory (as copies).
You should not give other users write access to the chroot(
)ed directory.
If you intend to log with syslog( ), you should
call the openlog( ) function before executing
the chroot( ) system call, or make sure that a
/dev/log device file exists within the
chroot( ) directory.
chroot( )ed processes should run with a UID that
is not used by any programs outside of the chroot(
) area. This prevents the processes from using debugger
hooks to manipulate outside processes and potentially subvert the
jail.
Do not allow root-owned processes to run inside the
chroot area. As soon as your program
successfully chroots, it should immediately
setgid( ) and setuid( ) to
give up its superuser privileges. Likewise, where possible, restrict
the occurance of SUID programs and devices within the
chroot environment.
Many versions of Unix provide a program called
chroot that can be used to execute an arbitrary
command in a chrooted environment, like this:
# chroot /path/to/directory /chrooted/path/to/command arguments
This will cause a chroot to the specified
directory (which must be set up as described earlier), and then run
the given command, which must be in the chrooted
area (along with any necessary shared libraries, etc.) already.
Note that under some versions of Unix, a user with a
root shell and the ability to copy compiled code
into the chrooted environment may be able to
"break out." The same applies to an
SUID program (or other program running as root)
that has not dropped its privileges. Thus, don't put
all your faith in this mechanism.
|