aboutsummaryrefslogtreecommitdiff
path: root/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
diff options
context:
space:
mode:
Diffstat (limited to 'en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml')
-rw-r--r--en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml611
1 files changed, 0 insertions, 611 deletions
diff --git a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
deleted file mode 100644
index 53af59a441..0000000000
--- a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
+++ /dev/null
@@ -1,611 +0,0 @@
-<!--
- The FreeBSD Documentation Project
-
- $FreeBSD$
--->
-
-<chapter id="jail">
- <chapterinfo>
- <author><firstname>Evan Sarmiento</firstname>
- <affiliation><address><email>evms@cs.bu.edu</email></address>
- </affiliation>
- </author>
- <copyright>
- <year>2001</year>
- <holder role="mailto:evms@cs.bu.edu">Evan Sarmiento</holder>
- </copyright>
- </chapterinfo>
- <title>The Jail Subsystem</title>
-
- <para>On most UNIX systems, root has omnipotent power. This promotes
- insecurity. If an attacker were to gain 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;. <application>Jail</application> chroots an
- environment and sets certain restrictions on processes which are
- forked from within. For example, a jailed process cannot affect
- processes outside of the jail, utilize certain system calls, or
- inflict any damage on the main computer.</para>
-
- <para><application>Jail</application> 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 <application>Jail</application>, it is only
- an annoyance, and not a devastation. This article focuses on the
- internals (source code) of <application>Jail</application> and
- <application>Jail</application> NG. It will also suggest
- improvements upon the jail code base which are already being
- worked on. If you are looking for a how-to on setting up a
- <application>Jail</application>, I suggest you look at my other
- article in Sys Admin Magazine, May 2001, entitled "Securing
- FreeBSD using <application>Jail</application>."</para>
-
- <sect1 id="jail-arch">
- <title>Architecture</title>
-
- <para>
- <application>Jail</application> consists of two realms: the
- user-space program, jail, and the code implemented within the
- kernel: the <literal>jail()</literal> system call and associated
- restrictions. I will be discussing the user-space program and
- then how jail is implemented within the kernel.</para>
-
- <sect2>
- <title>Userland code</title>
-
- <para>The source for the user-land jail is located in
- <filename>/usr/src/usr.sbin/jail</filename>, consisting of
- one file, <filename>jail.c</filename>. The program takes these
- arguments: the path of the jail, hostname, ip address, and the
- command to be executed.</para>
-
- <sect3>
- <title>Data Structures</title>
-
- <para>In <filename>jail.c</filename>, the first thing I would
- note is the declaration of an important structure
- <literal>struct jail j</literal>; which was included from
- <filename>/usr/include/sys/jail.h</filename>.
-
- <para>The definition of the jail structure is:</para>
-
-<programlisting><filename>/usr/include/sys/jail.h</filename>:
-
-struct jail {
- u_int32_t version;
- char *path;
- char *hostname;
- u_int32_t ip_number;
-};</programlisting>
-
- <para>As you can see, there is an entry for each of the
- arguments passed to the jail program, and indeed, they are
- set during it's execution.</para>
-
- <programlisting><filename>/usr/src/usr.sbin/jail.c</filename>
-j.version = 0;
-j.path = argv[1];
-j.hostname = argv[2];</programlisting>
-
- </sect3>
-
- <sect3>
- <title>Networking</title>
-
- <para>One of the arguments passed to the Jail program is an IP
- address with which the jail can be accessed over the
- network. Jail translates the ip address given into network
- byte order and then stores it in j (the jail structure).</para>
-
- <programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>:
-struct in.addr in;
-...
-i = inet.aton(argv[3], <![CDATA[&in]]>);
-...
-j.ip_number = ntohl(in.s.addr);</programlisting>
-
- <para>The
- <citerefentry><refentrytitle>inet_aton</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- function "interprets the specified character string as an
- Internet address, placing the address into the structure
- provided." The ip number node in the jail structure is set
- only when the ip address placed onto the in structure by
- inet aton is translated into network byte order by
- <function>ntohl()</function>.</para>
-
- </sect3>
-
- <sect3>
- <title>Jailing The Process</title>
-
- <para>Finally, the userland program jails the process, and
- executes the command specified. Jail now becomes an
- imprisoned process itself and forks a child process which
- then executes the command given using &man.execv.3;
-
- <programlisting><filename>/usr/src/sys/usr.sbin/jail/jail.c</filename>
-i = jail(<![CDATA[&j]]>);
-...
-i = execv(argv[4], argv + 4);</programlisting>
-
- <para>As you can see, the jail function is being called, and
- its argument is the jail structure which has been filled
- with the arguments given to the program. Finally, the
- program you specify is executed. I will now discuss how Jail
- is implemented within the kernel.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Kernel Space</title>
-
- <para>We will now be looking at the file
- <filename>/usr/src/sys/kern/kern_jail.c</filename>. This is
- the file where the jail system call, appropriate sysctls, and
- networking functions are defined.</para>
-
- <sect3>
- <title>sysctls</title>
-
- <para>In <filename>kern_jail.c</filename>, the following
- sysctls are defined:</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
-
-int jail_set_hostname_allowed = 1;
-SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
- <![CDATA[&jail]]>_set_hostname_allowed, 0,
- "Processes in jail can set their hostnames");
-
-int jail_socket_unixiproute_only = 1;
-SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
- <![CDATA[&jail]]>_socket_unixiproute_only, 0,
- "Processes in jail are limited to creating UNIX/IPv4/route sockets only
-");
-
-int jail_sysvipc_allowed = 0;
-SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
- <![CDATA[&jail]]>_sysvipc_allowed, 0,
- "Processes in jail can use System V IPC primitives");</programlisting>
-
- <para>Each of these sysctls can be accessed by the user
- through the sysctl program. Throughout the kernel, these
- specific sysctls are recognized by their name. For example,
- the name of the first sysctl is
- <literal>jail.set.hostname.allowed</literal>.</para>
- </sect3>
-
- <sect3>
- <title>&man.jail.2; system call</title>
-
- <para>Like all system calls, the &man.jail.2; system call takes
- two arguments, <literal>struct proc *p</literal> and
- <literal>struct jail_args
- *uap</literal>. <literal>p</literal> is a pointer to a proc
- structure which describes the calling process. In this
- context, uap is a pointer to a structure which specifies the
- arguments given to &man.jail.2; from the userland program
- <filename>jail.c</filename>. When I described the userland
- program before, you saw that the &man.jail.2; system call was
- given a jail structure as its own argument.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
-int
-jail(p, uap)
- struct proc *p;
- struct jail_args /* {
- syscallarg(struct jail *) jail;
- } */ *uap;</programlisting>
-
- <para>Therefore, <literal>uap->jail</literal> would access the
- jail structure which was passed to the system call. Next,
- the system call copies the jail structure into kernel space
- using the <literal>copyin()</literal>
- function. <literal>copyin()</literal> takes three arguments:
- the data which is to be copied into kernel space,
- <literal>uap->jail</literal>, where to store it,
- <literal>j</literal> and the size of the storage. The jail
- structure <literal>uap->jail</literal> is copied into kernel
- space and stored in another jail structure,
- <literal>j</literal>.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c: </filename>
-error = copyin(uap->jail, <![CDATA[&j]]>, sizeof j);</programlisting>
-
- <para>There is another important structure defined in
- jail.h. It is the prison structure
- (<literal>pr</literal>). The prison structure is used
- exclusively within kernel space. The &man.jail.2; system call
- copies everything from the jail structure onto the prison
- structure. Here is the definition of the prison structure.</para>
-
- <programlisting><filename>/usr/include/sys/jail.h</filename>:
-struct prison {
- int pr_ref;
- char pr_host[MAXHOSTNAMELEN];
- u_int32_t pr_ip;
- void *pr_linux;
-};</programlisting>
-
- <para>The jail() system call then allocates memory for a
- pointer to a prison structure and copies data between the two
- structures.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
- MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK);
- bzero((caddr_t)pr, sizeof *pr);
- error = copyinstr(j.hostname, <![CDATA[&pr->pr_host]]>, sizeof pr->pr_host, 0);
- if (error)
- goto bail;</programlisting>
-
- <para>Finally, the jail system call chroots the path
- specified. The chroot function is given two arguments. The
- first is p, which represents the calling process, the second
- is a pointer to the structure chroot args. The structure
- chroot args contains the path which is to be chrooted. As
- you can see, the path specified in the jail structure is
- copied to the chroot args structure and used.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
-ca.path = j.path;
-error = chroot(p, <![CDATA[&ca]]>);</programlisting>
-
- <para>These next three lines in the source are very important,
- as they specify how the kernel recognizes a process as
- jailed. Each process on a Unix system is described by its
- own proc structure. You can see the whole proc structure in
- <filename>/usr/include/sys/proc.h</filename>. For example,
- the p argument in any system call is actually a pointer to
- that process' proc structure, as stated before. The proc
- structure contains nodes which can describe the owner's
- identity (<literal>p_cred</literal>), the process resource
- limits (<literal>p_limit</literal>), and so on. In the
- definition of the process structure, there is a pointer to a
- prison structure. (<literal>p_prison</literal>).</para>
-
- <programlisting><filename>/usr/include/sys/proc.h: </filename>
-struct proc {
-...
-struct prison *p_prison;
-...
-};</programlisting>
-
- <para>In <filename>kern_jail.c</filename>, the function then
- copies the pr structure, which is filled with all the
- information from the original jail structure, over to the
- <literal>p->p_prison</literal> structure. It then does a
- bitwise OR of <literal>p->p_flag</literal> with the constant
- <literal>P_JAILED</literal>, meaning that the calling
- process is now recognized as jailed. The parent process of
- each process, forked within the jail, is the program jail
- itself, as it calls the &man.jail.2; system call. When the
- program is executed through execve, it inherits the
- properties of its parents proc structure, therefore it has
- the <literal>p->p_flag</literal> set, and the
- <literal>p->p_prison</literal> structure is filled.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>
-p->p.prison = pr;
-p->p.flag |= P.JAILED;</programlisting>
-
- <para>When a process is forked from a parent process, the
- &man.fork.2; system call deals differently with imprisoned
- processes. In the fork system call, there are two pointers
- to a <literal>proc</literal> structure <literal>p1</literal>
- and <literal>p2</literal>. <literal>p1</literal> points to
- the parent's <literal>proc</literal> structure and p2 points
- to the child's unfilled <literal>proc</literal>
- structure. After copying all relevant data between the
- structures, &man.fork.2; checks if the structure
- <literal>p->p_prison</literal> is filled on
- <literal>p2</literal>. If it is, it increments the
- <literal>pr.ref</literal> by one, and sets the
- <literal>p_flag</literal> to one on the child process.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_fork.c</filename>:
-if (p2->p_prison) {
- p2->p_prison->pr_ref++;
- p2->p_flag |= P_JAILED;
-}</programlisting>
-
- </sect3>
- </sect2>
- </sect1>
-
- <sect1 id="jail-restrictions">
- <title>Restrictions</title>
-
- <para>Throughout the kernel there are access restrictions relating
- to jailed processes. Usually, these restrictions only check if
- the process is jailed, and if so, returns an error. For
- example:</para>
-
- <programlisting>if (p->p_prison)
- return EPERM;</programlisting>
-
- <sect2>
- <title>SysV IPC</title>
-
- <para>System V IPC is based on messages. Processes can send each
- other these messages which tell them how to act. The functions
- which deal with messages are: <literal>msgsys</literal>,
- <literal>msgctl</literal>, <literal>msgget</literal>,
- <literal>msgsend</literal> and <literal>msgrcv</literal>.
- Earlier, I mentioned that there were certain sysctls you could
- turn on or off in order to affect the behavior of Jail. One of
- these sysctls was <literal>jail_sysvipc_allowed</literal>. On
- most systems, this sysctl is set to 0. If it were set to 1, it
- would defeat the whole purpose of having a jail; privleged
- users from within the jail would be able to affect processes
- outside of the environment. The difference between a message
- and a signal is that the message only consists of the signal
- number.</para>
-
- <para><filename>/usr/src/sys/kern/sysv_msg.c</filename>:</para>
-
- <itemizedlist>
- <listitem> <para>&man.msgget.3;: msgget returns (and possibly
- creates) a message descriptor that designates a message queue
- for use in other system calls.</para></listitem>
-
- <listitem> <para>&man.msgctl.3;: Using this function, a process
- can query the status of a message
- descriptor.</para></listitem>
-
- <listitem> <para>&man.msgsnd.3;: msgsnd sends a message to a
- process.</para></listitem>
-
- <listitem> <para>&man.msgrcv.3;: a process receives messages using
- this function</para></listitem>
-
- </itemizedlist>
-
- <para>In each of these system calls, there is this
- conditional:</para>
-
- <programlisting><filename>/usr/src/sys/kern/sysv msg.c</filename>:
-if (!jail.sysvipc.allowed && p->p_prison != NULL)
- return (ENOSYS);</programlisting>
-
- <para>Semaphore system calls allow processes to synchronize
- execution by doing a set of operations atomically on a set of
- semaphores. Basically semaphores provide another way for
- processes lock resources. However, process waiting on a
- semaphore, that is being used, will sleep until the resources
- are relinquished. The following semaphore system calls are
- blocked inside a jail: <literal>semsys</literal>,
- <literal>semget</literal>, <literal>semctl</literal> and
- <literal>semop</literal>.</para>
-
- <para><filename>/usr/src/sys/kern/sysv_sem.c</filename>:</para>
-
- <itemizedlist>
- <listitem>
- <para>&man.semctl.2;<literal>(id, num, cmd, arg)</literal>:
- Semctl does the specified cmd on the semaphore queue
- indicated by id.</para></listitem>
-
- <listitem>
- <para>&man.semget.2;<literal>(key, nsems, flag)</literal>:
- Semget creates an array of semaphores, corresponding to
- key.</para>
-
- <para><literal>Key and flag take on the same meaning as they
- do in msgget.</literal></para></listitem>
-
- <listitem><para>&man.semop.2;<literal>(id, ops, num)</literal>:
- Semop does the set of semaphore operations in the array of
- structures ops, to the set of semaphores identified by
- id.</para></listitem>
- </itemizedlist>
-
- <para>System V IPC allows for processes to share
- memory. Processes can communicate directly with each other by
- sharing parts of their virtual address space and then reading
- and writing data stored in the shared memory. These system
- calls are blocked within a jailed environment: <literal>shmdt,
- shmat, oshmctl, shmctl, shmget</literal>, and
- <literal>shmsys</literal>.</para>
-
- <para><filename>/usr/src/sys/kern/sysv shm.c</filename>:</para>
-
- <itemizedlist>
- <listitem><para>&man.shmctl.2;<literal>(id, cmd, buf)</literal>:
- shmctl does various control operations on the shared memory
- region identified by id.</para></listitem>
-
- <listitem><para>&man.shmget.2;<literal>(key, size,
- flag)</literal>: shmget accesses or creates a shared memory
- region of size bytes.</para></listitem>
-
- <listitem><para>&man.shmat.2;<literal>(id, addr, flag)</literal>:
- shmat attaches a shared memory region identified by id to the
- address space of a process.</para></listitem>
-
- <listitem><para>&man.shmdt.2;<literal>(addr)</literal>: shmdt
- detaches the shared memory region previously attached at
- addr.</para></listitem>
-
- </itemizedlist>
- </sect2>
-
- <sect2>
- <title>Sockets</title>
-
- <para>Jail treats the &man.socket.2; system call and related
- lower-level socket functions in a special manner. In order to
- determine whether a certain socket is allowed to be created,
- it first checks to see if the sysctl
- <literal>jail.socket.unixiproute.only</literal> is set. If
- set, sockets are only allowed to be created if the family
- specified is either <literal>PF_LOCAL</literal>,
- <literal>PF_INET</literal> or
- <literal>PF_ROUTE</literal>. Otherwise, it returns an
- error.</para>
-
- <programlisting><filename>/usr/src/sys/kern/uipc_socket.c</filename>:
-int socreate(dom, aso, type, proto, p)
-...
-register struct protosw *prp;
-...
-{
- if (p->p_prison && jail_socket_unixiproute_only &&
- prp->pr_domain->dom_family != PR_LOCAL && prp->pr_domain->dom_family != PF_INET
- && prp->pr_domain->dom_family != PF_ROUTE)
- return (EPROTONOSUPPORT);
-...
-}</programlisting>
-
- </sect2>
-
- <sect2>
- <title>Berkeley Packet Filter</title>
-
- <para>The Berkeley Packet Filter provides a raw interface to
- data link layers in a protocol independent fashion. The
- function <literal>bpfopen()</literal> opens an Ethernet
- device. There is a conditional which disallows any jailed
- processes from accessing this function.</para>
-
- <programlisting><filename>/usr/src/sys/net/bpf.c</filename>:
-static int bpfopen(dev, flags, fmt, p)
-...
-{
- if (p->p_prison)
- return (EPERM);
-...
-}</programlisting>
-
- </sect2>
-
- <sect2>
- <title>Protocols</title>
-
- <para>There are certain protocols which are very common, such as
- TCP, UDP, IP and ICMP. IP and ICMP are on the same level: the
- network layer 2. There are certain precautions which are
- taken in order to prevent a jailed process from binding a
- protocol to a certain port only if the <literal>nam</literal>
- parameter is set. nam is a pointer to a sockaddr structure,
- which describes the address on which to bind the service. A
- more exact definition is that sockaddr "may be used as a
- template for reffering to the identifying tag and length of
- each address"[2]. In the function in
- <literal>pcbbind</literal>, <literal>sin</literal> is a
- pointer to a sockaddr.in structure, which contains the port,
- address, length and domain family of the socket which is to be
- bound. Basically, this disallows any processes from jail to be
- able to specify the domain family.</para>
-
- <programlisting><filename>/usr/src/sys/kern/netinet/in_pcb.c</filename>:
-int in.pcbbind(int, nam, p)
-...
- struct sockaddr *nam;
- struct proc *p;
-{
- ...
- struct sockaddr.in *sin;
- ...
- if (nam) {
- sin = (struct sockaddr.in *)nam;
- ...
- if (sin->sin_addr.s_addr != INADDR_ANY)
- if (prison.ip(p, 0, <![CDATA[&sin]]>->sin.addr.s_addr))
- return (EINVAL);
- ....
- }
-...
-}</programlisting>
-
- <para>You might be wondering what function
- <literal>prison_ip()</literal> does. prison.ip is given three
- arguments, the current process (represented by
- <literal>p</literal>), any flags, and an ip address. It
- returns 1 if the ip address belongs to a jail or 0 if it does
- not. As you can see from the code, if it is indeed an ip
- address belonging to a jail, the protcol is not allowed to
- bind to a certain port.</para>
-
- <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
-int prison_ip(struct proc *p, int flag, u_int32_t *ip) {
- u_int32_t tmp;
-
- if (!p->p_prison)
- return (0);
- if (flag)
- tmp = *ip;
- else tmp = ntohl (*ip);
-
- if (tmp == INADDR_ANY) {
- if (flag)
- *ip = p->p_prison->pr_ip;
- else *ip = htonl(p->p_prison->pr_ip);
- return (0);
- }
-
- if (p->p_prison->pr_ip != tmp)
- return (1);
- return (0);
-}</programlisting>
-
- <para>Jailed users are not allowed to bind services to an ip
- which does not belong to the jail. The restriction is also
- written within the function <literal>in_pcbbind</literal>:</para>
-
- <programlisting><filename>/usr/src/sys/net inet/in_pcb.c</filename>
- if (nam) {
- ...
- lport = sin->sin.port;
- ... if (lport) {
- ...
- if (p && p->p_prison)
- prison = 1;
- if (prison &&
- prison_ip(p, 0, <![CDATA[&sin]]>->sin_addr.s_addr))
- return (EADDRNOTAVAIL);</programlisting>
-
- </sect2>
-
- <sect2>
- <title>Filesystem</title>
-
- <para>Even root users within the jail are not allowed to set any
- file flags, such as immutable, append, and no unlink flags, if
- the securelevel is greater than 0.</para>
-
- <programlisting>/usr/src/sys/ufs/ufs/ufs_vnops.c:
-int ufs.setattr(ap)
- ...
-{
- if ((cred->cr.uid == 0) && (p->prison == NULL)) {
- if ((ip->i_flags
- & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
- securelevel > 0)
- return (EPERM);
-}</programlisting>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="jail-jailng">
- <title>Jail NG</title>
-
- <para>Jail NG is a "from-scratch re-implementation of Jail" by
- Robert Watson, a FreeBSD committer. Some of the new features
- include the ability to add processes to a jail, an improved
- management tool, and per-jail sysctls. For example, you could
- have <literal>sysvipc_permitted</literal> set on one jail while
- another jail may be allowed to use System V IPC. You can
- download the kernel patches and utilities for Jail NG from his
- website at:
- <ulink
- url="http://www.watson.org/~robert/jailng/"></ulink>.</para>
-
- </sect1>
-
-</chapter>
-