Tuesday, February 17, 2009

Using Chroot

The chroot() system call (pronounced “cha-root”) allows a process and all of its child processes to redefine what they perceive the root directory to be. For example, if you were to chroot("/www") and start a shell, you could find that using the cd command would leave you at /www. The program would believe it is a root directory, but in reality,it would not be. This restriction applies to all aspects of the process’s behavior: where it loads configuration files, shared libraries, data files, etc.

NOTE Once executed, the change in root directory by chroot is irrevocable through the lifetime of the process.



by changing the perceived root directory of the system, a process has a restricted view of what is on the system. Access to other directories, libraries, and configuration files is not available. Because of this restriction, it is necessary for an application to have all of the files necessary for it to work completely contained within the chroot environment. This includes any passwd files, libraries, binaries, and data files.

CAUTION A chroot environment will protect against accessing files outside of the directory,
but it does not protect against system utilization, memory access, kernel access, and interprocess
communication. This means that if there is a security vulnerability that can be taken advantage of by sending signals to another process, it will be possible to exploit it from within a chroot environment.In other words, chroot is not a perfect cure, but rather more of a deterrent.

Every application needs its own set of files and executables, and thus, the directions for making an application work in a chroot environment vary. However, the principle remains the same: Make it all self-contained under a single directory with a faux root directory structure.



An Example Chroot Environment

As an example, let’s create a chroot environment for the BASH shell. We begin by creating the directory we want to put everything into. Since this is just an example, we’ll create a directory in /tmp called myroot.

[root@serverA ~]# mkdir /tmp/myroot
[root@serverA ~]# cd /tmp/myroot

Let’s assume we need only two programs: bash and ls. Let’s create the bin directory under myroot and copy the binaries over there.

[root@serverA myroot]# mkdir bin
[root@serverA myroot]# cp /bin/bash bin/
[root@serverA myroot]# cp /bin/ls bin/


With the binaries there, we now need to check whether these binaries need any libraries. We use the ldd command to determine what (if any) libraries are used by these two programs. We run ldd against /bin/bash, like so:


[root@serverA myroot]# ldd /bin/bash
linux-gate.so.1 => (0x00110000)
libtinfo.so.5 => /lib/libtinfo.so.5 (0x031f3000)
libdl.so.2 => /lib/libdl.so.2 (0x00c1c000)
libc.so.6 => /lib/libc.so.6 (0x00a96000)
/lib/ld-linux.so.2 (0x00a77000)

We also run ldd against /bin/ls, like so:

[root@serverA myroot]# ldd /bin/ls
linux-gate.so.1 => (0x00110000)
librt.so.1 => /lib/librt.so.1 (0x0043b000)
libselinux.so.1 => /lib/libselinux.so.1 (0x0041e000)
libacl.so.1 => /lib/libacl.so.1 (0x00a47000)
libc.so.6 => /lib/libc.so.6 (0x00a96000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00c23000)
/lib/ld-linux.so.2 (0x00a77000)
libdl.so.2 => /lib/libdl.so.2 (0x00c1c000)
libattr.so.1 => /lib/libattr.so.1 (0x00a40000)

Now that we know what libraries need to be in place, we create the lib directory and copy the libraries over.First we create the /tmp/myroot/lib directory:

[root@serverA myroot]# mkdir /tmp/myroot/lib


For shared libraries that /bin/bash needs, we run
[root@serverA myroot]# cp /lib/libtinfo.so.5 lib/
[root@serverA myroot]# cp /lib/libdl.so.2 lib/
[root@serverA myroot]# cp /lib/libc.so.6 lib/
[root@serverA myroot]# cp /lib/ld-linux.so.2 lib/

And for /bin/ls, we need

[root@serverA myroot]# cp /lib/librt.so.1 lib/
[root@serverA myroot]# cp /lib/libselinux.so.1 lib/
[root@serverA myroot]# cp /lib/libacl.so.1 lib/
[root@serverA myroot]# cp /lib/libpthread.so.0 lib/
[root@serverA myroot]# cp /lib/libattr.so.1 lib/

Most Linux distros include a little program called chroot that invokes the chroot() system call for us, so we don’t need to write our own C program to do it. The program takes two parameters: the directory that you want to make the root directory and the command that you want to run in the chroot environment. We want to use /tmp/myroot as the directory and start /bin/bash, thus we run:

[root@serverA myroot]# chroot /tmp/myroot /bin/bash

Because there is no /etc/profile or /etc/bashrc to change our prompt, the prompt will change to

bash-3.00#. Now try an ls:
bash-3.00# ls
bin lib

Then try a pwd to view the current working directory:

bash-3.00# pwd
/

NOTE We didn’t need to explicitly copy over the pwd command used previously, because pwd is one of the many BASH built-in commands. It comes with the BASH program that we already copied over. Since we don’t have an /etc/passwd or /etc/group file in the chrooted environment
(to help map numeric user IDs to usernames), an ls -l command will show the raw user ID (UID) values for each file. For example:

bash-3.2# cd lib/
bash-3.2# ls -l
-rwxr-xr-x 1 0 0 128952 Feb 10 18:09 ld-linux.so.2
-rwxr-xr-x 1 0 0 26156 Feb 10 18:14 libacl.so.1

..........
-rwxr-xr-x 1 0 0 95188 Feb 10 18:05 libtinfo.so.5

With limited commands/executables in a chroot environment, the environment isn’t terribly useful for practical work, which is what makes it great from a security perspective; we give only the minimum files necessary for an application to work, thus minimizing our exposure in the event the application gets compromised. Keep in mind that not all chroot environments need to have a shell and an ls command installed— for example, if the Berkeley Internet Name Domain (BIND) DNS server needs only its own executable, libraries, and zone files installed, then that’s all you need.

No comments:

Post a Comment