Directories and Links 367
18.12 Changing the Root Directory of a Process: chroot()........................................................
Every process has a root directory, which is the point from which absolute pathnames
(i.e., those beginning with /) are interpreted. By default, this is the real root directory
of the file system. (A new process inherits its parent’s root directory.) On occasion, it
is useful for a process to change its root directory, and a privileged (CAP_SYS_CHROOT)
process can do this using the chroot() system call.
The chroot() system call changes the process’s root directory to the directory speci-
fied by pathname (which is dereferenced if it is a symbolic link). Thereafter, all
absolute pathnames are interpreted as starting from that location in the file system.
This is sometimes referred to as setting up a chroot jail, since the program is then
confined to a particular area of the file system.
SUSv2 contained a specification for chroot() (marked LEGACY), but this was
removed in SUSv3. Nevertheless, chroot() appears on most UNIX implementations.
The chroot() system call is employed by the chroot command, which enables us
to execute shell commands in a chroot jail.
The root directory of any process can be found by reading (readlink()) the
contents of the Linux-specific /proc/PID/root symbolic link.
The classic example of the use of chroot() is in the ftp program. As a security mea-
sure, when a user logs in anonymously under FTP, the ftp program uses chroot() to
set the root directory for the new process to the directory specifically reserved for
anonymous logins. After the chroot() call, the user is limited to the file-system subtree
under their new root directory, so they can’t roam around the entire file system.
(This relies on the fact that the root directory is its own parent; that is, /.. is a link
to /, so that changing directory to / and then attempting a cd .. leaves the user in the
same directory.)
Some UNIX implementations (but not Linux) allow multiple hard links to a
directory, so that it is possible to create a hard link within a subdirectory to its
parent (or a further removed ancestor). On implementations permitting this,
the presence of a hard link that reaches outside the jail directory tree compro-
mises the jail. Symbolic links to directories outside the jail don’t pose a problem—
because they are interpreted within the framework of the process’s new root
directory, they can’t reach outside the chroot jail.
Normally, we can’t execute arbitrary programs within a chroot jail. This is because
most programs are dynamically linked against shared libraries. Therefore, we must
either limit ourselves to executing statically linked programs, or replicate a stan-
dard set of system directories containing shared libraries (including, for example, /lib
and /usr/lib) within the jail (in this regard, the bind mount feature described in
Section 14.9.4 can be useful).
#define _BSD_SOURCE
#include <unistd.h>
int chroot(const char *pathname);
Returns 0 on success, or –1 on error