Clean up some errors that were reported by textproc/igor:
- Bad tag indents - Wrap long lines - Two spaces at sentence start
This commit is contained in:
parent
892468b17f
commit
93632dc9d5
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=52176
1 changed files with 354 additions and 307 deletions
|
@ -4,53 +4,68 @@
|
|||
|
||||
$FreeBSD$
|
||||
-->
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="jail">
|
||||
<info><title>The Jail Subsystem</title>
|
||||
<author><personname><firstname>Evan</firstname><surname>Sarmiento</surname></personname><affiliation>
|
||||
<address><email>evms@cs.bu.edu</email></address>
|
||||
</affiliation></author>
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
|
||||
xml:id="jail">
|
||||
<info>
|
||||
<title>The Jail Subsystem</title>
|
||||
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Evan</firstname>
|
||||
<surname>Sarmiento</surname>
|
||||
</personname>
|
||||
<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>
|
||||
</info>
|
||||
|
||||
|
||||
<indexterm><primary>security</primary></indexterm>
|
||||
<indexterm><primary>Jail</primary></indexterm>
|
||||
<indexterm><primary>root</primary></indexterm>
|
||||
|
||||
<para>On most &unix; systems, <literal>root</literal> has omnipotent power.
|
||||
This promotes insecurity. If an attacker gained <literal>root</literal>
|
||||
on a system, he would have every function at his fingertips. In FreeBSD
|
||||
there are sysctls which dilute the power of <literal>root</literal>, in
|
||||
order to minimize the damage caused by an attacker. Specifically, one of
|
||||
these functions is called <literal>secure levels</literal>. 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 within
|
||||
the <application>jail</application>. For example, a jailed process
|
||||
cannot affect processes outside the <application>jail</application>,
|
||||
utilize certain system calls, or inflict any damage on the host
|
||||
environment.</para>
|
||||
<para>On most &unix; systems, <literal>root</literal> has omnipotent
|
||||
power. This promotes insecurity. If an attacker gained
|
||||
<literal>root</literal> on a system, he would have every function
|
||||
at his fingertips. In FreeBSD there are sysctls which dilute the
|
||||
power of <literal>root</literal>, in order to minimize the damage
|
||||
caused by an attacker. Specifically, one of these functions is
|
||||
called <literal>secure levels</literal>. 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 within the <application>jail</application>. For
|
||||
example, a jailed process cannot affect processes outside the
|
||||
<application>jail</application>, utilize certain system calls, or
|
||||
inflict any damage on the host environment.</para>
|
||||
|
||||
<para><application>Jail</application> is becoming the new security
|
||||
model. People are running potentially vulnerable servers such as
|
||||
<application>Apache</application>, <application>BIND</application>, and
|
||||
<application>sendmail</application> within jails, so that if an attacker
|
||||
gains <literal>root</literal> within the <application>jail</application>,
|
||||
it is only an annoyance, and not a devastation. This article mainly
|
||||
focuses on the internals (source code) of <application>jail</application>.
|
||||
For information on how to set up a jail see the <link xlink:href="&url.books.handbook;/jails.html">handbook entry on jails</link>.</para>
|
||||
model. People are running potentially vulnerable servers such as
|
||||
<application>Apache</application>,
|
||||
<application>BIND</application>, and
|
||||
<application>sendmail</application> within jails, so that if an
|
||||
attacker gains <literal>root</literal> within the
|
||||
<application>jail</application>, it is only an annoyance, and not
|
||||
a devastation. This article mainly focuses on the internals
|
||||
(source code) of <application>jail</application>. For information
|
||||
on how to set up a jail see the <link
|
||||
xlink:href="&url.books.handbook;/jails.html">handbook entry on
|
||||
jails</link>.</para>
|
||||
|
||||
<sect1 xml:id="jail-arch">
|
||||
<title>Architecture</title>
|
||||
|
||||
<para>
|
||||
<application>Jail</application> consists of two realms: the
|
||||
<para><application>Jail</application> 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
|
||||
restrictions. I will be discussing the userland program and
|
||||
then how <application>jail</application> is implemented within
|
||||
the kernel.</para>
|
||||
|
||||
|
@ -60,24 +75,25 @@
|
|||
<indexterm><primary>Jail</primary>
|
||||
<secondary>Userland Program</secondary></indexterm>
|
||||
|
||||
<para>The source for the userland <application>jail</application>
|
||||
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 <application>jail</application>,
|
||||
hostname, IP address, and the command to be executed.</para>
|
||||
<para>The source for the userland
|
||||
<application>jail</application> 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 <application>jail</application>,
|
||||
hostname, IP address, and the command to be executed.</para>
|
||||
|
||||
<sect3>
|
||||
<title>Data Structures</title>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<para>The definition of the <literal>jail</literal> structure is:
|
||||
</para>
|
||||
<para>The definition of the <literal>jail</literal> structure
|
||||
is:</para>
|
||||
|
||||
<programlisting><filename>/usr/include/sys/jail.h</filename>:
|
||||
<programlisting><filename>/usr/include/sys/jail.h</filename>:
|
||||
|
||||
struct jail {
|
||||
u_int32_t version;
|
||||
|
@ -86,11 +102,11 @@ struct jail {
|
|||
u_int32_t ip_number;
|
||||
};</programlisting>
|
||||
|
||||
<para>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.</para>
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>
|
||||
char path[PATH_MAX];
|
||||
...
|
||||
if (realpath(argv[0], path) == NULL)
|
||||
|
@ -101,54 +117,55 @@ memset(&j, 0, sizeof(j));
|
|||
j.version = 0;
|
||||
j.path = path;
|
||||
j.hostname = argv[1];</programlisting>
|
||||
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Networking</title>
|
||||
<title>Networking</title>
|
||||
|
||||
<para>One of the arguments passed to the &man.jail.8; program is
|
||||
an IP address with which the <application>jail</application>
|
||||
can be accessed over the network. &man.jail.8; translates the
|
||||
IP address given into host byte order and then stores it in
|
||||
<literal>j</literal> (the <literal>jail</literal> structure).</para>
|
||||
<para>One of the arguments passed to the &man.jail.8; program
|
||||
is an IP address with which the
|
||||
<application>jail</application> can be accessed over the
|
||||
network. &man.jail.8; translates the IP address given into
|
||||
host byte order and then stores it in <literal>j</literal>
|
||||
(the <literal>jail</literal> structure).</para>
|
||||
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>:
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>:
|
||||
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);</programlisting>
|
||||
|
||||
<para>The &man.inet.aton.3; function "interprets the specified
|
||||
character string as an Internet address, placing the address
|
||||
into the structure provided." The <literal>ip_number</literal>
|
||||
member in the <literal>jail</literal> structure is set only
|
||||
when the IP address placed onto the <literal>in</literal>
|
||||
structure by &man.inet.aton.3; is translated into host byte
|
||||
order by &man.ntohl.3;.</para>
|
||||
|
||||
<para>The &man.inet.aton.3; function "interprets the specified
|
||||
character string as an Internet address, placing the address
|
||||
into the structure provided." The
|
||||
<literal>ip_number</literal> member in the
|
||||
<literal>jail</literal> structure is set only when the IP
|
||||
address placed onto the <literal>in</literal> structure by
|
||||
&man.inet.aton.3; is translated into host byte order by
|
||||
&man.ntohl.3;.</para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Jailing the Process</title>
|
||||
<title>Jailing the Process</title>
|
||||
|
||||
<para>Finally, the userland program jails the process.
|
||||
<application>Jail</application> now becomes an imprisoned
|
||||
process itself and then executes the command given using
|
||||
&man.execv.3;.</para>
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>
|
||||
<para>Finally, the userland program jails the process.
|
||||
<application>Jail</application> now becomes an imprisoned
|
||||
process itself and then executes the command given using
|
||||
&man.execv.3;.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>
|
||||
i = jail(&j);
|
||||
...
|
||||
if (execv(argv[3], argv + 3) != 0)
|
||||
err(1, "execv: %s", argv[3]);</programlisting>
|
||||
|
||||
<para>As you can see, the <literal>jail()</literal> function is
|
||||
called, and its argument is the <literal>jail</literal> structure
|
||||
which has been filled with the arguments given to the program.
|
||||
Finally, the program you specify is executed. I will now discuss
|
||||
how <application>jail</application> is implemented within the
|
||||
kernel.</para>
|
||||
<para>As you can see, the <literal>jail()</literal> function
|
||||
is called, and its argument is the <literal>jail</literal>
|
||||
structure which has been filled with the arguments given to
|
||||
the program. Finally, the program you specify is executed.
|
||||
I will now discuss how <application>jail</application> is
|
||||
implemented within the kernel.</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
|
@ -159,20 +176,19 @@ if (execv(argv[3], argv + 3) != 0)
|
|||
<secondary>Kernel Architecture</secondary></indexterm>
|
||||
|
||||
<para>We will now be looking at the file
|
||||
<filename>/usr/src/sys/kern/kern_jail.c</filename>. This is
|
||||
the file where the &man.jail.2; system call, appropriate sysctls,
|
||||
and networking functions are defined.</para>
|
||||
<filename>/usr/src/sys/kern/kern_jail.c</filename>. This is
|
||||
the file where the &man.jail.2; system call, appropriate
|
||||
sysctls, and networking functions are defined.</para>
|
||||
|
||||
<sect3>
|
||||
<title>sysctls</title>
|
||||
<title>Sysctls</title>
|
||||
|
||||
<indexterm><primary>sysctl</primary></indexterm>
|
||||
<indexterm><primary>sysctl</primary></indexterm>
|
||||
|
||||
<para>In <filename>kern_jail.c</filename>, the following
|
||||
sysctls are defined:</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
|
||||
<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(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
|
||||
&jail_set_hostname_allowed, 0,
|
||||
|
@ -208,29 +224,30 @@ SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
|
|||
&jail_mount_allowed, 0,
|
||||
"Processes in jail can mount/unmount jail-friendly file systems");</programlisting>
|
||||
|
||||
<para>Each of these sysctls can be accessed by the user
|
||||
through the &man.sysctl.8; program. Throughout the kernel, these
|
||||
specific sysctls are recognized by their name. For example,
|
||||
the name of the first sysctl is
|
||||
<literal>security.jail.set_hostname_allowed</literal>.</para>
|
||||
<para>Each of these sysctls can be accessed by the user
|
||||
through the &man.sysctl.8; program. Throughout the kernel,
|
||||
these specific sysctls are recognized by their name. For
|
||||
example, the name of the first sysctl is
|
||||
<literal>security.jail.set_hostname_allowed</literal>.</para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>&man.jail.2; System Call</title>
|
||||
<title>&man.jail.2; System Call</title>
|
||||
|
||||
<para>Like all system calls, the &man.jail.2; system call takes
|
||||
two arguments, <literal>struct thread *td</literal> and
|
||||
<literal>struct jail_args *uap</literal>.
|
||||
<literal>td</literal> is a pointer to the <literal>thread</literal>
|
||||
structure which describes the calling thread. In this
|
||||
context, <literal>uap</literal> is a pointer to the structure
|
||||
in which a pointer to the <literal>jail</literal> structure
|
||||
passed by the userland <filename>jail.c</filename> is contained.
|
||||
When I described the userland program before, you saw that the
|
||||
&man.jail.2; system call was given a <literal>jail</literal>
|
||||
structure as its own argument.</para>
|
||||
<para>Like all system calls, the &man.jail.2; system call
|
||||
takes two arguments, <literal>struct thread *td</literal>
|
||||
and <literal>struct jail_args *uap</literal>.
|
||||
<literal>td</literal> is a pointer to the
|
||||
<literal>thread</literal> structure which describes the
|
||||
calling thread. In this context, <literal>uap</literal> is
|
||||
a pointer to the structure in which a pointer to the
|
||||
<literal>jail</literal> structure passed by the userland
|
||||
<filename>jail.c</filename> is contained. When I described
|
||||
the userland program before, you saw that the &man.jail.2;
|
||||
system call was given a <literal>jail</literal> structure as
|
||||
its own argument.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
|
||||
/*
|
||||
* struct jail_args {
|
||||
* struct jail *jail;
|
||||
|
@ -239,29 +256,30 @@ SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
|
|||
int
|
||||
jail(struct thread *td, struct jail_args *uap)</programlisting>
|
||||
|
||||
<para>Therefore, <literal>uap->jail</literal> can be used to
|
||||
access the <literal>jail</literal> structure which was passed
|
||||
to the system call. Next, the system call copies the
|
||||
<literal>jail</literal> structure into kernel space using
|
||||
the &man.copyin.9; function. &man.copyin.9; takes three arguments:
|
||||
the address of 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
|
||||
<literal>jail</literal> structure pointed by
|
||||
<literal>uap->jail</literal> is copied into kernel space and
|
||||
is stored in another <literal>jail</literal> structure,
|
||||
<literal>j</literal>.</para>
|
||||
<para>Therefore, <literal>uap->jail</literal> can be used
|
||||
to access the <literal>jail</literal> structure which was
|
||||
passed to the system call. Next, the system call copies the
|
||||
<literal>jail</literal> structure into kernel space using
|
||||
the &man.copyin.9; function. &man.copyin.9; takes three
|
||||
arguments: the address of 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 <literal>jail</literal> structure pointed by
|
||||
<literal>uap->jail</literal> is copied into kernel space
|
||||
and is stored in another <literal>jail</literal> structure,
|
||||
<literal>j</literal>.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c: </filename>
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
|
||||
error = copyin(uap->jail, &j, sizeof(j));</programlisting>
|
||||
|
||||
<para>There is another important structure defined in
|
||||
<filename>jail.h</filename>. It is the <literal>prison</literal>
|
||||
structure. The <literal>prison</literal> structure is used
|
||||
exclusively within kernel space. Here is the definition of the
|
||||
<literal>prison</literal> structure.</para>
|
||||
<para>There is another important structure defined in
|
||||
<filename>jail.h</filename>. It is the
|
||||
<literal>prison</literal> structure. The
|
||||
<literal>prison</literal> structure is used exclusively
|
||||
within kernel space. Here is the definition of the
|
||||
<literal>prison</literal> structure.</para>
|
||||
|
||||
<programlisting><filename>/usr/include/sys/jail.h</filename>:
|
||||
<programlisting><filename>/usr/include/sys/jail.h</filename>:
|
||||
struct prison {
|
||||
LIST_ENTRY(prison) pr_list; /* (a) all prisons */
|
||||
int pr_id; /* (c) prison id */
|
||||
|
@ -277,12 +295,12 @@ struct prison {
|
|||
void **pr_slots; /* (p) additional data */
|
||||
};</programlisting>
|
||||
|
||||
<para>The &man.jail.2; system call then allocates memory for
|
||||
a <literal>prison</literal> structure and copies data between
|
||||
the <literal>jail</literal> and <literal>prison</literal>
|
||||
structure.</para>
|
||||
<para>The &man.jail.2; system call then allocates memory for a
|
||||
<literal>prison</literal> structure and copies data between
|
||||
the <literal>jail</literal> and <literal>prison</literal>
|
||||
structure.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
|
||||
MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
|
||||
...
|
||||
error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
|
||||
|
@ -293,10 +311,12 @@ error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
|
|||
if (error)
|
||||
goto e_dropvnref;
|
||||
pr->pr_ip = j.ip_number;</programlisting>
|
||||
<para>Next, we will discuss another important system call
|
||||
&man.jail.attach.2;, which implements the function to put
|
||||
a process into the <application>jail</application>.</para>
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
|
||||
|
||||
<para>Next, we will discuss another important system call
|
||||
&man.jail.attach.2;, which implements the function to put a
|
||||
process into the <application>jail</application>.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>:
|
||||
/*
|
||||
* struct jail_attach_args {
|
||||
* int jid;
|
||||
|
@ -304,34 +324,37 @@ pr->pr_ip = j.ip_number;</programlisting>
|
|||
*/
|
||||
int
|
||||
jail_attach(struct thread *td, struct jail_attach_args *uap)</programlisting>
|
||||
<para>This system call makes the changes that can distinguish
|
||||
a jailed process from those unjailed ones.
|
||||
To understand what &man.jail.attach.2; does for us, certain
|
||||
background information is needed.</para>
|
||||
<para>
|
||||
On FreeBSD, each kernel visible thread is identified by its
|
||||
<literal>thread</literal> structure, while the processes are
|
||||
described by their <literal>proc</literal> structures. You can
|
||||
find the definitions of the <literal>thread</literal> and
|
||||
<literal>proc</literal> structure in
|
||||
<filename>/usr/include/sys/proc.h</filename>.
|
||||
For example, the <literal>td</literal> argument in any system
|
||||
call is actually a pointer to the calling thread's
|
||||
<literal>thread</literal> structure, as stated before.
|
||||
The <literal>td_proc</literal> member in the
|
||||
<literal>thread</literal> structure pointed by <literal>td</literal>
|
||||
is a pointer to the <literal>proc</literal> structure which
|
||||
represents the process that contains the thread represented by
|
||||
<literal>td</literal>. The <literal>proc</literal> structure
|
||||
contains members which can describe the owner's
|
||||
identity(<literal>p_ucred</literal>), the process resource
|
||||
limits(<literal>p_limit</literal>), and so on. In the
|
||||
<literal>ucred</literal> structure pointed by
|
||||
<literal>p_ucred</literal> member in the <literal>proc</literal>
|
||||
structure, there is a pointer to the <literal>prison</literal>
|
||||
structure(<literal>cr_prison</literal>).</para>
|
||||
|
||||
<programlisting><filename>/usr/include/sys/proc.h: </filename>
|
||||
<para>This system call makes the changes that can distinguish
|
||||
a jailed process from those unjailed ones. To understand
|
||||
what &man.jail.attach.2; does for us, certain background
|
||||
information is needed.</para>
|
||||
|
||||
<para>On FreeBSD, each kernel visible thread is identified by
|
||||
its <literal>thread</literal> structure, while the processes
|
||||
are described by their <literal>proc</literal> structures.
|
||||
You can find the definitions of the
|
||||
<literal>thread</literal> and <literal>proc</literal>
|
||||
structure in <filename>/usr/include/sys/proc.h</filename>.
|
||||
For example, the <literal>td</literal> argument in any
|
||||
system call is actually a pointer to the calling thread's
|
||||
<literal>thread</literal> structure, as stated before. The
|
||||
<literal>td_proc</literal> member in the
|
||||
<literal>thread</literal> structure pointed by
|
||||
<literal>td</literal> is a pointer to the
|
||||
<literal>proc</literal> structure which represents the
|
||||
process that contains the thread represented by
|
||||
<literal>td</literal>. The <literal>proc</literal>
|
||||
structure contains members which can describe the owner's
|
||||
identity(<literal>p_ucred</literal>), the process resource
|
||||
limits(<literal>p_limit</literal>), and so on. In the
|
||||
<literal>ucred</literal> structure pointed by
|
||||
<literal>p_ucred</literal> member in the
|
||||
<literal>proc</literal> structure, there is a pointer to the
|
||||
<literal>prison</literal>
|
||||
structure(<literal>cr_prison</literal>).</para>
|
||||
|
||||
<programlisting><filename>/usr/include/sys/proc.h:</filename>
|
||||
struct thread {
|
||||
...
|
||||
struct proc *td_proc;
|
||||
|
@ -349,29 +372,33 @@ struct ucred {
|
|||
...
|
||||
};</programlisting>
|
||||
|
||||
<para>In <filename>kern_jail.c</filename>, the function
|
||||
<literal>jail()</literal> then calls function
|
||||
<literal>jail_attach()</literal> with a given <literal>jid</literal>.
|
||||
And <literal>jail_attach()</literal> calls function
|
||||
<literal>change_root()</literal> to change the root directory of the
|
||||
calling process. The <literal>jail_attach()</literal> then creates
|
||||
a new <literal>ucred</literal> structure, and attaches the newly
|
||||
created <literal>ucred</literal> structure to the calling process
|
||||
after it has successfully attached the <literal>prison</literal>
|
||||
structure to the <literal>ucred</literal> structure. From then on,
|
||||
the calling process is recognized as jailed. When the kernel routine
|
||||
<literal>jailed()</literal> is called in the kernel with the newly
|
||||
created <literal>ucred</literal> structure as its argument, it
|
||||
returns 1 to tell that the credential is connected
|
||||
with a <application>jail</application>. The public ancestor process
|
||||
of all the process forked within the <application>jail</application>,
|
||||
is the process which runs &man.jail.8;, as it calls the
|
||||
&man.jail.2; system call. When a program is executed through
|
||||
&man.execve.2;, it inherits the jailed property of its parent's
|
||||
<literal>ucred</literal> structure, therefore it has a jailed
|
||||
<literal>ucred</literal> structure.</para>
|
||||
<para>In <filename>kern_jail.c</filename>, the function
|
||||
<literal>jail()</literal> then calls function
|
||||
<literal>jail_attach()</literal> with a given
|
||||
<literal>jid</literal>. And
|
||||
<literal>jail_attach()</literal> calls function
|
||||
<literal>change_root()</literal> to change the root
|
||||
directory of the calling process. The
|
||||
<literal>jail_attach()</literal> then creates a new
|
||||
<literal>ucred</literal> structure, and attaches the newly
|
||||
created <literal>ucred</literal> structure to the calling
|
||||
process after it has successfully attached the
|
||||
<literal>prison</literal> structure to the
|
||||
<literal>ucred</literal> structure. From then on, the
|
||||
calling process is recognized as jailed. When the kernel
|
||||
routine <literal>jailed()</literal> is called in the kernel
|
||||
with the newly created <literal>ucred</literal> structure as
|
||||
its argument, it returns 1 to tell that the credential is
|
||||
connected with a <application>jail</application>. The
|
||||
public ancestor process of all the process forked within the
|
||||
<application>jail</application>, is the process which runs
|
||||
&man.jail.8;, as it calls the &man.jail.2; system call.
|
||||
When a program is executed through &man.execve.2;, it
|
||||
inherits the jailed property of its parent's
|
||||
<literal>ucred</literal> structure, therefore it has a
|
||||
jailed <literal>ucred</literal> structure.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>
|
||||
int
|
||||
jail(struct thread *td, struct jail_args *uap)
|
||||
{
|
||||
|
@ -401,17 +428,18 @@ jail_attach(struct thread *td, struct jail_attach_args *uap)
|
|||
p->p_ucred = newcred;
|
||||
...
|
||||
}</programlisting>
|
||||
<para>When a process is forked from its parent process, the
|
||||
&man.fork.2; system call uses <literal>crhold()</literal> to
|
||||
maintain the credential for the newly forked process. It inherently
|
||||
keep the newly forked child's credential consistent with its parent,
|
||||
so the child process is also jailed.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_fork.c</filename>:
|
||||
<para>When a process is forked from its parent process, the
|
||||
&man.fork.2; system call uses <literal>crhold()</literal> to
|
||||
maintain the credential for the newly forked process. It
|
||||
inherently keep the newly forked child's credential
|
||||
consistent with its parent, so the child process is also
|
||||
jailed.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_fork.c</filename>:
|
||||
p2->p_ucred = crhold(td->td_ucred);
|
||||
...
|
||||
td2->td_ucred = crhold(p2->p_ucred);</programlisting>
|
||||
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
@ -420,12 +448,11 @@ td2->td_ucred = crhold(p2->p_ucred);</programlisting>
|
|||
<title>Restrictions</title>
|
||||
|
||||
<para>Throughout the kernel there are access restrictions relating
|
||||
to jailed processes. Usually, these restrictions only check whether
|
||||
the process is jailed, and if so, returns an error. For
|
||||
to jailed processes. Usually, these restrictions only check
|
||||
whether the process is jailed, and if so, returns an error. For
|
||||
example:</para>
|
||||
|
||||
<programlisting>
|
||||
if (jailed(td->td_ucred))
|
||||
<programlisting>if (jailed(td->td_ucred))
|
||||
return (EPERM);</programlisting>
|
||||
|
||||
<sect2>
|
||||
|
@ -433,112 +460,128 @@ if (jailed(td->td_ucred))
|
|||
|
||||
<indexterm><primary>System V IPC</primary></indexterm>
|
||||
|
||||
<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:
|
||||
&man.msgctl.3;, &man.msgget.3;, &man.msgsnd.3; and &man.msgrcv.3;.
|
||||
Earlier, I mentioned that there were certain sysctls you could
|
||||
turn on or off in order to affect the behavior of
|
||||
<application>jail</application>. One of these sysctls was
|
||||
<literal>security.jail.sysvipc_allowed</literal>. By default,
|
||||
this sysctl is set to 0. If it were set to 1, it would defeat the
|
||||
whole purpose of having a <application>jail</application>; privileged
|
||||
users from the <application>jail</application> would be able to
|
||||
affect processes outside the jailed environment. The difference
|
||||
between a message and a signal is that the message only consists
|
||||
of the signal number.</para>
|
||||
<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: &man.msgctl.3;,
|
||||
&man.msgget.3;, &man.msgsnd.3; and &man.msgrcv.3;. Earlier, I
|
||||
mentioned that there were certain sysctls you could turn on or
|
||||
off in order to affect the behavior of
|
||||
<application>jail</application>. One of these sysctls was
|
||||
<literal>security.jail.sysvipc_allowed</literal>. By default,
|
||||
this sysctl is set to 0. If it were set to 1, it would defeat
|
||||
the whole purpose of having a <application>jail</application>;
|
||||
privileged users from the <application>jail</application>
|
||||
would be able to affect processes outside the jailed
|
||||
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><literal>msgget(key, msgflg)</literal>:
|
||||
<literal>msgget</literal> returns (and possibly creates) a message
|
||||
descriptor that designates a message queue for use in other
|
||||
functions.</para></listitem>
|
||||
<listitem>
|
||||
<para><literal>msgget(key, msgflg)</literal>:
|
||||
<literal>msgget</literal> returns (and possibly creates) a
|
||||
message descriptor that designates a message queue for use
|
||||
in other functions.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem> <para><literal>msgctl(msgid, cmd, buf)</literal>:
|
||||
Using this function, a process can query the status of a message
|
||||
descriptor.</para></listitem>
|
||||
<listitem>
|
||||
<para><literal>msgctl(msgid, cmd, buf)</literal>: Using this
|
||||
function, a process can query the status of a message
|
||||
descriptor.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem> <para><literal>msgsnd(msgid, msgp, msgsz, msgflg)</literal>:
|
||||
<literal>msgsnd</literal> sends a message to a
|
||||
process.</para></listitem>
|
||||
|
||||
<listitem> <para><literal>msgrcv(msgid, msgp, msgsz, msgtyp,
|
||||
msgflg)</literal>: a process receives messages using
|
||||
this function</para></listitem>
|
||||
<listitem>
|
||||
<para><literal>msgsnd(msgid, msgp, msgsz, msgflg)</literal>:
|
||||
<literal>msgsnd</literal> sends a message to a
|
||||
process.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>msgrcv(msgid, msgp, msgsz, msgtyp,
|
||||
msgflg)</literal>: a process receives messages using
|
||||
this function</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>In each of the system calls corresponding to these functions,
|
||||
there is this conditional:</para>
|
||||
<para>In each of the system calls corresponding to these
|
||||
functions, there is this conditional:</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/sysv_msg.c</filename>:
|
||||
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
|
||||
return (ENOSYS);</programlisting>
|
||||
|
||||
<indexterm><primary>semaphores</primary></indexterm>
|
||||
|
||||
<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 <application>jail</application>: &man.semget.2;,
|
||||
&man.semctl.2; and &man.semop.2;.</para>
|
||||
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 <application>jail</application>:
|
||||
&man.semget.2;, &man.semctl.2; and &man.semop.2;.</para>
|
||||
|
||||
<para><filename>/usr/src/sys/kern/sysv_sem.c</filename>:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>semctl(semid, semnum, cmd, ...)</literal>:
|
||||
<literal>semctl</literal> does the specified <literal>cmd</literal>
|
||||
on the semaphore queue indicated by
|
||||
<literal>semid</literal>.</para></listitem>
|
||||
<listitem>
|
||||
<para><literal>semctl(semid, semnum, cmd, ...)</literal>:
|
||||
<literal>semctl</literal> does the specified
|
||||
<literal>cmd</literal> on the semaphore queue indicated by
|
||||
<literal>semid</literal>.</para></listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>semget(key, nsems, flag)</literal>:
|
||||
<literal>semget</literal> creates an array of semaphores,
|
||||
corresponding to <literal>key</literal>.</para>
|
||||
<listitem>
|
||||
<para><literal>semget(key, nsems, flag)</literal>:
|
||||
<literal>semget</literal> creates an array of semaphores,
|
||||
corresponding to <literal>key</literal>.</para>
|
||||
|
||||
<para><literal>key and flag take on the same meaning as they
|
||||
do in msgget.</literal></para></listitem>
|
||||
<para><literal>key and flag take on the same meaning as they
|
||||
do in msgget.</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem><para><literal>semop(semid, array, nops)</literal>:
|
||||
<literal>semop</literal> performs a group of operations indicated
|
||||
by <literal>array</literal>, to the set of semaphores identified by
|
||||
<literal>semid</literal>.</para></listitem>
|
||||
<listitem><para><literal>semop(semid, array, nops)</literal>:
|
||||
<literal>semop</literal> performs a group of operations
|
||||
indicated by <literal>array</literal>, to the set of
|
||||
semaphores identified by
|
||||
<literal>semid</literal>.</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<indexterm><primary>shared memory</primary></indexterm>
|
||||
<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: &man.shmdt.2;,
|
||||
&man.shmat.2;, &man.shmctl.2; and &man.shmget.2;.</para>
|
||||
|
||||
<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: &man.shmdt.2;,
|
||||
&man.shmat.2;, &man.shmctl.2; and &man.shmget.2;.</para>
|
||||
|
||||
<para><filename>/usr/src/sys/kern/sysv_shm.c</filename>:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para><literal>shmctl(shmid, cmd, buf)</literal>:
|
||||
<literal>shmctl</literal> does various control operations on the
|
||||
shared memory region identified by
|
||||
<literal>shmid</literal>.</para></listitem>
|
||||
<listitem><para><literal>shmctl(shmid, cmd, buf)</literal>:
|
||||
<literal>shmctl</literal> does various control operations
|
||||
on the shared memory region identified by
|
||||
<literal>shmid</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem><para><literal>shmget(key, size, flag)</literal>:
|
||||
<literal>shmget</literal> accesses or creates a shared memory
|
||||
region of <literal>size</literal> bytes.</para></listitem>
|
||||
<listitem><para><literal>shmget(key, size, flag)</literal>:
|
||||
<literal>shmget</literal> accesses or creates a shared
|
||||
memory region of <literal>size</literal>
|
||||
bytes.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem><para><literal>shmat(shmid, addr, flag)</literal>:
|
||||
<literal>shmat</literal> attaches a shared memory region identified
|
||||
by <literal>shmid</literal> to the address space of a
|
||||
process.</para></listitem>
|
||||
|
||||
<listitem><para><literal>shmdt(addr)</literal>:
|
||||
<literal>shmdt</literal> detaches the shared memory region
|
||||
previously attached at <literal>addr</literal>.</para></listitem>
|
||||
<listitem><para><literal>shmat(shmid, addr, flag)</literal>:
|
||||
<literal>shmat</literal> attaches a shared memory region
|
||||
identified by <literal>shmid</literal> to the address
|
||||
space of a process.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem><para><literal>shmdt(addr)</literal>:
|
||||
<literal>shmdt</literal> detaches the shared memory region
|
||||
previously attached at
|
||||
<literal>addr</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
|
@ -546,16 +589,17 @@ if (!jail_sysvipc_allowed && jailed(td->td_ucred))
|
|||
<title>Sockets</title>
|
||||
|
||||
<indexterm><primary>sockets</primary></indexterm>
|
||||
<para><application>Jail</application> 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>security.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>
|
||||
|
||||
<para><application>Jail</application> 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>security.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
|
||||
|
@ -572,7 +616,6 @@ socreate(int dom, struct socket **aso, int type, int proto,
|
|||
}
|
||||
...
|
||||
}</programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
|
@ -581,10 +624,11 @@ socreate(int dom, struct socket **aso, int type, int proto,
|
|||
<indexterm><primary>Berkeley Packet Filter</primary></indexterm>
|
||||
<indexterm><primary>data link layer</primary></indexterm>
|
||||
|
||||
<para>The <application>Berkeley Packet Filter</application> provides
|
||||
a raw interface to data link layers in a protocol independent
|
||||
fashion. <application>BPF</application> is now controlled by the
|
||||
&man.devfs.8; whether it can be used in a jailed environment.</para>
|
||||
<para>The <application>Berkeley Packet Filter</application>
|
||||
provides a raw interface to data link layers in a protocol
|
||||
independent fashion. <application>BPF</application> is now
|
||||
controlled by the &man.devfs.8; whether it can be used in a
|
||||
jailed environment.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
@ -594,23 +638,25 @@ socreate(int dom, struct socket **aso, int type, int proto,
|
|||
<indexterm><primary>protocols</primary></indexterm>
|
||||
|
||||
<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 address only if the <literal>nam</literal>
|
||||
parameter is set. <literal>nam</literal> is a pointer to a
|
||||
<literal>sockaddr</literal> structure,
|
||||
which describes the address on which to bind the service. A
|
||||
more exact definition is that <literal>sockaddr</literal> "may be
|
||||
used as a template for referring to the identifying tag and length of
|
||||
each address". In the function
|
||||
<literal>in_pcbbind_setup()</literal>, <literal>sin</literal> is a
|
||||
pointer to a <literal>sockaddr_in</literal> structure, which
|
||||
contains the port, address, length and domain family of the socket
|
||||
which is to be bound. Basically, this disallows any processes from
|
||||
<application>jail</application> to be able to specify the address
|
||||
that does not belong to the <application>jail</application> in which
|
||||
the calling process exists.</para>
|
||||
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 address only if the
|
||||
<literal>nam</literal> parameter is set.
|
||||
<literal>nam</literal> is a pointer to a
|
||||
<literal>sockaddr</literal> structure, which describes the
|
||||
address on which to bind the service. A more exact definition
|
||||
is that <literal>sockaddr</literal> "may be used as a template
|
||||
for referring to the identifying tag and length of each
|
||||
address". In the function
|
||||
<literal>in_pcbbind_setup()</literal>, <literal>sin</literal>
|
||||
is a pointer to a <literal>sockaddr_in</literal> structure,
|
||||
which contains the port, address, length and domain family of
|
||||
the socket which is to be bound. Basically, this disallows
|
||||
any processes from <application>jail</application> to be able
|
||||
to specify the address that does not belong to the
|
||||
<application>jail</application> in which the calling process
|
||||
exists.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/netinet/in_pcb.c</filename>:
|
||||
int
|
||||
|
@ -648,14 +694,15 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
|||
}</programlisting>
|
||||
|
||||
<para>You might be wondering what function
|
||||
<literal>prison_ip()</literal> does. <literal>prison_ip()</literal>
|
||||
is given three arguments, a pointer to the credential(represented by
|
||||
<literal>cred</literal>), any flags, and an IP address. It
|
||||
returns 1 if the IP address does NOT belong to the
|
||||
<application>jail</application> or 0 otherwise. As you can see
|
||||
from the code, if it is indeed an IP address not belonging to the
|
||||
<application>jail</application>, the protocol is not allowed to bind
|
||||
to that address.</para>
|
||||
<literal>prison_ip()</literal> does.
|
||||
<literal>prison_ip()</literal> is given three arguments, a
|
||||
pointer to the credential(represented by
|
||||
<literal>cred</literal>), any flags, and an IP address. It
|
||||
returns 1 if the IP address does NOT belong to the
|
||||
<application>jail</application> or 0 otherwise. As you can
|
||||
see from the code, if it is indeed an IP address not belonging
|
||||
to the <application>jail</application>, the protocol is not
|
||||
allowed to bind to that address.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename>
|
||||
int
|
||||
|
@ -693,10 +740,12 @@ prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
|
|||
<title>Filesystem</title>
|
||||
|
||||
<indexterm><primary>filesystem</primary></indexterm>
|
||||
|
||||
<para>Even <literal>root</literal> users within the
|
||||
<application>jail</application> are not allowed to unset or modify
|
||||
any file flags, such as immutable, append-only, and undeleteable
|
||||
flags, if the securelevel is greater than 0.</para>
|
||||
<application>jail</application> are not allowed to unset or
|
||||
modify any file flags, such as immutable, append-only, and
|
||||
undeleteable flags, if the securelevel is greater than
|
||||
0.</para>
|
||||
|
||||
<programlisting><filename>/usr/src/sys/ufs/ufs/ufs_vnops.c:</filename>
|
||||
static int
|
||||
|
@ -741,7 +790,5 @@ prison_priv_check(struct ucred *cred, int priv)
|
|||
...
|
||||
}</programlisting>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
Loading…
Reference in a new issue