English Chinese (Traditional) (zh_TW)
Chapter 4. The Jail Subsystem
The Jail Subsystem
On most UNIX(R) systems, `root` has omnipotent power. This promotes insecurity. If an attacker gained `root` on a system, he would have every function at his fingertips. In FreeBSD there are sysctls which dilute the power of `root`, in order to minimize the damage caused by an attacker. Specifically, one of these functions is called `secure levels`. Similarly, another function which is present from FreeBSD 4.0 and onward, is a utility called man:jail[8]. Jail chroots an environment and sets certain restrictions on processes which are forked within the jail. For example, a jailed process cannot affect processes outside the jail, utilize certain system calls, or inflict any damage on the host environment.
Jail is becoming the new security model. People are running potentially vulnerable servers such as Apache, BIND, and sendmail within jails, so that if an attacker gains `root` within the jail, it is only an annoyance, and not a devastation. This article mainly focuses on the internals (source code) of jail. For information on how to set up a jail see the link:{handbook}#jails/[handbook entry on jails].
Architecture
Jail consists of two realms: the userland program, man:jail[8], and the code implemented within the kernel: the man:jail[2] system call and associated restrictions. I will be discussing the userland program and then how jail is implemented within the kernel.
Userland Code
The source for the userland jail is located in [.filename]#/usr/src/usr.sbin/jail#, consisting of one file, [.filename]#jail.c#. The program takes these arguments: the path of the jail, hostname, IP address, and the command to be executed.
Data Structures
In [.filename]#jail.c#, the first thing I would note is the declaration of an important structure `struct jail j;` which was included from [.filename]#/usr/include/sys/jail.h#.
The definition of the `jail` structure is:
/usr/include/sys/jail.h:
struct jail {
u_int32_t version;
char *path;
char *hostname;
u_int32_t ip_number;
};
As you can see, there is an entry for each of the arguments passed to the man:jail[8] program, and indeed, they are set during its execution.
/usr/src/usr.sbin/jail/jail.c
char path[PATH_MAX];
...
if (realpath(argv[0], path) == NULL)
err(1, "realpath: %s", argv[0]);
if (chdir(path) != 0)
err(1, "chdir: %s", path);
memset(&j, 0, sizeof(j));
j.version = 0;
j.path = path;
j.hostname = argv[1];
Networking
One of the arguments passed to the man:jail[8] program is an IP address with which the jail can be accessed over the network. man:jail[8] translates the IP address given into host byte order and then stores it in `j` (the `jail` structure).
/usr/src/usr.sbin/jail/jail.c:
struct in_addr in;
...
if (inet_aton(argv[2], &in) == 0)
errx(1, "Could not make sense of ip-number: %s", argv[2]);
j.ip_number = ntohl(in.s_addr);
The man:inet_aton[3] function "interprets the specified character string as an Internet address, placing the address into the structure provided." The `ip_number` member in the `jail` structure is set only when the IP address placed onto the `in` structure by man:inet_aton[3] is translated into host byte order by man:ntohl[3].
Jailing the Process