Recipe 3.15 Restricting Services to Specific Filesystem Directories
3.15.1 Problem
You want to create a
chroot
cage to restrict a service
to a particular directory (and its subdirectories) in your
filesystem.
3.15.2 Solution
Create a chroot cage by running the GNU
chroot program instead of the service. Pass the
service executable as an argument. In other words, change this:
/etc/xinetd.conf or /etc/xinetd.d/myservice:
service myservice
{
...
server = /usr/sbin/myservice -a -b
...
}
into this:
service myservice
{
...
user = root
server = /usr/sbin/chroot
server_args = /var/cage /usr/sbin/myservice -a -b
...
}
3.15.3 Discussion
chroot takes two arguments: a directory and a
program. It forces the program to behave as if the given directory
were the root of the filesystem,
"/". This effectively prevents the
program from accessing any files not under the chroot cage directory,
since those files have no names in the chroot'ed
view of the filesystem. Even if the program runs with root
privileges, it cannot get around this restriction. The system call
invoked by chroot (which also is named
chroot) is one-way: once it is invoked, there is
no system call to undo it in the context of the calling process or
its children.
A chroot cage is most effective if the program relinquishes its root
privileges after it starts—many daemons can be configured to do
this. A root program confined to a chroot cage can still wreak havoc
by creating and using new device special files, or maliciously using
system calls that are not related to the filesystem (like reboot!).
In normal operation, a program may access many files not directly
related to its purpose, and this can restrict the practicality of
chroot. You might have to duplicate so much of
your filesystem inside the cage as to negate the
cage's usefulness—especially if the files are
sensitive (e.g., your password file, for authentication), or if they
change. In the former case, it's better if the
service itself contains special support for
chroot, where it can choose to perform the
chroot operation after it has accessed all the
general system resources it needs. In the latter case, you can use
hard links to make files already named outside the cage accessible
from inside it—but that works only for files residing on the
same filesystem as the cage. Symbolic links will not be effective, as
they will be followed in the context of the cage.
In order for chroot to work, it must be run as
root, and the given "cage"
directory must contain a Linux directory structure sufficient to run
myservice. In the preceding example,
/var/cage will have to contain
/var/cage/usr/sbin/myservice,
/var/cage/lib (which must include any libraries
that myservice may use), and so forth. Otherwise
you'll see errors like:
chroot: cannot execute program_name: No such file or directory
This can be a bit of a detective game. For example, to get this
simple command working:
# chroot /var/cage /usr/bin/who
the directory /var/cage will need to mirror:
- /usr/bin/who
- /lib/ld-linux.so.2
- /lib/libc.so.6
- /var/log/wtmp
- /var/run/utmp
The commands ldd and strings can help
identify which shared libraries and which files are used by the
service, e.g.:
$ ldd /usr/sbin/myservice
... output...
$ strings /usr/sbin/myservice | grep /
... output...
3.15.4 See Also
chroot(1), xinetd.conf(5), strings(1), ldd(1). If
there's no ldd manpage on your
system, type ldd —help for usage.
|